diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 312fc6ba4..3b80d31b1 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -1,34 +1,37 @@ -# To get started with Dependabot version updates, you'll need to specify which -# package ecosystems to update and where the package manifests are located. # Please see the documentation for all configuration options: # https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates - version: 2 updates: +# GitHub Actions +- package-ecosystem: "github-actions" + # Workflow files stored in the + # default location of `.github/workflows` + directory: "/" + schedule: + interval: "weekly" + groups: + all-github-actions: + patterns: [ "*" ] + commit-message: + prefix: ":seedling:" + labels: + - "ok-to-test" - # Maintain dependencies for GitHub Actions - - package-ecosystem: "github-actions" - # Workflow files stored in the - # default location of `.github/workflows` - directory: "/" - schedule: - interval: "weekly" - commit-message: - prefix: ":seedling:" - labels: - - "ok-to-test" - - # Maintain dependencies for go - - package-ecosystem: "gomod" - directory: "/" - schedule: - interval: "weekly" - commit-message: - prefix: ":seedling:" - labels: - - "ok-to-test" - # Ignore K8 packages as these are done manually - ignore: - - dependency-name: "k8s.io/api" - - dependency-name: "k8s.io/apiextensions-apiserver" - - dependency-name: "k8s.io/apimachinery" +# Go modules +- package-ecosystem: "gomod" + directory: "/" + schedule: + interval: "weekly" + # group all dependencies with a k8s.io prefix into a single PR. + groups: + all-go-mod-patch-and-minor: + patterns: [ "*" ] + update-types: [ "patch", "minor" ] + ignore: + # Ignore k8s and its transitives modules as they are upgraded manually. + - dependency-name: "k8s.io/*" + update-types: [ "version-update:semver-major", "version-update:semver-minor" ] + commit-message: + prefix: ":seedling:" + labels: + - "ok-to-test" diff --git a/.github/workflows/golangci-lint.yml b/.github/workflows/golangci-lint.yml new file mode 100644 index 000000000..103f7ff99 --- /dev/null +++ b/.github/workflows/golangci-lint.yml @@ -0,0 +1,37 @@ +name: golangci-lint +on: + pull_request: + types: [opened, edited, synchronize, reopened] + branches: + - main + - master + +permissions: + # Required: allow read access to the content for analysis. + contents: read + # Optional: allow read access to pull request. Use with `only-new-issues` option. + pull-requests: read + # Optional: Allow write access to checks to allow the action to annotate code in the PR. + checks: write + +jobs: + golangci: + name: lint + runs-on: ubuntu-latest + strategy: + matrix: + working-directory: + - "" + steps: + - name: Set up Go + uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # tag=v5.0.2 + with: + go-version: "1.22" + cache: false + - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # tag=v4.1.7 + - name: golangci-lint + uses: golangci/golangci-lint-action@a4f60bb28d35aeee14e6880718e0c85ff1882e64 # tag=v6.0.1 + with: + version: v1.57.2 + args: --out-format=colored-line-number + working-directory: ${{matrix.working-directory}} diff --git a/.github/workflows/pr-dependabot.yaml b/.github/workflows/pr-dependabot.yaml new file mode 100644 index 000000000..41f839568 --- /dev/null +++ b/.github/workflows/pr-dependabot.yaml @@ -0,0 +1,35 @@ +name: PR dependabot go modules fix + +# This action runs on PRs opened by dependabot and updates modules. +on: + pull_request: + branches: + - dependabot/** + push: + branches: + - dependabot/** + workflow_dispatch: + +permissions: + contents: write # Allow to update the PR. + +jobs: + build: + name: Build + runs-on: ubuntu-latest + steps: + - name: Check out code + uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # tag=v4.1.7 + - name: Set up Go + uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # tag=v5.0.2 + with: + go-version: '1.22' + - name: Update all modules + run: make modules + - uses: EndBug/add-and-commit@a94899bca583c204427a224a7af87c02f9b325d5 # tag=v9.1.4 + name: Commit changes + with: + author_name: dependabot[bot] + author_email: 49699333+dependabot[bot]@users.noreply.github.com + default_author: github_actor + message: 'Update generated code' diff --git a/.github/workflows/tools-releases.yml b/.github/workflows/tools-releases.yml new file mode 100644 index 000000000..6d3f0e372 --- /dev/null +++ b/.github/workflows/tools-releases.yml @@ -0,0 +1,61 @@ +name: Package controller-runtime envtest + +on: + push: + branches: + - main + - master + paths: + - 'hack/envtest/_matrix/*.yaml' + +permissions: + contents: write + pull-requests: write + +jobs: + build-and-push: + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # tag=v4.1.7 + - name: Get changed files + id: changed-files + uses: tj-actions/changed-files@6b2903bdce6310cfbddd87c418f253cf29b2dec9 # tag=v44.5.6 + with: + files: | + hack/envtest/_matrix/*.yaml + - name: Setup package release version + id: release-version + run: | + if [[ ${{ steps.changed-files.outputs.all_changed_files_count }} != 1 ]]; then + echo "One Kubernetes patch version files should be changed for a release, found ${{ steps.changed-files.outputs.all_changed_files_count }}" + exit 1 + fi + + for changed_file in ${{ steps.changed-files.outputs.all_changed_files }}; do + export KUBERNETES_VERSION=$(echo "${changed_file}" | grep -oP '(?<=/)[^/]+(?=\.yaml)') + echo "KUBERNETES_VERSION=$KUBERNETES_VERSION" >> $GITHUB_ENV + done + - name: Build packages + run: | + make release-envtest KUBERNETES_VERSION=${{ env.KUBERNETES_VERSION }} + - name: Release + uses: softprops/action-gh-release@c062e08bd532815e2082a85e87e3ef29c3e6d191 # tag=v2.0.8 + with: + tag_name: envtest-${{ env.KUBERNETES_VERSION }} + draft: false + make_latest: false + files: | + out/envtest-*.tar.gz + out/envtest-*.tar.gz.sha512 + fail_on_unmatched_files: true + - name: Create Pull Request + uses: peter-evans/create-pull-request@c5a7806660adbe173f04e3e038b0ccdcd758773c # tag=v6.1.0 + with: + commit-message: Promote envtest release for Kubernetes ${{ env.KUBERNETES_VERSION }} + title: ":seedling: Promotion of envtest release for Kubernetes ${{ env.KUBERNETES_VERSION }}" + body: | + This PR promotes the envtest release for Kubernetes ${{ env.KUBERNETES_VERSION }}. + branch: promote-envtest-${{ env.KUBERNETES_VERSION }} + add-paths: | + envtest-releases.yaml diff --git a/.github/workflows/verify.yml b/.github/workflows/verify.yml index b36de6677..e24f96210 100644 --- a/.github/workflows/verify.yml +++ b/.github/workflows/verify.yml @@ -1,8 +1,9 @@ -name: PR Verifier - on: pull_request_target: - types: [opened, edited, reopened] + types: [opened, edited, reopened, synchronize] + +permissions: + checks: write # Allow access to checks to write check runs. jobs: verify: @@ -11,6 +12,6 @@ jobs: steps: - name: Verifier action id: verifier - uses: kubernetes-sigs/kubebuilder-release-tools@v0.2.0 + uses: kubernetes-sigs/kubebuilder-release-tools@012269a88fa4c034a0acf1ba84c26b195c0dbab4 # tag=v0.4.3 with: github_token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.gitignore b/.gitignore index 9e0c605fc..01a75264a 100644 --- a/.gitignore +++ b/.gitignore @@ -16,3 +16,10 @@ *.swp *.swo *~ + +# Tools binaries. +out +hack/tools/bin + +junit-report.xml +/artifacts diff --git a/.golangci.yml b/.golangci.yml index 3a3f0f04c..d3f395402 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -2,4 +2,11 @@ run: modules-download-mode: readonly # Increase the default deadline from 1m as some module operations can take a # while if uncached! - deadline: 5m + timeout: 10m + +issues: + exclude-rules: + # Dot imports for gomega and ginkgo are allowed + # within test files. + - path: _test\.go + text: should not use dot imports diff --git a/Makefile b/Makefile index b20be62d9..3f07ea451 100644 --- a/Makefile +++ b/Makefile @@ -1,2 +1,137 @@ -test-all: +#!/usr/bin/env bash + +# Copyright 2024 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. + +# If you update this file, please follow +# https://suva.sh/posts/well-documented-makefiles + +## -------------------------------------- +## General +## -------------------------------------- + +SHELL:=/usr/bin/env bash +.DEFAULT_GOAL:=help + +# Use GOPROXY environment variable if set +GOPROXY := $(shell go env GOPROXY) +ifeq ($(GOPROXY),) +GOPROXY := https://proxy.golang.org +endif +export GOPROXY + +# Active module mode, as we use go modules to manage dependencies +export GO111MODULE=on + +# Tools. +ENVTEST_DIR := hack/envtest +ENVTEST_MATRIX_DIR := $(ENVTEST_DIR)/_matrix +TOOLS_DIR := hack/tools +TOOLS_BIN_DIR := $(abspath $(TOOLS_DIR)/bin) +GOLANGCI_LINT := $(abspath $(TOOLS_BIN_DIR)/golangci-lint) +GO_INSTALL := ./hack/go-install.sh + +## -------------------------------------- +## Binaries +## -------------------------------------- + +GOLANGCI_LINT_BIN := golangci-lint +GOLANGCI_LINT_VER := $(shell cat .github/workflows/golangci-lint.yml | grep [[:space:]]version: | sed 's/.*version: //') +GOLANGCI_LINT := $(abspath $(TOOLS_BIN_DIR)/$(GOLANGCI_LINT_BIN)-$(GOLANGCI_LINT_VER)) +GOLANGCI_LINT_PKG := github.com/golangci/golangci-lint/cmd/golangci-lint + +$(GOLANGCI_LINT): # Build golangci-lint from tools folder. + GOBIN=$(TOOLS_BIN_DIR) $(GO_INSTALL) $(GOLANGCI_LINT_PKG) $(GOLANGCI_LINT_BIN) $(GOLANGCI_LINT_VER) + +## -------------------------------------- +## Linting +## -------------------------------------- + +.PHONY: lint +lint: $(GOLANGCI_LINT) ## Lint codebase + $(GOLANGCI_LINT) run -v $(GOLANGCI_LINT_EXTRA_ARGS) + cd tools/setup-envtest; $(GOLANGCI_LINT) run -v $(GOLANGCI_LINT_EXTRA_ARGS) + +.PHONY: lint-fix +lint-fix: $(GOLANGCI_LINT) ## Lint the codebase and run auto-fixers if supported by the linter. + GOLANGCI_LINT_EXTRA_ARGS=--fix $(MAKE) lint + +## -------------------------------------- +## Testing +## -------------------------------------- + +.PHONY: test +test: ## Run the test.sh script which will check all. TRACE=1 ./test.sh + +test-all: + $(MAKE) test + +.PHONY: modules +modules: ## Runs go mod to ensure modules are up to date. + go mod tidy + +## -------------------------------------- +## Cleanup / Verification +## -------------------------------------- + +.PHONY: clean +clean: ## Cleanup. + $(GOLANGCI_LINT) cache clean + $(MAKE) clean-bin + +.PHONY: clean-bin +clean-bin: ## Remove all generated binaries. + rm -rf hack/tools/bin + +.PHONE: clean-release +clean-release: ## Remove all generated release binaries. + rm -rf $(RELEASE_DIR) + +## -------------------------------------- +## Envtest Build +## -------------------------------------- + +RELEASE_DIR := out + +.PHONY: $(RELEASE_DIR) +$(RELEASE_DIR): + mkdir -p $(RELEASE_DIR)/ + +.PHONY: release-envtest +release-envtest: clean-release ## Build the envtest binaries by operating system. + OS=linux ARCH=amd64 $(MAKE) release-envtest-docker-build + OS=linux ARCH=arm64 $(MAKE) release-envtest-docker-build + OS=linux ARCH=ppc64le $(MAKE) release-envtest-docker-build + OS=linux ARCH=s390x $(MAKE) release-envtest-docker-build + OS=darwin ARCH=amd64 $(MAKE) release-envtest-docker-build + OS=darwin ARCH=arm64 $(MAKE) release-envtest-docker-build + OS=windows ARCH=amd64 $(MAKE) release-envtest-docker-build + ./hack/envtest/update-releases.sh + +.PHONY: release-envtest-docker-build +release-envtest-docker-build: $(RELEASE_DIR) ## Build the envtest binaries. + @: $(if $(KUBERNETES_VERSION),,$(error KUBERNETES_VERSION is not set)) + @: $(if $(OS),,$(error OS is not set)) + @: $(if $(ARCH),,$(error ARCH is not set)) + docker buildx build \ + --file ./hack/envtest/$(OS)/Dockerfile \ + --build-arg KUBERNETES_VERSION=$(KUBERNETES_VERSION) \ + --build-arg GO_VERSION=$(shell yq eval '.go' $(ENVTEST_MATRIX_DIR)/$(KUBERNETES_VERSION).yaml) \ + --build-arg ETCD_VERSION=$(shell yq eval '.etcd' $(ENVTEST_MATRIX_DIR)/$(KUBERNETES_VERSION).yaml) \ + --build-arg OS=$(OS) \ + --build-arg ARCH=$(ARCH) \ + --tag sigs.k8s.io/controller-tools/envtest:$(KUBERNETES_VERSION)-$(OS)-$(ARCH) \ + --output type=local,dest=$(RELEASE_DIR) \ + . diff --git a/OWNERS_ALIASES b/OWNERS_ALIASES index c1373872a..132ed8b51 100644 --- a/OWNERS_ALIASES +++ b/OWNERS_ALIASES @@ -4,15 +4,13 @@ aliases: # active folks who can be contacted to perform admin-related # tasks on the repo, or otherwise approve any PRS. controller-tools-admins: - - droot - - mengqiy - - pwittrock + - vincepri + - joelanford # non-admin folks who can approve any PRs in the repo controller-tools-maintainers: - alvaroaleman - - joelanford - - vincepri + - sbueringer # non-admin folks who can approve any PRs in the repo controller-tools-approvers: [] @@ -26,3 +24,6 @@ aliases: # but are no longer directly involved controller-tools-emeritus-maintainers: - directxman12 + - droot + - mengqiy + - pwittrock diff --git a/VERSIONING.md b/VERSIONING.md index 7d5e0d6c6..faa6c396d 100644 --- a/VERSIONING.md +++ b/VERSIONING.md @@ -13,7 +13,7 @@ as a "library project", but otherwise follows the guidelines closely. For release branches, we generally do not support older branches. This may change in the future. -Compability-wise, remember that changes to generation defaults are +Compatibility-wise, remember that changes to generation defaults are breaking changes. ## Updates to Other Projects on Release diff --git a/cmd/helpgen/main.go b/cmd/helpgen/main.go index c5c769356..b7b81a892 100644 --- a/cmd/helpgen/main.go +++ b/cmd/helpgen/main.go @@ -37,7 +37,7 @@ func init() { const ( markerName = "controllertools:marker:generateHelp" header = ` -// +build !ignore_autogenerated +//go:build !ignore_autogenerated %[2]s diff --git a/envtest-releases.yaml b/envtest-releases.yaml new file mode 100644 index 000000000..0d037d63a --- /dev/null +++ b/envtest-releases.yaml @@ -0,0 +1,375 @@ +releases: + v1.28.0: + envtest-v1.28.0-darwin-amd64.tar.gz: + hash: f4c5ae38e1331c32b416c47536aa3d35e58b9b9b3800b5e0f46ec8495b4ec891dcc99366dd9aa44f8b7aeb24269f117fd8672027902706d885b1beb1abdc771c + selfLink: https://github.com/kubernetes-sigs/controller-tools/releases/download/envtest-v1.28.0/envtest-v1.28.0-darwin-amd64.tar.gz + envtest-v1.28.0-darwin-arm64.tar.gz: + hash: 0df39d01e57f8175e86e843fc1d75df4028a2889feb7477d65220c120c04a2db511b1c4a4303d5b1ef34ad0c1733c1de17a64502898c9625b2a35bcca13d7979 + selfLink: https://github.com/kubernetes-sigs/controller-tools/releases/download/envtest-v1.28.0/envtest-v1.28.0-darwin-arm64.tar.gz + envtest-v1.28.0-linux-amd64.tar.gz: + hash: 000c9adc2c140bed3f73e28caabdfa82d76d7c35c4b0cf93322d0fcbc1f28a070962e928c9132ea6b60c02ed677a7449cfab0b91134971419a21dab65ce5781e + selfLink: https://github.com/kubernetes-sigs/controller-tools/releases/download/envtest-v1.28.0/envtest-v1.28.0-linux-amd64.tar.gz + envtest-v1.28.0-linux-arm64.tar.gz: + hash: 4a68bc6ec20c63db330f763bf347bbf791d335fa2861de6b9a89cf8132bbd538049495055e0c47779d8aa6877e2cdb7cda01064609f55be3a5dff144f48cf084 + selfLink: https://github.com/kubernetes-sigs/controller-tools/releases/download/envtest-v1.28.0/envtest-v1.28.0-linux-arm64.tar.gz + envtest-v1.28.0-linux-ppc64le.tar.gz: + hash: 5fd02dfca7e74cf5c752c4d4f31005a8316c4690485804e38e10ed8a7bc1a2c638d9f4bcf1568cfe7e19ae14ccd2aa62684e6c564acc9024dc74df28070b19ae + selfLink: https://github.com/kubernetes-sigs/controller-tools/releases/download/envtest-v1.28.0/envtest-v1.28.0-linux-ppc64le.tar.gz + envtest-v1.28.0-linux-s390x.tar.gz: + hash: 4fddb7f62b6b07bd4d395f3995e0d3a30788fa409064ad23d8371332b647a681e8c10042f98f02e95b344e5bf8c6e01106feebf968c20de42eddb30832a8c78d + selfLink: https://github.com/kubernetes-sigs/controller-tools/releases/download/envtest-v1.28.0/envtest-v1.28.0-linux-s390x.tar.gz + envtest-v1.28.0-windows-amd64.tar.gz: + hash: cf80fda14a3d7c8ab4e1565a6243e53546c0e52b7344c342296495fc537b5094f4d15e927198a439127f8352bf6b43f6a8a00b217c5756bc405705ecc154f581 + selfLink: https://github.com/kubernetes-sigs/controller-tools/releases/download/envtest-v1.28.0/envtest-v1.28.0-windows-amd64.tar.gz + v1.29.4: + envtest-v1.29.4-darwin-amd64.tar.gz: + hash: 9631990f3cd5d5020f807e13639baabccd82051604473b7a5bfc143dc9207e4c32f6f64be46893f07d0723cd519c38499563dc0ef442c7897533470f559d8036 + selfLink: https://github.com/kubernetes-sigs/controller-tools/releases/download/envtest-v1.29.4/envtest-v1.29.4-darwin-amd64.tar.gz + envtest-v1.29.4-darwin-arm64.tar.gz: + hash: d46c24070f983089a02cb1c5f1bfa42c4ccc5b8509e72f7bac50d7a4b45fea2f7111db569d658137362667ff26a88b49bc6fad1dbc1083342e6d642876ca6abb + selfLink: https://github.com/kubernetes-sigs/controller-tools/releases/download/envtest-v1.29.4/envtest-v1.29.4-darwin-arm64.tar.gz + envtest-v1.29.4-linux-amd64.tar.gz: + hash: ac6f0fd04d09e06a31786dbf82891f6db459e787f12cccb668704aad18329af7c1a7bc3bc5c4b07c4fa59fb8310fac1e1db117e7c073de59d8f44f97e2fbcbfa + selfLink: https://github.com/kubernetes-sigs/controller-tools/releases/download/envtest-v1.29.4/envtest-v1.29.4-linux-amd64.tar.gz + envtest-v1.29.4-linux-arm64.tar.gz: + hash: c1152157187241a207dafc5e8a5dbad92316b0533319a2425c1db5ff2a8a2988301440d955265d621ade249c4cba0349a8944c8ec3e89a4f12813575ebc249f4 + selfLink: https://github.com/kubernetes-sigs/controller-tools/releases/download/envtest-v1.29.4/envtest-v1.29.4-linux-arm64.tar.gz + envtest-v1.29.4-linux-ppc64le.tar.gz: + hash: 6cf2f80abc27a8e6536a05cb1e051d18ee1a4662d8e02dcad73b8798162aab3cda04fe08aaa84fe312004e03de389a79148b20ba080d2083cafb4b708b92339b + selfLink: https://github.com/kubernetes-sigs/controller-tools/releases/download/envtest-v1.29.4/envtest-v1.29.4-linux-ppc64le.tar.gz + envtest-v1.29.4-linux-s390x.tar.gz: + hash: 6666f9f906460b0b386b3227f80a59cf92f6377c12e702304817faefb21d04eaef6204738bea13de2ac6b4462c1717b7de927755de270fc2297304cfef7fa8e6 + selfLink: https://github.com/kubernetes-sigs/controller-tools/releases/download/envtest-v1.29.4/envtest-v1.29.4-linux-s390x.tar.gz + envtest-v1.29.4-windows-amd64.tar.gz: + hash: a56729c968fe462a002b4afe041f8700900853c114d4a643e9ddb2e2cedf786ebd5a02203418728a1304145b5a089f6693120456af4e78b7d0a5d70a9b4c58a3 + selfLink: https://github.com/kubernetes-sigs/controller-tools/releases/download/envtest-v1.29.4/envtest-v1.29.4-windows-amd64.tar.gz + v1.30.0: + envtest-v1.30.0-darwin-amd64.tar.gz: + hash: e705b35189052880afefeac72797834d2750bfcfc8971dd913cc2b5575ea7222e9cfa3ebb38a5e5deec8f06089ecc654beaf9c4fe990acf41e57758c26b3d62a + selfLink: https://github.com/kubernetes-sigs/controller-tools/releases/download/envtest-v1.30.0/envtest-v1.30.0-darwin-amd64.tar.gz + envtest-v1.30.0-darwin-arm64.tar.gz: + hash: 48c1fa5555f021f8aa365faaa96b106804ce5e3022142a2a166bc91ecd5b22da79f012d20c1a4963e0236df00a214f3311cdd842de4ab19442ca1c83b3bcb859 + selfLink: https://github.com/kubernetes-sigs/controller-tools/releases/download/envtest-v1.30.0/envtest-v1.30.0-darwin-arm64.tar.gz + envtest-v1.30.0-linux-amd64.tar.gz: + hash: d53870e1a6c9b3b50366489a9387f4e254c664955e932e3e25e2088bb437b270bfab75d241b50849233f9a34bb1f08b41567ebb81ea29352104ae0f5b1cb9e88 + selfLink: https://github.com/kubernetes-sigs/controller-tools/releases/download/envtest-v1.30.0/envtest-v1.30.0-linux-amd64.tar.gz + envtest-v1.30.0-linux-arm64.tar.gz: + hash: 140748efaa394598f50175e809cd53896881ed046d93ebdfbd5442100f68b3d8d51fd22f8cf1ae06a6e43473897b789df0db6e0ae6c45c8320b000d5ee900005 + selfLink: https://github.com/kubernetes-sigs/controller-tools/releases/download/envtest-v1.30.0/envtest-v1.30.0-linux-arm64.tar.gz + envtest-v1.30.0-linux-ppc64le.tar.gz: + hash: 04e3570354001547d04eff1764d0dada9f5451fead5544e7f30457874b4d157fc62b769026f4c4fe3b8defa52892b722532229e2c6c27ad98c358c76ad018426 + selfLink: https://github.com/kubernetes-sigs/controller-tools/releases/download/envtest-v1.30.0/envtest-v1.30.0-linux-ppc64le.tar.gz + envtest-v1.30.0-linux-s390x.tar.gz: + hash: 19f2d516b5b7753afdab991901e690cdb728367b783b32339cbe2d138619b35c1e59d13368b783a6b455b30d190abdfeb7997c48ae1710f66c69b2dc37c84375 + selfLink: https://github.com/kubernetes-sigs/controller-tools/releases/download/envtest-v1.30.0/envtest-v1.30.0-linux-s390x.tar.gz + envtest-v1.30.0-windows-amd64.tar.gz: + hash: bf0846337d2fb85b9676ae5eb47c676e9315612dccba2e4fc748d6c76bc1228321cfa182274e9773d649c2298f624f62278032c547736159a8695b1712de64d0 + selfLink: https://github.com/kubernetes-sigs/controller-tools/releases/download/envtest-v1.30.0/envtest-v1.30.0-windows-amd64.tar.gz + v1.29.3: + envtest-v1.29.3-darwin-amd64.tar.gz: + hash: 56614d52e534520b03257c4c54977e6ece5f12dec135c3e469837dc06f0ff026208fe172d05e9b8d865daa4cdc033c2c85f3d7f547e0b2c385c7409896ed9b14 + selfLink: https://github.com/kubernetes-sigs/controller-tools/releases/download/envtest-v1.29.3/envtest-v1.29.3-darwin-amd64.tar.gz + envtest-v1.29.3-darwin-arm64.tar.gz: + hash: e5c720980500915e720ff73b28d8b5a969f268030d0b7f9f3024337d8529160ac1ce3f740e62f37ed778420701c55f1006a87053be639fd5f307a29b0e9ff465 + selfLink: https://github.com/kubernetes-sigs/controller-tools/releases/download/envtest-v1.29.3/envtest-v1.29.3-darwin-arm64.tar.gz + envtest-v1.29.3-linux-amd64.tar.gz: + hash: 69267f765305436306221abbf63597c3383ae22fb8b893ec5db28b12e00cf0a690236e9038cc33b475d46ce2c9ac12cae871442dac3ec92b0c58c21fc0d8c1bb + selfLink: https://github.com/kubernetes-sigs/controller-tools/releases/download/envtest-v1.29.3/envtest-v1.29.3-linux-amd64.tar.gz + envtest-v1.29.3-linux-arm64.tar.gz: + hash: a1a46ecbf3104957a74f2ed57df5a033530cc0123b1b893350d0fcabc2539ee884729ad2f3bbc216cfb1fcbdec11a2fcb239a0a04abbd3d712b98c46287f37a3 + selfLink: https://github.com/kubernetes-sigs/controller-tools/releases/download/envtest-v1.29.3/envtest-v1.29.3-linux-arm64.tar.gz + envtest-v1.29.3-linux-ppc64le.tar.gz: + hash: 87fd6573f4a22e5764025c4c399cab1b5c6f338e4ebce17199095cd464140c1ddb659fc15251bef612f338a0ea2befc28e816a891501fd262de40ea165d4a9a5 + selfLink: https://github.com/kubernetes-sigs/controller-tools/releases/download/envtest-v1.29.3/envtest-v1.29.3-linux-ppc64le.tar.gz + envtest-v1.29.3-linux-s390x.tar.gz: + hash: 72fbe733a2758de7ad46994d60008c49e9f84796eed230179262ca1d91b6e2932069a7cc8b2fa9dda684fbdf73e6825bf5e5960f4706c009aa503480649487e7 + selfLink: https://github.com/kubernetes-sigs/controller-tools/releases/download/envtest-v1.29.3/envtest-v1.29.3-linux-s390x.tar.gz + envtest-v1.29.3-windows-amd64.tar.gz: + hash: 4367ebbf1811e037f5e856743523559717880981bfc2e2a23afa54665474bc7c4a5a36f6f8c76fb8ce695e54886055a57b0d3e8f9073893b2f246a56232b44e4 + selfLink: https://github.com/kubernetes-sigs/controller-tools/releases/download/envtest-v1.29.3/envtest-v1.29.3-windows-amd64.tar.gz + v1.25.0: + envtest-v1.25.0-darwin-amd64.tar.gz: + hash: 8213ef1b160ccecb80cf67334b682d84886365c2a0f9864a17956d7c56a8244497364254cee57a81e3ce697a3feeeb0d27c55191dcbac54efa6f9a8b48769cce + selfLink: https://github.com/kubernetes-sigs/controller-tools/releases/download/envtest-v1.25.0/envtest-v1.25.0-darwin-amd64.tar.gz + envtest-v1.25.0-darwin-arm64.tar.gz: + hash: 0ee5aba210bb060745f82c48ad9bca6e166a9eeb684501a979fa3af6a75435ee1c4c78f851964724eb2b11da7967d4ea7d29be2a7c4bdf850237d6d881cfa2d3 + selfLink: https://github.com/kubernetes-sigs/controller-tools/releases/download/envtest-v1.25.0/envtest-v1.25.0-darwin-arm64.tar.gz + envtest-v1.25.0-linux-amd64.tar.gz: + hash: 5ca5617298a78b958078ef108efc38bb73297b53c013537cc718ea5fc0f40e34cccf74fb0d281ab1069c8cfd271b7cec1dcd77ff7e371a2b98be4efb6a4985f1 + selfLink: https://github.com/kubernetes-sigs/controller-tools/releases/download/envtest-v1.25.0/envtest-v1.25.0-linux-amd64.tar.gz + envtest-v1.25.0-linux-arm64.tar.gz: + hash: 2c743ce14b3cff2db651dbf009103d5a53da9890e6a6fec3bcbaf01c415017d29ad3e2c676797aad2991522a9a1b2ef72656f9a9b392f28f4892ce0ff3f99a08 + selfLink: https://github.com/kubernetes-sigs/controller-tools/releases/download/envtest-v1.25.0/envtest-v1.25.0-linux-arm64.tar.gz + envtest-v1.25.0-linux-ppc64le.tar.gz: + hash: de4adf0fd2d806667c13f329e8775187bbb69b2717c462fb8b860301612587d833029a007e6df250620630f39f7fadcb5a7fdbca6d9dc4fcc68057e9654b5d7a + selfLink: https://github.com/kubernetes-sigs/controller-tools/releases/download/envtest-v1.25.0/envtest-v1.25.0-linux-ppc64le.tar.gz + envtest-v1.25.0-linux-s390x.tar.gz: + hash: aa34358ff97e62250b20fbc0dfc4657bc7b8a868d922ffd49244184370ccb21ff1449c92451c2981fa3883f9d641e61cea3c66ac2e00b3cbe8e2e1ca8d1a622e + selfLink: https://github.com/kubernetes-sigs/controller-tools/releases/download/envtest-v1.25.0/envtest-v1.25.0-linux-s390x.tar.gz + envtest-v1.25.0-windows-amd64.tar.gz: + hash: d2f4c4aafefef69f964605dbb951f0a1dd5740a20770e2ace3111cb8c98daf3d72f05ea2d53c1549f752e54c0d7d02f555d67016d6bc666271a7db22f2120c08 + selfLink: https://github.com/kubernetes-sigs/controller-tools/releases/download/envtest-v1.25.0/envtest-v1.25.0-windows-amd64.tar.gz + v1.26.0: + envtest-v1.26.0-darwin-amd64.tar.gz: + hash: 293615d95d12c0da47123caf8389bcc1b1d7ae3221c23b98bd26b9aa10d5608cc9c7f8d5c23a376cbe13683ab11e30142baefcbc8fbd8167f3fa615dacbf4350 + selfLink: https://github.com/kubernetes-sigs/controller-tools/releases/download/envtest-v1.26.0/envtest-v1.26.0-darwin-amd64.tar.gz + envtest-v1.26.0-darwin-arm64.tar.gz: + hash: 9b975180dfa50f562e3e63125d077528358670af3a1e09eda12edd6cf29d8c6a6b1efdccbb07222d18e32014f7a50a9c9d66c050350a338115aa65bd37d84f41 + selfLink: https://github.com/kubernetes-sigs/controller-tools/releases/download/envtest-v1.26.0/envtest-v1.26.0-darwin-arm64.tar.gz + envtest-v1.26.0-linux-amd64.tar.gz: + hash: 115275a461e5fb09515f4d87a12b07ccdf1662ed79a89af085ec965af1a2e9dd5ddcfa9399da0c409de29b7f2aede29d9af6cb91eeb80bebbeb09dc56a9ab36f + selfLink: https://github.com/kubernetes-sigs/controller-tools/releases/download/envtest-v1.26.0/envtest-v1.26.0-linux-amd64.tar.gz + envtest-v1.26.0-linux-arm64.tar.gz: + hash: 7703a8a5072bf8744436036e744cb93f79d91d49d3de5b407cdd59ee49894a3461a1eeb1bf4fe7afc4b2a2d505c62c058d5410fda95cf93a1a6fab8fd33a8687 + selfLink: https://github.com/kubernetes-sigs/controller-tools/releases/download/envtest-v1.26.0/envtest-v1.26.0-linux-arm64.tar.gz + envtest-v1.26.0-linux-ppc64le.tar.gz: + hash: 8219631136509c862f25a5e12d768315d8f0d7b8ec3b35960c47c0a520ce2461932701156e1c1daa014a6f26161e2566937c53efb4a42a9a3240ee3ed3e35c98 + selfLink: https://github.com/kubernetes-sigs/controller-tools/releases/download/envtest-v1.26.0/envtest-v1.26.0-linux-ppc64le.tar.gz + envtest-v1.26.0-linux-s390x.tar.gz: + hash: 5ebc3d1afa7361a38d3350506f23ae9aca25a6befa88f57eccc1e485785b86435287cda6fb5160d26f3ea812c018a859438d2bc5cd650d4a9af46f97a126b66d + selfLink: https://github.com/kubernetes-sigs/controller-tools/releases/download/envtest-v1.26.0/envtest-v1.26.0-linux-s390x.tar.gz + envtest-v1.26.0-windows-amd64.tar.gz: + hash: b80f33b5c50a80578907164e4825afeebef83744470e39e6005b35d56431de803a784d908f79f22bed80de0922932ac5121c3bdc6d67f283c03cb741b72d6776 + selfLink: https://github.com/kubernetes-sigs/controller-tools/releases/download/envtest-v1.26.0/envtest-v1.26.0-windows-amd64.tar.gz + v1.27.1: + envtest-v1.27.1-darwin-amd64.tar.gz: + hash: 663996ba95594c2ee97b63e43568567d48bad8bb04598bc27e23f0a64a6525d673bc403817a7bd4dfb043f7feb7f9f31e787e71123187e35344ccb17179b9215 + selfLink: https://github.com/kubernetes-sigs/controller-tools/releases/download/envtest-v1.27.1/envtest-v1.27.1-darwin-amd64.tar.gz + envtest-v1.27.1-darwin-arm64.tar.gz: + hash: adea3db3aa2174743251a6184cfad0b74224073e618f19dfd80c4d031c1352a18810d652a5c42b10e13d8db85e40679dae83448238c22eeff04b5aacd6530011 + selfLink: https://github.com/kubernetes-sigs/controller-tools/releases/download/envtest-v1.27.1/envtest-v1.27.1-darwin-arm64.tar.gz + envtest-v1.27.1-linux-amd64.tar.gz: + hash: 607ffc315583a654a7ce6d9ee1bc0ce18ba85750a13f7d972effe253a53e3bb9910f5fb083ebafd7802d39192226493013b9c88108ceeaaa8192323099cf7a9e + selfLink: https://github.com/kubernetes-sigs/controller-tools/releases/download/envtest-v1.27.1/envtest-v1.27.1-linux-amd64.tar.gz + envtest-v1.27.1-linux-arm64.tar.gz: + hash: 4505684de16e556fea03ea2a9c60bd543dd263b3d07e56bfa2391f09a05edb7c65da3c4544e1d6b6b14b05b9ed991df88385e59911399620ae9b660d56f4a848 + selfLink: https://github.com/kubernetes-sigs/controller-tools/releases/download/envtest-v1.27.1/envtest-v1.27.1-linux-arm64.tar.gz + envtest-v1.27.1-linux-ppc64le.tar.gz: + hash: bf0f8258979400304bc7bd20f755bbe860240edd0f059b5aca8400d26a45b7d3aa0b2f3716bcfe07fedd33d96372d81e6e4563a4f960c7c1d090dd4b39730dbb + selfLink: https://github.com/kubernetes-sigs/controller-tools/releases/download/envtest-v1.27.1/envtest-v1.27.1-linux-ppc64le.tar.gz + envtest-v1.27.1-linux-s390x.tar.gz: + hash: fce63eb0ff3f440093f572eae10d3a97213ce713b81ab8dcc1dc59b6b62d72c496fbf51c8d2621a5238f1afea7f33f1e419ea30ec9681d15cfcdbd24c2d3674d + selfLink: https://github.com/kubernetes-sigs/controller-tools/releases/download/envtest-v1.27.1/envtest-v1.27.1-linux-s390x.tar.gz + envtest-v1.27.1-windows-amd64.tar.gz: + hash: a8bcd4586ed1d94da74588f909d79dab817cc729ee01ff499362d11a2c0355e065bf3ae1d1c801035a2b47920b0dab24c795991b7e4017512cf58a236ef496fe + selfLink: https://github.com/kubernetes-sigs/controller-tools/releases/download/envtest-v1.27.1/envtest-v1.27.1-windows-amd64.tar.gz + v1.29.0: + envtest-v1.29.0-darwin-amd64.tar.gz: + hash: e18607924960a21ad72cc76a0af1dd07f027b5644e272956489a6e12c7e3bcb789a791127915733ccfa17cd1a4f1b7cb8192d57244b42a40ca9f8a5dce98bc31 + selfLink: https://github.com/kubernetes-sigs/controller-tools/releases/download/envtest-v1.29.0/envtest-v1.29.0-darwin-amd64.tar.gz + envtest-v1.29.0-darwin-arm64.tar.gz: + hash: 27cac8ea6ffbd4ff625195697a83acf773a6b6f0ba76ef5d4af452f3ae1ce946f1d35944780c1e1340be19e1cfee9a948c8c900278ac1712db42aa3d7063bb4a + selfLink: https://github.com/kubernetes-sigs/controller-tools/releases/download/envtest-v1.29.0/envtest-v1.29.0-darwin-arm64.tar.gz + envtest-v1.29.0-linux-amd64.tar.gz: + hash: 256020ab84ee6d8d55bd7a25f6abbfeefebade0d8d17cd7c3d1c3b08a9b4859454e97f4972dae8ba31388a4c70c5cc0828c4ff91308d76d65286a592586fbf96 + selfLink: https://github.com/kubernetes-sigs/controller-tools/releases/download/envtest-v1.29.0/envtest-v1.29.0-linux-amd64.tar.gz + envtest-v1.29.0-linux-arm64.tar.gz: + hash: f1041551205a5d2b55cea4a9b3c6ae00de554389bafd87351ac891cf2f01a48cc1f18033bdb83e6b4f73bc249a2081868cc9f8c1f26240587cd3885f1f3eccc2 + selfLink: https://github.com/kubernetes-sigs/controller-tools/releases/download/envtest-v1.29.0/envtest-v1.29.0-linux-arm64.tar.gz + envtest-v1.29.0-linux-ppc64le.tar.gz: + hash: 641a1887c45adde184fca9cda44e63ea5928152a0aa1010713de8edd8034e2f092300d457db0d0456fce36f27b2904408018254689998e4c0b7df63752a3ed52 + selfLink: https://github.com/kubernetes-sigs/controller-tools/releases/download/envtest-v1.29.0/envtest-v1.29.0-linux-ppc64le.tar.gz + envtest-v1.29.0-linux-s390x.tar.gz: + hash: 85770f39d0e2af74fe95f1e4521769eebe8060fbe605cd4e4df689b83b6d3d5cc9903f025c643e4ac3fac37528e90f0e4da91f3fa879c20e811f35f16ce8e259 + selfLink: https://github.com/kubernetes-sigs/controller-tools/releases/download/envtest-v1.29.0/envtest-v1.29.0-linux-s390x.tar.gz + envtest-v1.29.0-windows-amd64.tar.gz: + hash: fd82a876f27a9b2888315e94c46da1704a3d9f1ebca14df3deab09eede7214c17a735d795fd2e2eaf62a6d6ec6c44a2ffc2d3bd5aa5b18889c61fbc64df9d1f9 + selfLink: https://github.com/kubernetes-sigs/controller-tools/releases/download/envtest-v1.29.0/envtest-v1.29.0-windows-amd64.tar.gz + v1.26.1: + envtest-v1.26.1-darwin-amd64.tar.gz: + hash: c41ff9d03763c5c08ce879a20480d9a9254a9e7f581056cf5cecf6521845f171e0ce17ec3ce236969e9e0c4cec792dc2d9b2afd71f6613ded192988f1e162b81 + selfLink: https://github.com/kubernetes-sigs/controller-tools/releases/download/envtest-v1.26.1/envtest-v1.26.1-darwin-amd64.tar.gz + envtest-v1.26.1-darwin-arm64.tar.gz: + hash: e160a6c863b62c301582b6635d9dbea4275025639f5895b11fc61b11a9986d401cf56695ae8f7600dc17c5aa5900c90dafb5c900fb7166271458948eed6df68f + selfLink: https://github.com/kubernetes-sigs/controller-tools/releases/download/envtest-v1.26.1/envtest-v1.26.1-darwin-arm64.tar.gz + envtest-v1.26.1-linux-amd64.tar.gz: + hash: 9ddb3e172759be64b0748c0d103a976dfd6aecdcaa0c8fff7724a89b7426b3e00863b8782b3dff16f04768be9e56acbda3755e7c7c00571bc3a8d100b25e04b1 + selfLink: https://github.com/kubernetes-sigs/controller-tools/releases/download/envtest-v1.26.1/envtest-v1.26.1-linux-amd64.tar.gz + envtest-v1.26.1-linux-arm64.tar.gz: + hash: 988f35b688c50ce49056d7549f0532523973b5e7e3629631cda74f2e7c7ad3715cfb8e746ce48e9b366aaad57ac1d191f9735e59e491986bb2d50ef85001bed4 + selfLink: https://github.com/kubernetes-sigs/controller-tools/releases/download/envtest-v1.26.1/envtest-v1.26.1-linux-arm64.tar.gz + envtest-v1.26.1-linux-ppc64le.tar.gz: + hash: bf216cbb7bfe453c06d55c4d0dca9765bdede5485eccd67fb87a2178d41ab2f9a04be9e6c57b0031c3fa71b8e34490797b4f71a6bbcd5c324791c147ffd0fc53 + selfLink: https://github.com/kubernetes-sigs/controller-tools/releases/download/envtest-v1.26.1/envtest-v1.26.1-linux-ppc64le.tar.gz + envtest-v1.26.1-linux-s390x.tar.gz: + hash: c9b4c833600aec7f5923690bd474eddcde75e75446e6324b0c800a5b089413cf3402cc7f72d2154dbbddb00b1e45972042e717af5a31473bcab12f072446c344 + selfLink: https://github.com/kubernetes-sigs/controller-tools/releases/download/envtest-v1.26.1/envtest-v1.26.1-linux-s390x.tar.gz + envtest-v1.26.1-windows-amd64.tar.gz: + hash: a1394eae03b0eddaf04d08482d823a7f507db67ca9ed7dd775c6953457cd111f7042019a0fbbc07fcb8c52ec3804933a0c6d8643c8336fd8d66a063fa7a43d89 + selfLink: https://github.com/kubernetes-sigs/controller-tools/releases/download/envtest-v1.26.1/envtest-v1.26.1-windows-amd64.tar.gz + v1.29.1: + envtest-v1.29.1-darwin-amd64.tar.gz: + hash: c6c5065eef420239823288fe9d71a6fecf398737149ef32b38ba649b2b00ebf6ad2660dbd31f92bd92925cb82a93acc7464e0ff03354f60fb8feb2a204066895 + selfLink: https://github.com/kubernetes-sigs/controller-tools/releases/download/envtest-v1.29.1/envtest-v1.29.1-darwin-amd64.tar.gz + envtest-v1.29.1-darwin-arm64.tar.gz: + hash: 402029dc5e15b9033e6046457269aac845f98b801dac7959d5e0390ee9ef95c8225094f7f2f3e9666fa2bf8beca75980030237383614088365bf7ea8006833f3 + selfLink: https://github.com/kubernetes-sigs/controller-tools/releases/download/envtest-v1.29.1/envtest-v1.29.1-darwin-arm64.tar.gz + envtest-v1.29.1-linux-amd64.tar.gz: + hash: ee6d019d3f0209dea2c5871508137bba9b8d3dee7ea287a7dcdfa520aca9de62fe25ed36e9bd693e2633b86adc93944b34524d2686e9a2cfe0e3159ab04e2fcc + selfLink: https://github.com/kubernetes-sigs/controller-tools/releases/download/envtest-v1.29.1/envtest-v1.29.1-linux-amd64.tar.gz + envtest-v1.29.1-linux-arm64.tar.gz: + hash: 7a4aea49a69640466295600ff2d0e66d9f4f720a8247aa63ea84c8fc1fdea2312653b4ae92bf533e51783cc7fb1870da78689a2ef8747116a83bd4adda1d7c12 + selfLink: https://github.com/kubernetes-sigs/controller-tools/releases/download/envtest-v1.29.1/envtest-v1.29.1-linux-arm64.tar.gz + envtest-v1.29.1-linux-ppc64le.tar.gz: + hash: 0feb6ca2d886bf9ebc917b8cc5ba0233072d92d220d335e8f1a0cc8d74d1d1591e55dfbfc605a9aa63d027a01d8cc5d1a860010cf7fe1d9d846f7868b4213550 + selfLink: https://github.com/kubernetes-sigs/controller-tools/releases/download/envtest-v1.29.1/envtest-v1.29.1-linux-ppc64le.tar.gz + envtest-v1.29.1-linux-s390x.tar.gz: + hash: e36f7982c0e6507c2feec737d66875fd0daa95e4263f22f7311e07b29c953f89f192ca8ddaf6a0bc22c88ed38444012f590d6a84e8d01138c97a86916f4d7ce6 + selfLink: https://github.com/kubernetes-sigs/controller-tools/releases/download/envtest-v1.29.1/envtest-v1.29.1-linux-s390x.tar.gz + envtest-v1.29.1-windows-amd64.tar.gz: + hash: c5b65cee850dcb70ea2ecea49b7411e3b83f640a54ea2ce6c029c22b802e083fbefd92989a3377917233a7d5157dc6fccbbf1916ce8008515641c32f2c9530c5 + selfLink: https://github.com/kubernetes-sigs/controller-tools/releases/download/envtest-v1.29.1/envtest-v1.29.1-windows-amd64.tar.gz + v1.24.2: + envtest-v1.24.2-darwin-amd64.tar.gz: + hash: 8d0a73308daafbb65ed97449bce81e09d249045d4594ce4e4050cc8c5f2aa3147bf4a4fbda6b73a18b0a0cba4f88a01a4e0b9f66c371eba924e3bb36fe9860d5 + selfLink: https://github.com/kubernetes-sigs/controller-tools/releases/download/envtest-v1.24.2/envtest-v1.24.2-darwin-amd64.tar.gz + envtest-v1.24.2-darwin-arm64.tar.gz: + hash: f2eb57ac07a0eeb97d6a8e36bc397eb0b5bcaa432ccadb5a574d5684dd482d2121a193f3dfdf1ee04b4df7cdead8d899c5a57e753283ea406bad560063dbabb7 + selfLink: https://github.com/kubernetes-sigs/controller-tools/releases/download/envtest-v1.24.2/envtest-v1.24.2-darwin-arm64.tar.gz + envtest-v1.24.2-linux-amd64.tar.gz: + hash: 2b330c1802f7fd858a8a6e97141b07a4260eec135712c8913d36bb8e48f8dbfa45a8e5b13c15e7c20127a55d75bfda5007bf018e853cf156e3ac2b019d492892 + selfLink: https://github.com/kubernetes-sigs/controller-tools/releases/download/envtest-v1.24.2/envtest-v1.24.2-linux-amd64.tar.gz + envtest-v1.24.2-linux-arm64.tar.gz: + hash: 5cda1ba1f734a067e8b823130fca9c6bec151106aa1d32856ef7524afdfdd733e6c5c87b1b8d41c293083fd64ac668db8b74dca26554e0c99e0120e6f99f9e21 + selfLink: https://github.com/kubernetes-sigs/controller-tools/releases/download/envtest-v1.24.2/envtest-v1.24.2-linux-arm64.tar.gz + envtest-v1.24.2-linux-ppc64le.tar.gz: + hash: c2b72f3dbdda268aadb86c3abe78af412c74a750b652b5c326cab6b06a8ede9c2f57dfad16c9e6fddc68c56228ab0a61b9da0131b53f4de6abcd465f272eaf0b + selfLink: https://github.com/kubernetes-sigs/controller-tools/releases/download/envtest-v1.24.2/envtest-v1.24.2-linux-ppc64le.tar.gz + envtest-v1.24.2-linux-s390x.tar.gz: + hash: 1dc3f4b7375fdb703c1dd84e302559c7245c0676250e26f7396ad145f14162897c327812a7e4336b3b233b329338b58d3340f288490918c25883f1c2df0689ad + selfLink: https://github.com/kubernetes-sigs/controller-tools/releases/download/envtest-v1.24.2/envtest-v1.24.2-linux-s390x.tar.gz + envtest-v1.24.2-windows-amd64.tar.gz: + hash: b9708002e6265eb72ee3ba8a229624dbb1328881f08e53855b2d22fb334d6b40af3de11b9598f3a4c6829bbb6c787aa4556479855354eda1e899df34a2e93a5c + selfLink: https://github.com/kubernetes-sigs/controller-tools/releases/download/envtest-v1.24.2/envtest-v1.24.2-windows-amd64.tar.gz + v1.24.1: + envtest-v1.24.1-darwin-amd64.tar.gz: + hash: d00c0a8ac45d3c0bad1294ace3d8502681d84e48c7dbafb7f809371c8d2e517174fc5bf7ba23cd0b2b0965835abe9afc27b61725ffee90cce6119093f1428e73 + selfLink: https://github.com/kubernetes-sigs/controller-tools/releases/download/envtest-v1.24.1/envtest-v1.24.1-darwin-amd64.tar.gz + envtest-v1.24.1-darwin-arm64.tar.gz: + hash: fa1dfc2fd6e53869f55880aa9eb8dc45281559dea31079ab6e8bd6a55ad0e138477d5e77662acaf4ed90543223e1fa7f699e607a4ea1325f7ed187eeda7047f8 + selfLink: https://github.com/kubernetes-sigs/controller-tools/releases/download/envtest-v1.24.1/envtest-v1.24.1-darwin-arm64.tar.gz + envtest-v1.24.1-linux-amd64.tar.gz: + hash: bf99a87747430c7369fcfe63638f9a10c3b6a4581cfe93dec5fdd58036e270360b48bcceba1dc57b2439ba9c9d50dc330128737136893a0ed9b67babd82f3090 + selfLink: https://github.com/kubernetes-sigs/controller-tools/releases/download/envtest-v1.24.1/envtest-v1.24.1-linux-amd64.tar.gz + envtest-v1.24.1-linux-arm64.tar.gz: + hash: f654eda063fa216230460664ab934ddb3f26816565bc3ff78a2fe6ad791a784c4fa5b097644e2215eb08d29fc84b7adf6bd3e88f1d868f1cc239ce2eff8c1faa + selfLink: https://github.com/kubernetes-sigs/controller-tools/releases/download/envtest-v1.24.1/envtest-v1.24.1-linux-arm64.tar.gz + envtest-v1.24.1-linux-ppc64le.tar.gz: + hash: 567075b7d40826539eaef36b4de78eb2b3007634d2925becf6144651b0fb7d523d116f3b0a3fc644a72e13d472410d6b9a5a36f0304e069d53709537c203db35 + selfLink: https://github.com/kubernetes-sigs/controller-tools/releases/download/envtest-v1.24.1/envtest-v1.24.1-linux-ppc64le.tar.gz + envtest-v1.24.1-linux-s390x.tar.gz: + hash: 55c290a11e0cc7259bb4c4890781fb97c7e31ae35c727dea6403335d1df7f9104b4f765f5c3dd721a10393515928b5971ea5a310247ae04246db561021b0e287 + selfLink: https://github.com/kubernetes-sigs/controller-tools/releases/download/envtest-v1.24.1/envtest-v1.24.1-linux-s390x.tar.gz + envtest-v1.24.1-windows-amd64.tar.gz: + hash: 0074a2ae634d9a6bc0e8282471c5908b0469f5d578672c99e89107cc436a4e1173e747ff6b500016ef41aceb2815b74156f1d0c4e2e5acb79e07614c5c3c8600 + selfLink: https://github.com/kubernetes-sigs/controller-tools/releases/download/envtest-v1.24.1/envtest-v1.24.1-windows-amd64.tar.gz + v1.28.3: + envtest-v1.28.3-darwin-amd64.tar.gz: + hash: 818ff0f9149338df6c15e42ecb88b24745a3f340a989d8a70b5e3c9706a12c19b4a7de873feb778020665dd7975ec9beddb7aa5e9c60dca3782962253b57a1db + selfLink: https://github.com/kubernetes-sigs/controller-tools/releases/download/envtest-v1.28.3/envtest-v1.28.3-darwin-amd64.tar.gz + envtest-v1.28.3-darwin-arm64.tar.gz: + hash: eb9aea2b6dd196b84d8bed76bb0da8b4c8e9f11dd96e5d7224ebdb3a63f61a4cceafe21774c78e555fc3b32505e7973e1cf3fa9e87103546e088f7e86128c5c6 + selfLink: https://github.com/kubernetes-sigs/controller-tools/releases/download/envtest-v1.28.3/envtest-v1.28.3-darwin-arm64.tar.gz + envtest-v1.28.3-linux-amd64.tar.gz: + hash: db7aafadfa3c1cb5c7bd82f375425b11d6652129580ac507b2e2e290c1018ef18737352d506903503a1d47cc1569f050dff71ba22f06057f7a2ae318afd9f4e5 + selfLink: https://github.com/kubernetes-sigs/controller-tools/releases/download/envtest-v1.28.3/envtest-v1.28.3-linux-amd64.tar.gz + envtest-v1.28.3-linux-arm64.tar.gz: + hash: a5b9945d5b209c68cf88b8f5f4baacdd759d5b09536b4b05357a66bb85ee6da245bd1af1673b479075c7eb0b46041af1aae2a07cefaa5fcfe5f55dfe09984f96 + selfLink: https://github.com/kubernetes-sigs/controller-tools/releases/download/envtest-v1.28.3/envtest-v1.28.3-linux-arm64.tar.gz + envtest-v1.28.3-linux-ppc64le.tar.gz: + hash: c3332e33361c333ec6cf525959ad26b8d854b6859714020b068a4340427eb9c88117825857808cbb31dc094c0fae2b47830427c6cd6b3be9d50e864cfedabab0 + selfLink: https://github.com/kubernetes-sigs/controller-tools/releases/download/envtest-v1.28.3/envtest-v1.28.3-linux-ppc64le.tar.gz + envtest-v1.28.3-linux-s390x.tar.gz: + hash: 32dc0171444f762ef746d09b722cd421d56da514191197af59d8677281cd7aa9371cfc95f2f89781aa89eab967dd9405e89ecdc3ff69bd61b16366433870bd54 + selfLink: https://github.com/kubernetes-sigs/controller-tools/releases/download/envtest-v1.28.3/envtest-v1.28.3-linux-s390x.tar.gz + envtest-v1.28.3-windows-amd64.tar.gz: + hash: 8ebe28deabbdd635477fec8b2d313dc4d4e9a871bfdbf36614d357dc4883d34523f9b7e4c21ddf665aaad5b99d9fdf5fb64eb3caf52e676b3720b45ec023028b + selfLink: https://github.com/kubernetes-sigs/controller-tools/releases/download/envtest-v1.28.3/envtest-v1.28.3-windows-amd64.tar.gz + v1.23.5: + envtest-v1.23.5-darwin-amd64.tar.gz: + hash: 0a54def5dee969866694e38400f3daee052dc61fcdb8a93a402a957e9d8e297d934a82ea2a96de80c4e6a59858afc7ad577a6eebc422675933bc7632434b2d69 + selfLink: https://github.com/kubernetes-sigs/controller-tools/releases/download/envtest-v1.23.5/envtest-v1.23.5-darwin-amd64.tar.gz + envtest-v1.23.5-darwin-arm64.tar.gz: + hash: cb40666cd83d8bbf464ef99835d353d7cd02622c29fcb2fdbbbcb8880bbe02b35bfb10667fb8e9dc6e00bc4ab50727e6ce1486b1e98442865f9daebc9eb58cd6 + selfLink: https://github.com/kubernetes-sigs/controller-tools/releases/download/envtest-v1.23.5/envtest-v1.23.5-darwin-arm64.tar.gz + envtest-v1.23.5-linux-amd64.tar.gz: + hash: 9c9ef4082877558c28cc0b8f5bef7f20dbb62749865ae5397135df5c185d15d59cbb13b070813e2761e9de45b296909678856770148af5ee55a45d413246c44e + selfLink: https://github.com/kubernetes-sigs/controller-tools/releases/download/envtest-v1.23.5/envtest-v1.23.5-linux-amd64.tar.gz + envtest-v1.23.5-linux-arm64.tar.gz: + hash: 471bc06e7af168c34c06673d6ce5018eb43d7bb38a34bf50001e69b4e947d5b6350ae68887028985fd2566e6adfdc8637b4b97406ea87caf0cdc5fa28a832b59 + selfLink: https://github.com/kubernetes-sigs/controller-tools/releases/download/envtest-v1.23.5/envtest-v1.23.5-linux-arm64.tar.gz + envtest-v1.23.5-linux-ppc64le.tar.gz: + hash: bf1e3b76a1ca2cc602c47d2cd6e517268d28f54ef4fab457938aeac6a0f721503341371ddeec14f186870be4fd16aaa175d780814589a79377ad165ef0f8c6e1 + selfLink: https://github.com/kubernetes-sigs/controller-tools/releases/download/envtest-v1.23.5/envtest-v1.23.5-linux-ppc64le.tar.gz + envtest-v1.23.5-linux-s390x.tar.gz: + hash: f668d972e7d5715b8314c99804e33ce513411c41ef70b30df145fa10c1509e2f2b5493a99dddd63beba4b9f3c26b8389e03c74c46944077fdeb22b6d785958f6 + selfLink: https://github.com/kubernetes-sigs/controller-tools/releases/download/envtest-v1.23.5/envtest-v1.23.5-linux-s390x.tar.gz + envtest-v1.23.5-windows-amd64.tar.gz: + hash: d69058b3dc4c785c2c2c6a7a650c909751150a769e8f6720774f4cb0645a120064d1b419edcd43406dfca7641d51ef18fd6f49c123fc70ecc6f54f569a651d79 + selfLink: https://github.com/kubernetes-sigs/controller-tools/releases/download/envtest-v1.23.5/envtest-v1.23.5-windows-amd64.tar.gz + v1.29.5: + envtest-v1.29.5-darwin-amd64.tar.gz: + hash: 7abeaf5c0f1c2b6fa2ab8ff0ffd8eb1bd1db638243fa8f2183cb9dbde84744c5e8ba4dd6636b53d1210c6e8731dc29419fceb1108f86b872cb3c1afacaa2a3c4 + selfLink: https://github.com/kubernetes-sigs/controller-tools/releases/download/envtest-v1.29.5/envtest-v1.29.5-darwin-amd64.tar.gz + envtest-v1.29.5-darwin-arm64.tar.gz: + hash: 44d301abae4421b1e4427de4153b7305a2392302dfda79242633eb0c44029ce60f607a91da8412ae96ea8ef33d5fbe642f1c5a72e60ca5ffa8e606c2ef31f056 + selfLink: https://github.com/kubernetes-sigs/controller-tools/releases/download/envtest-v1.29.5/envtest-v1.29.5-darwin-arm64.tar.gz + envtest-v1.29.5-linux-amd64.tar.gz: + hash: b11190b9dd52e473ce57f780a145fc6e2250794a2a9fed4db9b4b13043df436a5fc66c077f1eb4808761764066a1936da27660c62d02ab5925b264f3f7caf7b5 + selfLink: https://github.com/kubernetes-sigs/controller-tools/releases/download/envtest-v1.29.5/envtest-v1.29.5-linux-amd64.tar.gz + envtest-v1.29.5-linux-arm64.tar.gz: + hash: 7cb476a57076775faec1ef6ea264bd3bb954432da0166b93c92f517869bceb51336121b4ec050bef5e5a5a1ca4dfbf3d73d56fd90acc56c90c09ed064eb92d7a + selfLink: https://github.com/kubernetes-sigs/controller-tools/releases/download/envtest-v1.29.5/envtest-v1.29.5-linux-arm64.tar.gz + envtest-v1.29.5-linux-ppc64le.tar.gz: + hash: a63974204e3bbb911144b96a520e2f116d8627279b975423d86b24336267e47f3132a0f39d5105bc7d49cd2831c017ea8bdca62467438391c0fffd48f4468bd3 + selfLink: https://github.com/kubernetes-sigs/controller-tools/releases/download/envtest-v1.29.5/envtest-v1.29.5-linux-ppc64le.tar.gz + envtest-v1.29.5-linux-s390x.tar.gz: + hash: 05340cc544e496c7ed5b900f82d3f5cf16c781aa00b187dce787900388e82515fe4aff818fc603f4a1faf514c9ae26179df53567a8f65b0d7f81f4f23903b4ce + selfLink: https://github.com/kubernetes-sigs/controller-tools/releases/download/envtest-v1.29.5/envtest-v1.29.5-linux-s390x.tar.gz + envtest-v1.29.5-windows-amd64.tar.gz: + hash: d440e3af67f4ea5f545981afb8ba8c56949d0a7d7b165347bac91338673b79024ff4137fe23344d0d685ee275efe5ef4066ba2d0bf84742cd8e2fe8ebeffa55c + selfLink: https://github.com/kubernetes-sigs/controller-tools/releases/download/envtest-v1.29.5/envtest-v1.29.5-windows-amd64.tar.gz + v1.30.2: + envtest-v1.30.2-darwin-amd64.tar.gz: + hash: bfae3317e7aa03913d1435a08cd110ac4630224389234f14f29d1ff35337acb7039bf6421041da849c3e4cc6c2847d285c29c3eb5218d4e921efb073eb413bdc + selfLink: https://github.com/kubernetes-sigs/controller-tools/releases/download/envtest-v1.30.2/envtest-v1.30.2-darwin-amd64.tar.gz + envtest-v1.30.2-darwin-arm64.tar.gz: + hash: 559cb740f222825f4fd18933327d5d05760f0f55f9098cee0fca8880c6de10f66b71e6bba5841a7dff143a9ed2251e2d8904d88af79d5d7e3b901d21c1cc8c1c + selfLink: https://github.com/kubernetes-sigs/controller-tools/releases/download/envtest-v1.30.2/envtest-v1.30.2-darwin-arm64.tar.gz + envtest-v1.30.2-linux-amd64.tar.gz: + hash: be8da7b4707547b7ca0d9a1eb19c5687f462fef8a912f06d6a7fc0e6088ee1c2e64b23fb330a5b4e9ef3c3500a3b069f16645e501ae475f1e99805a5f30e5700 + selfLink: https://github.com/kubernetes-sigs/controller-tools/releases/download/envtest-v1.30.2/envtest-v1.30.2-linux-amd64.tar.gz + envtest-v1.30.2-linux-arm64.tar.gz: + hash: 64840690a9d757a0f59f09f1a6d9b54e025d740d7a1cdc33785a5d05fb8f5de99a40ed6c8608bb846d3d9b803d4f393f9474e0174fc395e319042cfff36268c5 + selfLink: https://github.com/kubernetes-sigs/controller-tools/releases/download/envtest-v1.30.2/envtest-v1.30.2-linux-arm64.tar.gz + envtest-v1.30.2-linux-ppc64le.tar.gz: + hash: aa412c1a40ce3a9ac64c4e4278cc2485da480ac26750f372212139f6e93a5c999858b88661c8831740bc0a18ce3c0ca347336c6e81ddf3ac8b60cc3666f252cf + selfLink: https://github.com/kubernetes-sigs/controller-tools/releases/download/envtest-v1.30.2/envtest-v1.30.2-linux-ppc64le.tar.gz + envtest-v1.30.2-linux-s390x.tar.gz: + hash: 2316ceeffd0170c8b4d7c88a86eb2d14c012f2f6f17448052c0e891156706940b9c8df8b168b2f46506eff9d6ecdf807012ddc4307e8c55117b14f860a3b1ba5 + selfLink: https://github.com/kubernetes-sigs/controller-tools/releases/download/envtest-v1.30.2/envtest-v1.30.2-linux-s390x.tar.gz + envtest-v1.30.2-windows-amd64.tar.gz: + hash: 0a2d6405cd4211bfbdabffe2146fd78dfaf7562ef7fdf5ef910efae202dec944f2514053e99dca9f9c3352ac20cff62881dcc0adb5f3d2251bf019c41e9605ef + selfLink: https://github.com/kubernetes-sigs/controller-tools/releases/download/envtest-v1.30.2/envtest-v1.30.2-windows-amd64.tar.gz + v1.31.0-beta.0: + envtest-v1.31.0-beta.0-darwin-amd64.tar.gz: + hash: 8a37e38e6e590102c44d55b9fed36a011b03db24ddcb5f355cf6c4af1c70ffde338056d12ad809d0b0aa6f154cdb4372499bc68cc2e2944f4c5f97334e220a76 + selfLink: https://github.com/kubernetes-sigs/controller-tools/releases/download/envtest-v1.31.0-beta.0/envtest-v1.31.0-beta.0-darwin-amd64.tar.gz + envtest-v1.31.0-beta.0-darwin-arm64.tar.gz: + hash: d50f73f7c4c1174f31c858dc1f9cbaf70cc4d1a119ce85d83cb876aa4d25433c38e8eb1235386ca249add1026aedb12777190777cadea369100e990411528fe9 + selfLink: https://github.com/kubernetes-sigs/controller-tools/releases/download/envtest-v1.31.0-beta.0/envtest-v1.31.0-beta.0-darwin-arm64.tar.gz + envtest-v1.31.0-beta.0-linux-amd64.tar.gz: + hash: 11ca704b2072081fd651acd65f28f62e6595a56b59664877cbcd12eb7507a2fbbd02468eef9c5aeeea73ac906724011d40f5461ccb9143f15d8777058543f936 + selfLink: https://github.com/kubernetes-sigs/controller-tools/releases/download/envtest-v1.31.0-beta.0/envtest-v1.31.0-beta.0-linux-amd64.tar.gz + envtest-v1.31.0-beta.0-linux-arm64.tar.gz: + hash: df90e1af8a8af485010a607164a7da87be8c13e7635d5b542cb68d402973e9e5cb41e9cfd76936eacd6199da638e6e37fbcc01f27e49a27dd98fa45abcd7e91f + selfLink: https://github.com/kubernetes-sigs/controller-tools/releases/download/envtest-v1.31.0-beta.0/envtest-v1.31.0-beta.0-linux-arm64.tar.gz + envtest-v1.31.0-beta.0-linux-ppc64le.tar.gz: + hash: 686cfbc1f8063533f6a5b3dae753e44d26fa41ed5d1106a111cda17a60d7b3ce417f6962ba1715ee5e8e14e9c4d6058e197cc4262f21577fd1f2253e2960ccf9 + selfLink: https://github.com/kubernetes-sigs/controller-tools/releases/download/envtest-v1.31.0-beta.0/envtest-v1.31.0-beta.0-linux-ppc64le.tar.gz + envtest-v1.31.0-beta.0-linux-s390x.tar.gz: + hash: e74239d9d3de6a847732b432fb287e98db176bf9fd5126f999bf507365ad71d5b80e4eeee8d8b3b3be0ab2e9125eab4f5ab685a752acb06e0291b8749d566846 + selfLink: https://github.com/kubernetes-sigs/controller-tools/releases/download/envtest-v1.31.0-beta.0/envtest-v1.31.0-beta.0-linux-s390x.tar.gz + envtest-v1.31.0-beta.0-windows-amd64.tar.gz: + hash: 547a6d5c224b7f5af534c3eb6b8a2fec8d4e19baf8550506d7aa6363f9f7ab639e41a7f546bf406ab77000c785aabd71eb3aa6beb8eb3a2d75fbb9e9c912f90a + selfLink: https://github.com/kubernetes-sigs/controller-tools/releases/download/envtest-v1.31.0-beta.0/envtest-v1.31.0-beta.0-windows-amd64.tar.gz diff --git a/go.mod b/go.mod index b913aee15..622bc3691 100644 --- a/go.mod +++ b/go.mod @@ -1,44 +1,45 @@ module sigs.k8s.io/controller-tools -go 1.19 +go 1.22.0 require ( - github.com/fatih/color v1.13.0 - github.com/gobuffalo/flect v0.3.0 - github.com/google/go-cmp v0.5.9 + github.com/fatih/color v1.17.0 + github.com/gobuffalo/flect v1.0.2 + github.com/google/go-cmp v0.6.0 github.com/onsi/ginkgo v1.16.5 - github.com/onsi/gomega v1.24.2 - github.com/spf13/cobra v1.6.1 + github.com/onsi/gomega v1.34.0 + github.com/spf13/cobra v1.8.1 github.com/spf13/pflag v1.0.5 - golang.org/x/tools v0.4.0 + golang.org/x/tools v0.23.0 gopkg.in/yaml.v2 v2.4.0 gopkg.in/yaml.v3 v3.0.1 - k8s.io/api v0.26.0 - k8s.io/apiextensions-apiserver v0.26.0 - k8s.io/apimachinery v0.26.0 - sigs.k8s.io/yaml v1.3.0 + k8s.io/api v0.30.3 + k8s.io/apiextensions-apiserver v0.30.3 + k8s.io/apimachinery v0.30.3 + k8s.io/utils v0.0.0-20230726121419-3b25d923346b + sigs.k8s.io/yaml v1.4.0 ) require ( - github.com/fsnotify/fsnotify v1.6.0 // indirect - github.com/go-logr/logr v1.2.3 // indirect + github.com/fsnotify/fsnotify v1.7.0 // indirect + github.com/go-logr/logr v1.4.1 // indirect github.com/gogo/protobuf v1.3.2 // indirect - github.com/google/gofuzz v1.1.0 // indirect - github.com/inconshreveable/mousetrap v1.0.1 // indirect + github.com/google/gofuzz v1.2.0 // indirect + github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/json-iterator/go v1.1.12 // indirect - github.com/mattn/go-colorable v0.1.9 // indirect - github.com/mattn/go-isatty v0.0.14 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/nxadm/tail v1.4.8 // indirect - golang.org/x/mod v0.7.0 // indirect - golang.org/x/net v0.4.0 // indirect - golang.org/x/sys v0.3.0 // indirect - golang.org/x/text v0.5.0 // indirect + golang.org/x/mod v0.19.0 // indirect + golang.org/x/net v0.27.0 // indirect + golang.org/x/sync v0.7.0 // indirect + golang.org/x/sys v0.22.0 // indirect + golang.org/x/text v0.16.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect - k8s.io/klog/v2 v2.80.1 // indirect - k8s.io/utils v0.0.0-20221107191617-1a15be271d1d // indirect - sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2 // indirect - sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect + k8s.io/klog/v2 v2.120.1 // indirect + sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect + sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect ) diff --git a/go.sum b/go.sum index 2a7f4a78c..c3f59974d 100644 --- a/go.sum +++ b/go.sum @@ -1,19 +1,21 @@ -github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= 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/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= -github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/fatih/color v1.17.0 h1:GlRw1BRJxkpqUCBKzKOw098ed57fEsKeNjpTe3cSjK4= +github.com/fatih/color v1.17.0/go.mod h1:YZ7TlrGPkiz6ku9fK3TLD/pl3CpsiFyu8N92HLgmosI= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= 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/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0= -github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= +github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= +github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ= +github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= -github.com/gobuffalo/flect v0.3.0 h1:erfPWM+K1rFNIQeRPdeEXxo8yFr/PO17lhRnS8FUrtk= -github.com/gobuffalo/flect v0.3.0/go.mod h1:5pf3aGnsvqvCj50AVni7mJJF8ICxGZ8HomberC3pXLE= +github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= +github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= +github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= +github.com/gobuffalo/flect v1.0.2 h1:eqjPGSo2WmjgY2XlpGwo2NXgL3RucAKo4k4qQMNA5sA= +github.com/gobuffalo/flect v1.0.2/go.mod h1:A5msMlrHtLqh9umBSnvabjsMrCcCpAyzglnDvkbYKHs= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -23,34 +25,38 @@ github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrU 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/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= 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.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/gofuzz v1.1.0 h1:Hsa8mG0dQ46ij8Sl2AYJDUv1oA9/d6Vk+3LG99Oe02g= -github.com/google/gofuzz v1.1.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-20240424215950-a892ee059fd6 h1:k7nVchz72niMH6YLQNvHSdIE7iqsQxK1P41mySCvssg= +github.com/google/pprof v0.0.0-20240424215950-a892ee059fd6/go.mod h1:kf6iHlnVGwgKolg33glAes7Yg/8iWP8ukqeldJSO7jw= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= -github.com/inconshreveable/mousetrap v1.0.1 h1:U3uMjPSQEBMNp1lFxmllqCPM6P5u/Xq7Pgzkat/bFNc= -github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= +github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= 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.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= -github.com/mattn/go-colorable v0.1.9 h1:sqDoxXbdeALODt0DAeJCVp38ps9ZogZEAXjus69YV3U= -github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= -github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= -github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y= -github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +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.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= 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/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= @@ -58,25 +64,31 @@ github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+W github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= 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.6.1 h1:1xQPCjcqYw/J5LchOcp4/2q/jzJFjiAOc25chhnDw+Q= +github.com/onsi/ginkgo/v2 v2.19.0 h1:9Cnnf7UHo57Hy3k6/m5k3dRfGTMXGvxhHFvkDTCTpvA= +github.com/onsi/ginkgo/v2 v2.19.0/go.mod h1:rlwLi9PilAFJ8jCg9UE1QP6VBpd6/xj3SRC0d6TU0To= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= -github.com/onsi/gomega v1.24.2 h1:J/tulyYK6JwBldPViHJReihxxZ+22FHs0piGjQAvoUE= -github.com/onsi/gomega v1.24.2/go.mod h1:gs3J10IS7Z7r7eXRoNJIrNqU4ToQukCJhFtKrWgHWnk= +github.com/onsi/gomega v1.34.0 h1:eSSPsPNp6ZpsG8X1OVmOTxig+CblTc4AxpPBykhe2Os= +github.com/onsi/gomega v1.34.0/go.mod h1:MIKI8c+f+QLWk+hxbePD4i0LMJSExPaZOVfkoex4cAo= 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/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= +github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/spf13/cobra v1.6.1 h1:o94oiPyS4KD1mPy2fmcYYHHfCxLqYjJOhGsCHFZtEzA= -github.com/spf13/cobra v1.6.1/go.mod h1:IOw/AERYS7UzyrGinqmz6HLUo219MORXGxhbaJUqzrY= +github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM= +github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y= 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.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= 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/stretchr/testify v1.8.4/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= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= @@ -84,47 +96,46 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U 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/mod v0.7.0 h1:LapD9S96VoQRhi/GrNTqeBJFrUjs5UHCAtTlgwA5oZA= -golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.19.0 h1:fEdghXQSo20giMthA7cd28ZC+jts4amQ3YMXiP5oMQ8= +golang.org/x/mod v0.19.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 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-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.4.0 h1:Q5QPcMlvfxFTAPV0+07Xz/MpK9NTXu2VDUuy0FeMfaU= -golang.org/x/net v0.4.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= +golang.org/x/net v0.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys= +golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/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.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= +golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= +golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/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-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200116001909-b77594299b42/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-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.3.0 h1:w8ZOecv6NaNa/zC8944JTU3vz4u6Lagfk4RPQxv92NQ= -golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI= +golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= 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/text v0.5.0 h1:OLmvp0KP+FVG99Ct/qFiL/Fhk4zp4QQnZ7b2U+5piUM= -golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= +golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= 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-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.4.0 h1:7mTAgkunk3fr4GAloyyCasadO6h9zSsQZbwvcaIciV4= -golang.org/x/tools v0.4.0/go.mod h1:UE5sM2OK9E/d67R0ANs2xJizIymRP5gJU295PvKXxjQ= +golang.org/x/tools v0.23.0 h1:SGsXPZ+2l4JsgaCKkx+FQ9YZ5XEtA1GZYuoDjenLjvg= +golang.org/x/tools v0.23.0/go.mod h1:pnu6ufv6vQkll6szChhK3C3L/ruaIv5eBeztNG8wtsI= 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= @@ -135,9 +146,11 @@ google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQ 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/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= +google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg= +google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= +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/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= @@ -152,19 +165,19 @@ 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.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -k8s.io/api v0.26.0 h1:IpPlZnxBpV1xl7TGk/X6lFtpgjgntCg8PJ+qrPHAC7I= -k8s.io/api v0.26.0/go.mod h1:k6HDTaIFC8yn1i6pSClSqIwLABIcLV9l5Q4EcngKnQg= -k8s.io/apiextensions-apiserver v0.26.0 h1:Gy93Xo1eg2ZIkNX/8vy5xviVSxwQulsnUdQ00nEdpDo= -k8s.io/apiextensions-apiserver v0.26.0/go.mod h1:7ez0LTiyW5nq3vADtK6C3kMESxadD51Bh6uz3JOlqWQ= -k8s.io/apimachinery v0.26.0 h1:1feANjElT7MvPqp0JT6F3Ss6TWDwmcjLypwoPpEf7zg= -k8s.io/apimachinery v0.26.0/go.mod h1:tnPmbONNJ7ByJNz9+n9kMjNP8ON+1qoAIIC70lztu74= -k8s.io/klog/v2 v2.80.1 h1:atnLQ121W371wYYFawwYx1aEY2eUfs4l3J72wtgAwV4= -k8s.io/klog/v2 v2.80.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= -k8s.io/utils v0.0.0-20221107191617-1a15be271d1d h1:0Smp/HP1OH4Rvhe+4B8nWGERtlqAGSftbSbbmm45oFs= -k8s.io/utils v0.0.0-20221107191617-1a15be271d1d/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= -sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2 h1:iXTIw73aPyC+oRdyqqvVJuloN1p0AC/kzH07hu3NE+k= -sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2/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= +k8s.io/api v0.30.3 h1:ImHwK9DCsPA9uoU3rVh4QHAHHK5dTSv1nxJUapx8hoQ= +k8s.io/api v0.30.3/go.mod h1:GPc8jlzoe5JG3pb0KJCSLX5oAFIW3/qNJITlDj8BH04= +k8s.io/apiextensions-apiserver v0.30.3 h1:oChu5li2vsZHx2IvnGP3ah8Nj3KyqG3kRSaKmijhB9U= +k8s.io/apiextensions-apiserver v0.30.3/go.mod h1:uhXxYDkMAvl6CJw4lrDN4CPbONkF3+XL9cacCT44kV4= +k8s.io/apimachinery v0.30.3 h1:q1laaWCmrszyQuSQCfNB8cFgCuDAoPszKY4ucAjDwHc= +k8s.io/apimachinery v0.30.3/go.mod h1:iexa2somDaxdnj7bha06bhb43Zpa6eWH8N8dbqVjTUc= +k8s.io/klog/v2 v2.120.1 h1:QXU6cPEOIslTGvZaXvFWiP9VKyeet3sawzTOvdXb4Vw= +k8s.io/klog/v2 v2.120.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= +k8s.io/utils v0.0.0-20230726121419-3b25d923346b h1:sgn3ZU783SCgtaSJjpcVVlRqd6GSnlTLKgpAAttJvpI= +k8s.io/utils v0.0.0-20230726121419-3b25d923346b/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +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.4.1 h1:150L+0vs/8DA78h1u02ooW1/fFq/Lwr+sGiqlzvrtq4= +sigs.k8s.io/structured-merge-diff/v4 v4.4.1/go.mod h1:N8hJocpFajUSSeSJ9bOZ77VzejKZaXsTtZo4/u7Io08= +sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E= +sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY= diff --git a/hack/envtest/_matrix/v1.23.5.yaml b/hack/envtest/_matrix/v1.23.5.yaml new file mode 100644 index 000000000..2582912e6 --- /dev/null +++ b/hack/envtest/_matrix/v1.23.5.yaml @@ -0,0 +1,2 @@ +go: 1.17 +etcd: v3.5.5 diff --git a/hack/envtest/_matrix/v1.24.1.yaml b/hack/envtest/_matrix/v1.24.1.yaml new file mode 100644 index 000000000..8e3e802a1 --- /dev/null +++ b/hack/envtest/_matrix/v1.24.1.yaml @@ -0,0 +1,2 @@ +go: 1.18 +etcd: v3.5.5 diff --git a/hack/envtest/_matrix/v1.24.2.yaml b/hack/envtest/_matrix/v1.24.2.yaml new file mode 100644 index 000000000..8e3e802a1 --- /dev/null +++ b/hack/envtest/_matrix/v1.24.2.yaml @@ -0,0 +1,2 @@ +go: 1.18 +etcd: v3.5.5 diff --git a/hack/envtest/_matrix/v1.25.0.yaml b/hack/envtest/_matrix/v1.25.0.yaml new file mode 100644 index 000000000..6d42e7484 --- /dev/null +++ b/hack/envtest/_matrix/v1.25.0.yaml @@ -0,0 +1,2 @@ +go: 1.19 +etcd: v3.5.5 diff --git a/hack/envtest/_matrix/v1.26.0.yaml b/hack/envtest/_matrix/v1.26.0.yaml new file mode 100644 index 000000000..4f62e0bdd --- /dev/null +++ b/hack/envtest/_matrix/v1.26.0.yaml @@ -0,0 +1,2 @@ +go: 1.19 +etcd: v3.5.6 diff --git a/hack/envtest/_matrix/v1.26.1.yaml b/hack/envtest/_matrix/v1.26.1.yaml new file mode 100644 index 000000000..4f62e0bdd --- /dev/null +++ b/hack/envtest/_matrix/v1.26.1.yaml @@ -0,0 +1,2 @@ +go: 1.19 +etcd: v3.5.6 diff --git a/hack/envtest/_matrix/v1.27.1.yaml b/hack/envtest/_matrix/v1.27.1.yaml new file mode 100644 index 000000000..21a82ff0c --- /dev/null +++ b/hack/envtest/_matrix/v1.27.1.yaml @@ -0,0 +1,2 @@ +go: 1.20 +etcd: v3.5.7 diff --git a/hack/envtest/_matrix/v1.28.0.yaml b/hack/envtest/_matrix/v1.28.0.yaml new file mode 100644 index 000000000..83bf3ddd8 --- /dev/null +++ b/hack/envtest/_matrix/v1.28.0.yaml @@ -0,0 +1,2 @@ +go: 1.21 +etcd: v3.5.9 diff --git a/hack/envtest/_matrix/v1.28.3.yaml b/hack/envtest/_matrix/v1.28.3.yaml new file mode 100644 index 000000000..83bf3ddd8 --- /dev/null +++ b/hack/envtest/_matrix/v1.28.3.yaml @@ -0,0 +1,2 @@ +go: 1.21 +etcd: v3.5.9 diff --git a/hack/envtest/_matrix/v1.29.0.yaml b/hack/envtest/_matrix/v1.29.0.yaml new file mode 100644 index 000000000..0fc8f0442 --- /dev/null +++ b/hack/envtest/_matrix/v1.29.0.yaml @@ -0,0 +1,2 @@ +go: 1.21 +etcd: v3.5.10 diff --git a/hack/envtest/_matrix/v1.29.1.yaml b/hack/envtest/_matrix/v1.29.1.yaml new file mode 100644 index 000000000..0fc8f0442 --- /dev/null +++ b/hack/envtest/_matrix/v1.29.1.yaml @@ -0,0 +1,2 @@ +go: 1.21 +etcd: v3.5.10 diff --git a/hack/envtest/_matrix/v1.29.3.yaml b/hack/envtest/_matrix/v1.29.3.yaml new file mode 100644 index 000000000..d35406399 --- /dev/null +++ b/hack/envtest/_matrix/v1.29.3.yaml @@ -0,0 +1,2 @@ +go: 1.21 +etcd: v3.5.12 diff --git a/hack/envtest/_matrix/v1.29.4.yaml b/hack/envtest/_matrix/v1.29.4.yaml new file mode 100644 index 000000000..1090968d7 --- /dev/null +++ b/hack/envtest/_matrix/v1.29.4.yaml @@ -0,0 +1,3 @@ +go: 1.21 +etcd: v3.5.12 + diff --git a/hack/envtest/_matrix/v1.29.5.yaml b/hack/envtest/_matrix/v1.29.5.yaml new file mode 100644 index 000000000..d35406399 --- /dev/null +++ b/hack/envtest/_matrix/v1.29.5.yaml @@ -0,0 +1,2 @@ +go: 1.21 +etcd: v3.5.12 diff --git a/hack/envtest/_matrix/v1.30.0.yaml b/hack/envtest/_matrix/v1.30.0.yaml new file mode 100644 index 000000000..ae8ee24db --- /dev/null +++ b/hack/envtest/_matrix/v1.30.0.yaml @@ -0,0 +1,2 @@ +go: 1.22 +etcd: v3.5.12 diff --git a/hack/envtest/_matrix/v1.30.2.yaml b/hack/envtest/_matrix/v1.30.2.yaml new file mode 100644 index 000000000..ae8ee24db --- /dev/null +++ b/hack/envtest/_matrix/v1.30.2.yaml @@ -0,0 +1,2 @@ +go: 1.22 +etcd: v3.5.12 diff --git a/hack/envtest/_matrix/v1.31.0-beta.0.yaml b/hack/envtest/_matrix/v1.31.0-beta.0.yaml new file mode 100644 index 000000000..75c3a1b8a --- /dev/null +++ b/hack/envtest/_matrix/v1.31.0-beta.0.yaml @@ -0,0 +1,2 @@ +go: 1.22 +etcd: v3.5.14 diff --git a/hack/envtest/darwin/Dockerfile b/hack/envtest/darwin/Dockerfile new file mode 100644 index 000000000..c5746b5bf --- /dev/null +++ b/hack/envtest/darwin/Dockerfile @@ -0,0 +1,64 @@ +# Copyright 2018 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. + +ARG GO_VERSION +FROM golang:${GO_VERSION} as builder + +# Version and platform args. +ARG KUBERNETES_VERSION +ARG ETCD_VERSION +ARG OS=darwin +ARG ARCH + +# Tools path. +ENV DEST=/controller-tools/envtest + +# Install dependencies. +RUN apt update && \ + apt install unzip rsync -y && \ + mkdir -p $DEST + +# kube-apiserver +WORKDIR /kubernetes +RUN git clone https://github.com/kubernetes/kubernetes . --depth=1 -b ${KUBERNETES_VERSION} +ENV CGO_ENABLED=0 +ENV KUBE_BUILD_PLATFORMS=${OS}/${ARCH} +RUN make WHAT=cmd/kube-apiserver && \ + cp _output/local/bin/${KUBE_BUILD_PLATFORMS}/kube-apiserver $DEST + +# kubectl +RUN /bin/bash -x -c ' \ + { curl -sfLO https://storage.googleapis.com/kubernetes-release/release/${KUBERNETES_VERSION}/bin/${OS}/${ARCH}/kubectl && \ + chmod +x kubectl && \ + cp kubectl $DEST; } || \ + { make WHAT=cmd/kubectl && \ + cp _output/local/bin/${KUBE_BUILD_PLATFORMS}/kubectl $DEST; }' + +# etcd +ENV ETCD_BASE_NAME=etcd-${ETCD_VERSION}-${OS}-${ARCH} +RUN curl -sfLO https://github.com/coreos/etcd/releases/download/${ETCD_VERSION}/${ETCD_BASE_NAME}.zip && \ + unzip -o ${ETCD_BASE_NAME}.zip && \ + cp ${ETCD_BASE_NAME}/etcd $DEST + +# Package into tarball. +RUN tar -czvf /envtest-${KUBERNETES_VERSION}-${OS}-${ARCH}.tar.gz $DEST +RUN sha512sum /envtest-${KUBERNETES_VERSION}-${OS}-${ARCH}.tar.gz > /envtest-${KUBERNETES_VERSION}-${OS}-${ARCH}.tar.gz.sha512 + +# Build the final image with the binaries. +FROM scratch +ARG OS +ARG ARCH +ARG KUBERNETES_VERSION +COPY --from=builder /envtest-${KUBERNETES_VERSION}-${OS}-${ARCH}.tar.gz / +COPY --from=builder /envtest-${KUBERNETES_VERSION}-${OS}-${ARCH}.tar.gz.sha512 / diff --git a/hack/envtest/linux/Dockerfile b/hack/envtest/linux/Dockerfile new file mode 100644 index 000000000..cbc743fd2 --- /dev/null +++ b/hack/envtest/linux/Dockerfile @@ -0,0 +1,58 @@ +# Copyright 2018 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. + +ARG GO_VERSION +FROM golang:${GO_VERSION} as builder + +# Version and platform args. +ARG KUBERNETES_VERSION +ARG ETCD_VERSION +ARG OS=linux +ARG ARCH + +# Tools path. +ENV DEST=/controller-tools/envtest + +# Install dependencies. +RUN apt update && \ + apt install unzip rsync -y && \ + mkdir -p $DEST + +# kube-apiserver +RUN curl -sfLO https://dl.k8s.io/${KUBERNETES_VERSION}/bin/${OS}/${ARCH}/kube-apiserver && \ + chmod +x kube-apiserver && \ + cp kube-apiserver $DEST + +# kubectl +RUN curl -sfLO https://storage.googleapis.com/kubernetes-release/release/${KUBERNETES_VERSION}/bin/${OS}/${ARCH}/kubectl && \ + chmod +x kubectl && \ + cp kubectl $DEST + +# etcd +ENV ETCD_BASE_NAME=etcd-${ETCD_VERSION}-${OS}-${ARCH} +RUN curl -sfLO https://github.com/coreos/etcd/releases/download/${ETCD_VERSION}/${ETCD_BASE_NAME}.tar.gz && \ + tar xzf ${ETCD_BASE_NAME}.tar.gz && \ + cp ${ETCD_BASE_NAME}/etcd $DEST + +# Package into tarball. +RUN tar -czvf /envtest-${KUBERNETES_VERSION}-${OS}-${ARCH}.tar.gz $DEST +RUN sha512sum /envtest-${KUBERNETES_VERSION}-${OS}-${ARCH}.tar.gz > /envtest-${KUBERNETES_VERSION}-${OS}-${ARCH}.tar.gz.sha512 + +# Build the final image with the binaries. +FROM scratch +ARG OS +ARG ARCH +ARG KUBERNETES_VERSION +COPY --from=builder /envtest-${KUBERNETES_VERSION}-${OS}-${ARCH}.tar.gz / +COPY --from=builder /envtest-${KUBERNETES_VERSION}-${OS}-${ARCH}.tar.gz.sha512 / diff --git a/hack/envtest/update-releases.sh b/hack/envtest/update-releases.sh new file mode 100755 index 000000000..21ca91f85 --- /dev/null +++ b/hack/envtest/update-releases.sh @@ -0,0 +1,44 @@ +#!/usr/bin/env bash +# Copyright 2024 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. + +set -o errexit +set -o nounset +set -o pipefail +set -x + +ROOT=$(dirname "${BASH_SOURCE[0]}")/../.. + +if [ -z "${KUBERNETES_VERSION}" ]; then + echo "Missing KUBERNETES_VERSION environment variable" + exit 1 +fi + +# Create the releases.yaml file in hack/envtest if it does not exist +if [ ! -f "${ROOT}"/envtest-releases.yaml ]; then + echo "releases:" > "${ROOT}"/envtest-releases.yaml +fi + +# Add the newly built Kubernetes version to the releases.yaml file with yq as an object key under releases +yq eval ".releases += {\"${KUBERNETES_VERSION}\": {}}" -i "${ROOT}"/envtest-releases.yaml + +for file in "${ROOT}"/out/*.tar.gz; do + file_name=$(basename "${file}") + file_hash=$(awk '{ print $1 }' < "${file}.sha512") + self_link=https://github.com/kubernetes-sigs/controller-tools/releases/download/envtest-${KUBERNETES_VERSION}/${file_name} + + yq eval \ + ".releases[\"${KUBERNETES_VERSION}\"] += {\"${file_name}\": {\"hash\": \"${file_hash}\", \"selfLink\": \"${self_link}\"}}" \ + -i "${ROOT}"/envtest-releases.yaml +done diff --git a/hack/envtest/windows/Dockerfile b/hack/envtest/windows/Dockerfile new file mode 100644 index 000000000..81ee2188c --- /dev/null +++ b/hack/envtest/windows/Dockerfile @@ -0,0 +1,64 @@ +# Copyright 2018 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. + +ARG GO_VERSION +FROM golang:${GO_VERSION} as builder + +# Version and platform args. +ARG KUBERNETES_VERSION +ARG ETCD_VERSION +ARG OS=windows +ARG ARCH + +# Tools path. +ENV DEST=/controller-tools/envtest + +# Install dependencies. +RUN apt update && \ + apt install unzip rsync -y && \ + mkdir -p $DEST + +# kube-apiserver +WORKDIR /kubernetes +RUN git clone https://github.com/kubernetes/kubernetes . --depth=1 -b ${KUBERNETES_VERSION} +ENV CGO_ENABLED=0 +ENV KUBE_BUILD_PLATFORMS=${OS}/${ARCH} +RUN make WHAT=cmd/kube-apiserver && \ + cp _output/local/bin/${KUBE_BUILD_PLATFORMS}/kube-apiserver.exe $DEST + +# kubectl +RUN /bin/bash -x -c ' \ + { curl -sfLO https://storage.googleapis.com/kubernetes-release/release/${KUBERNETES_VERSION}/bin/${OS}/${ARCH}/kubectl.exe && \ + chmod +x kubectl.exe && \ + cp kubectl.exe $DEST; } || \ + { make WHAT=cmd/kubectl && \ + cp _output/local/bin/${KUBE_BUILD_PLATFORMS}/kubectl.exe $DEST; }' + +# etcd +ENV ETCD_BASE_NAME=etcd-${ETCD_VERSION}-${OS}-${ARCH} +RUN curl -sfLO https://github.com/coreos/etcd/releases/download/${ETCD_VERSION}/${ETCD_BASE_NAME}.zip && \ + unzip -o ${ETCD_BASE_NAME}.zip && \ + cp ${ETCD_BASE_NAME}/etcd.exe $DEST + +# Package into tarball. +RUN tar -czvf /envtest-${KUBERNETES_VERSION}-${OS}-${ARCH}.tar.gz $DEST +RUN sha512sum /envtest-${KUBERNETES_VERSION}-${OS}-${ARCH}.tar.gz > /envtest-${KUBERNETES_VERSION}-${OS}-${ARCH}.tar.gz.sha512 + +# Build the final image with the binaries. +FROM scratch +ARG OS +ARG ARCH +ARG KUBERNETES_VERSION +COPY --from=builder /envtest-${KUBERNETES_VERSION}-${OS}-${ARCH}.tar.gz / +COPY --from=builder /envtest-${KUBERNETES_VERSION}-${OS}-${ARCH}.tar.gz.sha512 / diff --git a/hack/go-install.sh b/hack/go-install.sh new file mode 100755 index 000000000..a07b8e0f1 --- /dev/null +++ b/hack/go-install.sh @@ -0,0 +1,45 @@ +#!/usr/bin/env bash +# Copyright 2021 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. + +set -o errexit +set -o nounset +set -o pipefail + +if [ -z "${1}" ]; then + echo "must provide module as first parameter" + exit 1 +fi + +if [ -z "${2}" ]; then + echo "must provide binary name as second parameter" + exit 1 +fi + +if [ -z "${3}" ]; then + echo "must provide version as third parameter" + exit 1 +fi + +if [ -z "${GOBIN}" ]; then + echo "GOBIN is not set. Must set GOBIN to install the bin in a specified directory." + exit 1 +fi + +rm -f "${GOBIN}/${2}"* || true + +# install the golang module specified as the first argument +go install "${1}@${3}" +mv "${GOBIN}/${2}" "${GOBIN}/${2}-${3}" +ln -sf "${GOBIN}/${2}-${3}" "${GOBIN}/${2}" diff --git a/hack/tools/.keep b/hack/tools/.keep new file mode 100644 index 000000000..e69de29bb diff --git a/pkg/crd/gen.go b/pkg/crd/gen.go index c6c5f88b8..ac8eb566d 100644 --- a/pkg/crd/gen.go +++ b/pkg/crd/gen.go @@ -21,6 +21,7 @@ import ( "go/ast" "go/types" "sort" + "strings" apiext "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" "k8s.io/apimachinery/pkg/runtime/schema" @@ -78,6 +79,26 @@ type Generator struct { // GenerateEmbeddedObjectMeta specifies if any embedded ObjectMeta in the CRD should be generated GenerateEmbeddedObjectMeta *bool `marker:",optional"` + + // HeaderFile specifies the header text (e.g. license) to prepend to generated files. + HeaderFile string `marker:",optional"` + + // Year specifies the year to substitute for " YEAR" in the header file. + Year string `marker:",optional"` + + // DeprecatedV1beta1CompatibilityPreserveUnknownFields indicates whether + // or not we should turn off field pruning for this resource. + // + // Specifies spec.preserveUnknownFields value that is false and omitted by default. + // This value can only be specified for CustomResourceDefinitions that were created with + // `apiextensions.k8s.io/v1beta1`. + // + // The field can be set for compatiblity reasons, although strongly discouraged, resource + // authors should move to a structural OpenAPI schema instead. + // + // See https://kubernetes.io/docs/tasks/extend-kubernetes/custom-resources/custom-resource-definitions/#field-pruning + // for more information about field pruning and v1beta1 resources compatibility. + DeprecatedV1beta1CompatibilityPreserveUnknownFields *bool `marker:",optional"` } func (Generator) CheckFilter() loader.NodeFilter { @@ -93,15 +114,25 @@ func transformRemoveCRDStatus(obj map[string]interface{}) error { return nil } +// transformPreserveUnknownFields adds spec.preserveUnknownFields=value. +func transformPreserveUnknownFields(value bool) func(map[string]interface{}) error { + return func(obj map[string]interface{}) error { + if spec, ok := obj["spec"].(map[interface{}]interface{}); ok { + spec["preserveUnknownFields"] = value + } + return nil + } +} + func (g Generator) Generate(ctx *genall.GenerationContext) error { parser := &Parser{ Collector: ctx.Collector, Checker: ctx.Checker, // Perform defaulting here to avoid ambiguity later - IgnoreUnexportedFields: g.IgnoreUnexportedFields != nil && *g.IgnoreUnexportedFields == true, - AllowDangerousTypes: g.AllowDangerousTypes != nil && *g.AllowDangerousTypes == true, + IgnoreUnexportedFields: g.IgnoreUnexportedFields != nil && *g.IgnoreUnexportedFields, + AllowDangerousTypes: g.AllowDangerousTypes != nil && *g.AllowDangerousTypes, // Indicates the parser on whether to register the ObjectMeta type or not - GenerateEmbeddedObjectMeta: g.GenerateEmbeddedObjectMeta != nil && *g.GenerateEmbeddedObjectMeta == true, + GenerateEmbeddedObjectMeta: g.GenerateEmbeddedObjectMeta != nil && *g.GenerateEmbeddedObjectMeta, } AddKnownTypes(parser) @@ -128,6 +159,25 @@ func (g Generator) Generate(ctx *genall.GenerationContext) error { crdVersions = []string{defaultVersion} } + var headerText string + + if g.HeaderFile != "" { + headerBytes, err := ctx.ReadFile(g.HeaderFile) + if err != nil { + return err + } + headerText = string(headerBytes) + } + headerText = strings.ReplaceAll(headerText, " YEAR", " "+g.Year) + + yamlOpts := []*genall.WriteYAMLOptions{ + genall.WithTransform(transformRemoveCRDStatus), + genall.WithTransform(genall.TransformRemoveCreationTimestamp), + } + if g.DeprecatedV1beta1CompatibilityPreserveUnknownFields != nil { + yamlOpts = append(yamlOpts, genall.WithTransform(transformPreserveUnknownFields(*g.DeprecatedV1beta1CompatibilityPreserveUnknownFields))) + } + for _, groupKind := range kubeKinds { parser.NeedCRDFor(groupKind, g.MaxDescLen) crdRaw := parser.CustomResourceDefinitions[groupKind] @@ -153,7 +203,7 @@ func (g Generator) Generate(ctx *genall.GenerationContext) error { } else { fileName = fmt.Sprintf("%s_%s.%s.yaml", crdRaw.Spec.Group, crdRaw.Spec.Names.Plural, crdVersions[i]) } - if err := ctx.WriteYAML(fileName, []interface{}{crd}, genall.WithTransform(transformRemoveCRDStatus)); err != nil { + if err := ctx.WriteYAML(fileName, headerText, []interface{}{crd}, yamlOpts...); err != nil { return err } } @@ -176,7 +226,6 @@ func removeDescriptionFromMetadataProps(v *apiext.JSONSchemaProps) { if meta.Description != "" { meta.Description = "" v.Properties["metadata"] = m - } } } diff --git a/pkg/crd/gen_integration_test.go b/pkg/crd/gen_integration_test.go index e7ceb97e3..d59e3e923 100644 --- a/pkg/crd/gen_integration_test.go +++ b/pkg/crd/gen_integration_test.go @@ -19,7 +19,6 @@ package crd_test import ( "bytes" "io" - "io/ioutil" "os" "path/filepath" @@ -93,7 +92,7 @@ var _ = Describe("CRD Generation proper defaulting", func() { Expect(gen.Generate(ctx)).NotTo(HaveOccurred()) By("loading the desired YAML") - expectedFile, err := ioutil.ReadFile(filepath.Join(genDir, "bar.example.com_foos.yaml")) + expectedFile, err := os.ReadFile(filepath.Join(genDir, "bar.example.com_foos.yaml")) Expect(err).NotTo(HaveOccurred()) expectedFile = fixAnnotations(expectedFile) @@ -109,10 +108,10 @@ var _ = Describe("CRD Generation proper defaulting", func() { Expect(gen.Generate(ctx2)).NotTo(HaveOccurred()) By("loading the desired YAMLs") - expectedFileFoos, err := ioutil.ReadFile(filepath.Join(genDir, "bar.example.com_foos.yaml")) + expectedFileFoos, err := os.ReadFile(filepath.Join(genDir, "bar.example.com_foos.yaml")) Expect(err).NotTo(HaveOccurred()) expectedFileFoos = fixAnnotations(expectedFileFoos) - expectedFileZoos, err := ioutil.ReadFile(filepath.Join(genDir, "zoo", "bar.example.com_zooes.yaml")) + expectedFileZoos, err := os.ReadFile(filepath.Join(genDir, "zoo", "bar.example.com_zoos.yaml")) Expect(err).NotTo(HaveOccurred()) expectedFileZoos = fixAnnotations(expectedFileZoos) @@ -120,6 +119,43 @@ var _ = Describe("CRD Generation proper defaulting", func() { expectedOut := string(expectedFileFoos) + string(expectedFileZoos) Expect(out.buf.String()).To(Equal(expectedOut), cmp.Diff(out.buf.String(), expectedOut)) }) + + It("should add preserveUnknownFields=false when specified", func() { + By("calling Generate") + no := false + gen := &crd.Generator{ + CRDVersions: []string{"v1"}, + DeprecatedV1beta1CompatibilityPreserveUnknownFields: &no, + } + Expect(gen.Generate(ctx)).NotTo(HaveOccurred()) + + By("searching preserveUnknownFields") + Expect(out.buf.String()).To(ContainSubstring("preserveUnknownFields: false")) + }) + + It("should add preserveUnknownFields=true when specified", func() { + By("calling Generate") + yes := true + gen := &crd.Generator{ + CRDVersions: []string{"v1"}, + DeprecatedV1beta1CompatibilityPreserveUnknownFields: &yes, + } + Expect(gen.Generate(ctx)).NotTo(HaveOccurred()) + + By("searching preserveUnknownFields") + Expect(out.buf.String()).To(ContainSubstring("preserveUnknownFields: true")) + }) + + It("should not add preserveUnknownFields when not specified", func() { + By("calling Generate") + gen := &crd.Generator{ + CRDVersions: []string{"v1"}, + } + Expect(gen.Generate(ctx)).NotTo(HaveOccurred()) + + By("searching preserveUnknownFields") + Expect(out.buf.String()).NotTo(ContainSubstring("preserveUnknownFields")) + }) }) // fixAnnotations fixes the attribution annotation for tests. @@ -131,7 +167,7 @@ type outputRule struct { buf *bytes.Buffer } -func (o *outputRule) Open(_ *loader.Package, itemPath string) (io.WriteCloser, error) { +func (o *outputRule) Open(_ *loader.Package, _ string) (io.WriteCloser, error) { return nopCloser{o.buf}, nil } diff --git a/pkg/crd/known_types.go b/pkg/crd/known_types.go index 9e8decb28..1385f0b55 100644 --- a/pkg/crd/known_types.go +++ b/pkg/crd/known_types.go @@ -17,6 +17,7 @@ package crd import ( apiext "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" + "k8s.io/utils/ptr" "sigs.k8s.io/controller-tools/pkg/loader" ) @@ -75,7 +76,7 @@ var KnownPackages = map[string]PackageOverride{ p.Schemata[TypeIdent{Name: "RawExtension", Package: pkg}] = apiext.JSONSchemaProps{ // TODO(directxman12): regexp validation for this (or get kube to support it as a format value) Type: "object", - XPreserveUnknownFields: boolPtr(true), + XPreserveUnknownFields: ptr.To(true), } p.AddPackage(pkg) // get the rest of the types }, @@ -100,13 +101,13 @@ var KnownPackages = map[string]PackageOverride{ "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1": func(p *Parser, pkg *loader.Package) { p.Schemata[TypeIdent{Name: "JSON", Package: pkg}] = apiext.JSONSchemaProps{ - XPreserveUnknownFields: boolPtr(true), + XPreserveUnknownFields: ptr.To(true), } p.AddPackage(pkg) // get the rest of the types }, "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1": func(p *Parser, pkg *loader.Package) { p.Schemata[TypeIdent{Name: "JSON", Package: pkg}] = apiext.JSONSchemaProps{ - XPreserveUnknownFields: boolPtr(true), + XPreserveUnknownFields: ptr.To(true), } p.AddPackage(pkg) // get the rest of the types }, @@ -159,10 +160,6 @@ var ObjectMetaPackages = map[string]PackageOverride{ }, } -func boolPtr(b bool) *bool { - return &b -} - // AddKnownTypes registers the packages overrides in KnownPackages with the given parser. func AddKnownTypes(parser *Parser) { // ensure everything is there before adding to PackageOverrides diff --git a/pkg/crd/markers/crd.go b/pkg/crd/markers/crd.go index 0c637c773..1b1cf5ede 100644 --- a/pkg/crd/markers/crd.go +++ b/pkg/crd/markers/crd.go @@ -283,7 +283,7 @@ type Resource struct { Scope string `marker:",optional"` } -func (s Resource) ApplyToCRD(crd *apiext.CustomResourceDefinitionSpec, version string) error { +func (s Resource) ApplyToCRD(crd *apiext.CustomResourceDefinitionSpec, _ string) error { if s.Path != "" { crd.Names.Plural = s.Path } @@ -362,13 +362,16 @@ type Metadata struct { Labels []string `marker:",optional"` } -func (s Metadata) ApplyToCRD(crd *apiext.CustomResourceDefinition, version string) error { +func (s Metadata) ApplyToCRD(crd *apiext.CustomResourceDefinition, _ string) error { if len(s.Annotations) > 0 { if crd.Annotations == nil { crd.Annotations = map[string]string{} } for _, str := range s.Annotations { kv := strings.SplitN(str, "=", 2) + if len(kv) < 2 { + return fmt.Errorf("annotation %s is not in 'xxx=xxx' format", str) + } crd.Annotations[kv[0]] = kv[1] } } diff --git a/pkg/crd/markers/doc.go b/pkg/crd/markers/doc.go index 995af44b3..f01e9f1b3 100644 --- a/pkg/crd/markers/doc.go +++ b/pkg/crd/markers/doc.go @@ -26,7 +26,20 @@ limitations under the License. // be run after the rest of a given schema node has been generated. // Markers that need to be run before any other markers can also // implement ApplyFirst, but this is discouraged and may change -// in the future. +// in the future. It is recommended to implement the ApplyPriority +// interface in combination with ApplyPriorityDefault and +// ApplyPriorityFirst constants. Following is an example of how to +// implement such a marker: +// +// type MyCustomMarker string +// +// func (m MyCustomMarker) ApplyPriority() ApplyPriority { +// return ApplyPriorityFirst +// } +// +// func (m MyCustomMarker) ApplyToSchema(schema *apiext.JSONSchemaProps) error { +// ... +// } // // All validation markers start with "+kubebuilder:validation", and // have the same name as their type name. @@ -34,7 +47,7 @@ limitations under the License. // # CRD Markers // // Markers that modify anything in the CRD itself *except* for the schema -// implement ApplyToCRD (crd.CRDMarker). They are expected to detect whether +// implement ApplyToCRD (crd.SpecMarker). They are expected to detect whether // they should apply themselves to a specific version in the CRD (as passed to // them), or to the root-level CRD for legacy cases. They are applied *after* // the rest of the CRD is computed. diff --git a/pkg/crd/markers/package.go b/pkg/crd/markers/package.go index cebe8fa4b..86851b2c4 100644 --- a/pkg/crd/markers/package.go +++ b/pkg/crd/markers/package.go @@ -22,7 +22,7 @@ import ( func init() { AllDefinitions = append(AllDefinitions, - must(markers.MakeDefinition("groupName", markers.DescribesPackage, "")). + mustOptional(markers.MakeDefinition("groupName", markers.DescribesPackage, "")). WithHelp(markers.SimpleHelp("CRD", "specifies the API group name for this package.")), must(markers.MakeDefinition("versionName", markers.DescribesPackage, "")). diff --git a/pkg/crd/markers/priority.go b/pkg/crd/markers/priority.go new file mode 100644 index 000000000..1b4482521 --- /dev/null +++ b/pkg/crd/markers/priority.go @@ -0,0 +1,37 @@ +/* +Copyright 2022 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. +*/ + +package markers + +// ApplyPriority designates the order markers should be applied. +// Lower priority indicates it should be applied first +type ApplyPriority int64 + +const ( + // ApplyPriorityDefault is the default priority for markers + // that don't implement ApplyPriorityMarker + ApplyPriorityDefault ApplyPriority = 10 + + // ApplyPriorityFirst is the priority value assigned to markers + // that implement the ApplyFirst() method + ApplyPriorityFirst ApplyPriority = 1 +) + +// ApplyPriorityMarker designates the order validation markers should be applied. +// Lower priority indicates it should be applied first +type ApplyPriorityMarker interface { + ApplyPriority() ApplyPriority +} diff --git a/pkg/crd/markers/register.go b/pkg/crd/markers/register.go index 0e7c42694..b5a2760b0 100644 --- a/pkg/crd/markers/register.go +++ b/pkg/crd/markers/register.go @@ -17,6 +17,7 @@ limitations under the License. package markers import ( + "fmt" "reflect" "sigs.k8s.io/controller-tools/pkg/markers" @@ -42,12 +43,33 @@ func (d *definitionWithHelp) Register(reg *markers.Registry) error { return nil } +func (d *definitionWithHelp) clone() *definitionWithHelp { + newDef, newHelp := *d.Definition, *d.Help + return &definitionWithHelp{ + Definition: &newDef, + Help: &newHelp, + } +} + func must(def *markers.Definition, err error) *definitionWithHelp { return &definitionWithHelp{ Definition: markers.Must(def, err), } } +func mustOptional(def *markers.Definition, err error) *definitionWithHelp { + def = markers.Must(def, err) + if !def.AnonymousField() { + def = markers.Must(def, fmt.Errorf("not an anonymous field: %v", def)) + } + field := def.Fields[""] + field.Optional = true + def.Fields[""] = field + return &definitionWithHelp{ + Definition: def, + } +} + // AllDefinitions contains all marker definitions for this package. var AllDefinitions []*definitionWithHelp @@ -60,7 +82,7 @@ type hasHelp interface { func mustMakeAllWithPrefix(prefix string, target markers.TargetType, objs ...interface{}) []*definitionWithHelp { defs := make([]*definitionWithHelp, len(objs)) for i, obj := range objs { - name := prefix + ":" + reflect.TypeOf(obj).Name() + name := prefix + reflect.TypeOf(obj).Name() def, err := markers.MakeDefinition(name, target, obj) if err != nil { panic(err) diff --git a/pkg/crd/markers/topology.go b/pkg/crd/markers/topology.go index a92995c80..97dbc47c5 100644 --- a/pkg/crd/markers/topology.go +++ b/pkg/crd/markers/topology.go @@ -119,7 +119,9 @@ func (l ListType) ApplyToSchema(schema *apiext.JSONSchemaProps) error { return nil } -func (l ListType) ApplyFirst() {} +func (l ListType) ApplyPriority() ApplyPriority { + return ApplyPriorityDefault - 1 +} func (l ListMapKey) ApplyToSchema(schema *apiext.JSONSchemaProps) error { if schema.Type != "array" { diff --git a/pkg/crd/markers/validation.go b/pkg/crd/markers/validation.go index 5d1496189..08d28612c 100644 --- a/pkg/crd/markers/validation.go +++ b/pkg/crd/markers/validation.go @@ -20,6 +20,7 @@ import ( "encoding/json" "fmt" "math" + "strings" apiext "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" @@ -27,7 +28,10 @@ import ( ) const ( - SchemalessName = "kubebuilder:validation:Schemaless" + validationPrefix = "kubebuilder:validation:" + + SchemalessName = "kubebuilder:validation:Schemaless" + ValidationItemsPrefix = validationPrefix + "items:" ) // ValidationMarkers lists all available markers that affect CRD schema generation, @@ -35,7 +39,9 @@ const ( // All markers start with `+kubebuilder:validation:`, and continue with their type name. // A copy is produced of all markers that describes types as well, for making types // reusable and writing complex validations on slice items. -var ValidationMarkers = mustMakeAllWithPrefix("kubebuilder:validation", markers.DescribesField, +// At last a copy of all markers with the prefix `+kubebuilder:validation:items:` is +// produced for marking slice fields and types. +var ValidationMarkers = mustMakeAllWithPrefix(validationPrefix, markers.DescribesField, // numeric markers @@ -74,17 +80,24 @@ var ValidationMarkers = mustMakeAllWithPrefix("kubebuilder:validation", markers. // sense on a type, and thus aren't in ValidationMarkers). var FieldOnlyMarkers = []*definitionWithHelp{ must(markers.MakeDefinition("kubebuilder:validation:Required", markers.DescribesField, struct{}{})). - WithHelp(markers.SimpleHelp("CRD validation", "specifies that this field is required, if fields are optional by default.")), + WithHelp(markers.SimpleHelp("CRD validation", "specifies that this field is required.")), must(markers.MakeDefinition("kubebuilder:validation:Optional", markers.DescribesField, struct{}{})). - WithHelp(markers.SimpleHelp("CRD validation", "specifies that this field is optional, if fields are required by default.")), + WithHelp(markers.SimpleHelp("CRD validation", "specifies that this field is optional.")), + must(markers.MakeDefinition("required", markers.DescribesField, struct{}{})). + WithHelp(markers.SimpleHelp("CRD validation", "specifies that this field is required.")), must(markers.MakeDefinition("optional", markers.DescribesField, struct{}{})). - WithHelp(markers.SimpleHelp("CRD validation", "specifies that this field is optional, if fields are required by default.")), + WithHelp(markers.SimpleHelp("CRD validation", "specifies that this field is optional.")), must(markers.MakeDefinition("nullable", markers.DescribesField, Nullable{})). WithHelp(Nullable{}.Help()), must(markers.MakeAnyTypeDefinition("kubebuilder:default", markers.DescribesField, Default{})). WithHelp(Default{}.Help()), + must(markers.MakeDefinition("default", markers.DescribesField, KubernetesDefault{})). + WithHelp(KubernetesDefault{}.Help()), + + must(markers.MakeAnyTypeDefinition("kubebuilder:example", markers.DescribesField, Example{})). + WithHelp(Example{}.Help()), must(markers.MakeDefinition("kubebuilder:validation:EmbeddedResource", markers.DescribesField, XEmbeddedResource{})). WithHelp(XEmbeddedResource{}.Help()), @@ -107,14 +120,22 @@ func init() { AllDefinitions = append(AllDefinitions, ValidationMarkers...) for _, def := range ValidationMarkers { - newDef := *def.Definition - // copy both parts so we don't change the definition - typDef := definitionWithHelp{ - Definition: &newDef, - Help: def.Help, - } + typDef := def.clone() typDef.Target = markers.DescribesType - AllDefinitions = append(AllDefinitions, &typDef) + AllDefinitions = append(AllDefinitions, typDef) + + itemsName := ValidationItemsPrefix + strings.TrimPrefix(def.Name, validationPrefix) + + itemsFieldDef := def.clone() + itemsFieldDef.Name = itemsName + itemsFieldDef.Help.Summary = "for array items " + itemsFieldDef.Help.Summary + AllDefinitions = append(AllDefinitions, itemsFieldDef) + + itemsTypDef := def.clone() + itemsTypDef.Name = itemsName + itemsTypDef.Help.Summary = "for array items " + itemsTypDef.Help.Summary + itemsTypDef.Target = markers.DescribesType + AllDefinitions = append(AllDefinitions, itemsTypDef) } AllDefinitions = append(AllDefinitions, FieldOnlyMarkers...) @@ -170,7 +191,7 @@ type Pattern string type MaxItems int // +controllertools:marker:generateHelp:category="CRD validation" -// MinItems specifies the minimun length for this list. +// MinItems specifies the minimum length for this list. type MinItems int // +controllertools:marker:generateHelp:category="CRD validation" @@ -222,6 +243,33 @@ type Default struct { Value interface{} } +// +controllertools:marker:generateHelp:category="CRD validation" +// Default sets the default value for this field. +// +// A default value will be accepted as any value valid for the field. +// Only JSON-formatted values are accepted. `ref(...)` values are ignored. +// Formatting for common types include: boolean: `true`, string: +// `"Cluster"`, numerical: `1.24`, array: `[1,2]`, object: `{"policy": +// "delete"}`). Defaults should be defined in pruned form, and only best-effort +// validation will be performed. Full validation of a default requires +// submission of the containing CRD to an apiserver. +type KubernetesDefault struct { + Value interface{} +} + +// +controllertools:marker:generateHelp:category="CRD validation" +// Example sets the example value for this field. +// +// An example value will be accepted as any value valid for the +// field. Formatting for common types include: boolean: `true`, string: +// `Cluster`, numerical: `1.24`, array: `{1,2}`, object: `{policy: +// "delete"}`). Examples should be defined in pruned form, and only best-effort +// validation will be performed. Full validation of an example requires +// submission of the containing CRD to an apiserver. +type Example struct { + Value interface{} +} + // +controllertools:marker:generateHelp:category="CRD processing" // PreserveUnknownFields stops the apiserver from pruning fields which are not specified. // @@ -250,7 +298,7 @@ type XEmbeddedResource struct{} // IntOrString marks a fields as an IntOrString. // // This is required when applying patterns or other validations to an IntOrString -// field. Knwon information about the type is applied during the collapse phase +// field. Known information about the type is applied during the collapse phase // and as such is not normally available during marker application. type XIntOrString struct{} @@ -279,8 +327,11 @@ func isIntegral(value float64) bool { // This marker may be repeated to specify multiple expressions, all of // which must evaluate to true. type XValidation struct { - Rule string - Message string `marker:",optional"` + Rule string + Message string `marker:",optional"` + MessageExpression string `marker:"messageExpression,optional"` + Reason string `marker:"reason,optional"` + FieldPath string `marker:"fieldPath,optional"` } func (m Maximum) ApplyToSchema(schema *apiext.JSONSchemaProps) error { @@ -448,7 +499,9 @@ func (m Type) ApplyToSchema(schema *apiext.JSONSchemaProps) error { return nil } -func (m Type) ApplyFirst() {} +func (m Type) ApplyPriority() ApplyPriority { + return ApplyPriorityDefault - 1 +} func (m Nullable) ApplyToSchema(schema *apiext.JSONSchemaProps) error { schema.Nullable = true @@ -457,6 +510,37 @@ func (m Nullable) ApplyToSchema(schema *apiext.JSONSchemaProps) error { // Defaults are only valid CRDs created with the v1 API func (m Default) ApplyToSchema(schema *apiext.JSONSchemaProps) error { + marshalledDefault, err := json.Marshal(m.Value) + if err != nil { + return err + } + if schema.Type == "array" && string(marshalledDefault) == "{}" { + marshalledDefault = []byte("[]") + } + schema.Default = &apiext.JSON{Raw: marshalledDefault} + return nil +} + +func (m Default) ApplyPriority() ApplyPriority { + // explicitly go after +default markers, so kubebuilder-specific defaults get applied last and stomp + return 10 +} + +func (m *KubernetesDefault) ParseMarker(_ string, _ string, restFields string) error { + if strings.HasPrefix(strings.TrimSpace(restFields), "ref(") { + // Skip +default=ref(...) values for now, since we don't have a good way to evaluate go constant values via AST. + // See https://github.com/kubernetes-sigs/controller-tools/pull/938#issuecomment-2096790018 + return nil + } + return json.Unmarshal([]byte(restFields), &m.Value) +} + +// Defaults are only valid CRDs created with the v1 API +func (m KubernetesDefault) ApplyToSchema(schema *apiext.JSONSchemaProps) error { + if m.Value == nil { + // only apply to the schema if we have a non-nil default value + return nil + } marshalledDefault, err := json.Marshal(m.Value) if err != nil { return err @@ -465,6 +549,20 @@ func (m Default) ApplyToSchema(schema *apiext.JSONSchemaProps) error { return nil } +func (m KubernetesDefault) ApplyPriority() ApplyPriority { + // explicitly go before +kubebuilder:default markers, so kubebuilder-specific defaults get applied last and stomp + return 9 +} + +func (m Example) ApplyToSchema(schema *apiext.JSONSchemaProps) error { + marshalledExample, err := json.Marshal(m.Value) + if err != nil { + return err + } + schema.Example = &apiext.JSON{Raw: marshalledExample} + return nil +} + func (m XPreserveUnknownFields) ApplyToSchema(schema *apiext.JSONSchemaProps) error { defTrue := true schema.XPreserveUnknownFields = &defTrue @@ -484,12 +582,27 @@ func (m XIntOrString) ApplyToSchema(schema *apiext.JSONSchemaProps) error { return nil } -func (m XIntOrString) ApplyFirst() {} +func (m XIntOrString) ApplyPriority() ApplyPriority { + return ApplyPriorityDefault - 1 +} func (m XValidation) ApplyToSchema(schema *apiext.JSONSchemaProps) error { + var reason *apiext.FieldValueErrorReason + if m.Reason != "" { + switch m.Reason { + case string(apiext.FieldValueRequired), string(apiext.FieldValueInvalid), string(apiext.FieldValueForbidden), string(apiext.FieldValueDuplicate): + reason = (*apiext.FieldValueErrorReason)(&m.Reason) + default: + return fmt.Errorf("invalid reason %s, valid values are %s, %s, %s and %s", m.Reason, apiext.FieldValueRequired, apiext.FieldValueInvalid, apiext.FieldValueForbidden, apiext.FieldValueDuplicate) + } + } + schema.XValidations = append(schema.XValidations, apiext.ValidationRule{ - Rule: m.Rule, - Message: m.Message, + Rule: m.Rule, + Message: m.Message, + MessageExpression: m.MessageExpression, + Reason: reason, + FieldPath: m.FieldPath, }) return nil } diff --git a/pkg/crd/markers/zz_generated.markerhelp.go b/pkg/crd/markers/zz_generated.markerhelp.go index 4a920039f..7fb1b2164 100644 --- a/pkg/crd/markers/zz_generated.markerhelp.go +++ b/pkg/crd/markers/zz_generated.markerhelp.go @@ -1,5 +1,4 @@ //go:build !ignore_autogenerated -// +build !ignore_autogenerated /* Copyright2019 The Kubernetes Authors. @@ -29,8 +28,8 @@ func (Default) Help() *markers.DefinitionHelp { return &markers.DefinitionHelp{ Category: "CRD validation", DetailedHelp: markers.DetailedHelp{ - Summary: "sets the default value for this field. ", - Details: "A default value will be accepted as any value valid for the field. Formatting for common types include: boolean: `true`, string: `Cluster`, numerical: `1.24`, array: `{1,2}`, object: `{policy: \"delete\"}`). Defaults should be defined in pruned form, and only best-effort validation will be performed. Full validation of a default requires submission of the containing CRD to an apiserver.", + Summary: "sets the default value for this field.", + Details: "A default value will be accepted as any value valid for the\nfield. Formatting for common types include: boolean: `true`, string:\n`Cluster`, numerical: `1.24`, array: `{1,2}`, object: `{policy:\n\"delete\"}`). Defaults should be defined in pruned form, and only best-effort\nvalidation will be performed. Full validation of a default requires\nsubmission of the containing CRD to an apiserver.", }, FieldHelp: map[string]markers.DetailedHelp{ "Value": { @@ -68,6 +67,22 @@ func (Enum) Help() *markers.DefinitionHelp { } } +func (Example) Help() *markers.DefinitionHelp { + return &markers.DefinitionHelp{ + Category: "CRD validation", + DetailedHelp: markers.DetailedHelp{ + Summary: "sets the example value for this field.", + Details: "An example value will be accepted as any value valid for the\nfield. Formatting for common types include: boolean: `true`, string:\n`Cluster`, numerical: `1.24`, array: `{1,2}`, object: `{policy:\n\"delete\"}`). Examples should be defined in pruned form, and only best-effort\nvalidation will be performed. Full validation of an example requires\nsubmission of the containing CRD to an apiserver.", + }, + FieldHelp: map[string]markers.DetailedHelp{ + "Value": { + Summary: "", + Details: "", + }, + }, + } +} + func (ExclusiveMaximum) Help() *markers.DefinitionHelp { return &markers.DefinitionHelp{ Category: "CRD validation", @@ -94,19 +109,35 @@ func (Format) Help() *markers.DefinitionHelp { return &markers.DefinitionHelp{ Category: "CRD validation", DetailedHelp: markers.DetailedHelp{ - Summary: "specifies additional \"complex\" formatting for this field. ", - Details: "For example, a date-time field would be marked as \"type: string\" and \"format: date-time\".", + Summary: "specifies additional \"complex\" formatting for this field.", + Details: "For example, a date-time field would be marked as \"type: string\" and\n\"format: date-time\".", }, FieldHelp: map[string]markers.DetailedHelp{}, } } +func (KubernetesDefault) Help() *markers.DefinitionHelp { + return &markers.DefinitionHelp{ + Category: "CRD validation", + DetailedHelp: markers.DetailedHelp{ + Summary: "Default sets the default value for this field.", + Details: "A default value will be accepted as any value valid for the field.\nOnly JSON-formatted values are accepted. `ref(...)` values are ignored.\nFormatting for common types include: boolean: `true`, string:\n`\"Cluster\"`, numerical: `1.24`, array: `[1,2]`, object: `{\"policy\":\n\"delete\"}`). Defaults should be defined in pruned form, and only best-effort\nvalidation will be performed. Full validation of a default requires\nsubmission of the containing CRD to an apiserver.", + }, + FieldHelp: map[string]markers.DetailedHelp{ + "Value": { + Summary: "", + Details: "", + }, + }, + } +} + func (ListMapKey) Help() *markers.DefinitionHelp { return &markers.DefinitionHelp{ Category: "CRD processing", DetailedHelp: markers.DetailedHelp{ - Summary: "specifies the keys to map listTypes. ", - Details: "It indicates the index of a map list. They can be repeated if multiple keys must be used. It can only be used when ListType is set to map, and the keys should be scalar types.", + Summary: "specifies the keys to map listTypes.", + Details: "It indicates the index of a map list. They can be repeated if multiple keys\nmust be used. It can only be used when ListType is set to map, and the keys\nshould be scalar types.", }, FieldHelp: map[string]markers.DetailedHelp{}, } @@ -116,8 +147,8 @@ func (ListType) Help() *markers.DefinitionHelp { return &markers.DefinitionHelp{ Category: "CRD processing", DetailedHelp: markers.DetailedHelp{ - Summary: "specifies the type of data-structure that the list represents (map, set, atomic). ", - Details: "Possible data-structure types of a list are: \n - \"map\": it needs to have a key field, which will be used to build an associative list. A typical example is a the pod container list, which is indexed by the container name. \n - \"set\": Fields need to be \"scalar\", and there can be only one occurrence of each. \n - \"atomic\": All the fields in the list are treated as a single value, are typically manipulated together by the same actor.", + Summary: "specifies the type of data-structure that the list", + Details: "represents (map, set, atomic).\n\n\nPossible data-structure types of a list are:\n\n\n - \"map\": it needs to have a key field, which will be used to build an\n associative list. A typical example is a the pod container list,\n which is indexed by the container name.\n\n\n - \"set\": Fields need to be \"scalar\", and there can be only one\n occurrence of each.\n\n\n - \"atomic\": All the fields in the list are treated as a single value,\n are typically manipulated together by the same actor.", }, FieldHelp: map[string]markers.DetailedHelp{}, } @@ -127,8 +158,8 @@ func (MapType) Help() *markers.DefinitionHelp { return &markers.DefinitionHelp{ Category: "CRD processing", DetailedHelp: markers.DetailedHelp{ - Summary: "specifies the level of atomicity of the map; i.e. whether each item in the map is independent of the others, or all fields are treated as a single unit. ", - Details: "Possible values: \n - \"granular\": items in the map are independent of each other, and can be manipulated by different actors. This is the default behavior. \n - \"atomic\": all fields are treated as one unit. Any changes have to replace the entire map.", + Summary: "specifies the level of atomicity of the map;", + Details: "i.e. whether each item in the map is independent of the others,\nor all fields are treated as a single unit.\n\n\nPossible values:\n\n\n - \"granular\": items in the map are independent of each other,\n and can be manipulated by different actors.\n This is the default behavior.\n\n\n - \"atomic\": all fields are treated as one unit.\n Any changes have to replace the entire map.", }, FieldHelp: map[string]markers.DetailedHelp{}, } @@ -182,8 +213,8 @@ func (Metadata) Help() *markers.DefinitionHelp { return &markers.DefinitionHelp{ Category: "CRD", DetailedHelp: markers.DetailedHelp{ - Summary: "configures the additional annotations or labels for this CRD. For example adding annotation \"api-approved.kubernetes.io\" for a CRD with Kubernetes groups, or annotation \"cert-manager.io/inject-ca-from-secret\" for a CRD that needs CA injection.", - Details: "", + Summary: "configures the additional annotations or labels for this CRD.", + Details: "For example adding annotation \"api-approved.kubernetes.io\" for a CRD with Kubernetes groups,\nor annotation \"cert-manager.io/inject-ca-from-secret\" for a CRD that needs CA injection.", }, FieldHelp: map[string]markers.DetailedHelp{ "Annotations": { @@ -202,7 +233,7 @@ func (MinItems) Help() *markers.DefinitionHelp { return &markers.DefinitionHelp{ Category: "CRD validation", DetailedHelp: markers.DetailedHelp{ - Summary: "specifies the minimun length for this list.", + Summary: "specifies the minimum length for this list.", Details: "", }, FieldHelp: map[string]markers.DetailedHelp{}, @@ -257,7 +288,7 @@ func (Nullable) Help() *markers.DefinitionHelp { return &markers.DefinitionHelp{ Category: "CRD validation", DetailedHelp: markers.DetailedHelp{ - Summary: "marks this field as allowing the \"null\" value. ", + Summary: "marks this field as allowing the \"null\" value.", Details: "This is often not necessary, but may be helpful with custom serialization.", }, FieldHelp: map[string]markers.DetailedHelp{}, @@ -288,8 +319,8 @@ func (PrintColumn) Help() *markers.DefinitionHelp { Details: "", }, "Type": { - Summary: "indicates the type of the column. ", - Details: "It may be any OpenAPI data type listed at https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#data-types.", + Summary: "indicates the type of the column.", + Details: "It may be any OpenAPI data type listed at\nhttps://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#data-types.", }, "JSONPath": { Summary: "specifies the jsonpath expression used to extract the value of the column.", @@ -300,12 +331,12 @@ func (PrintColumn) Help() *markers.DefinitionHelp { Details: "", }, "Format": { - Summary: "specifies the format of the column. ", - Details: "It may be any OpenAPI data format corresponding to the type, listed at https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#data-types.", + Summary: "specifies the format of the column.", + Details: "It may be any OpenAPI data format corresponding to the type, listed at\nhttps://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#data-types.", }, "Priority": { - Summary: "indicates how important it is that this column be displayed. ", - Details: "Lower priority (*higher* numbered) columns will be hidden if the terminal width is too small.", + Summary: "indicates how important it is that this column be displayed.", + Details: "Lower priority (*higher* numbered) columns will be hidden if the terminal\nwidth is too small.", }, }, } @@ -320,24 +351,24 @@ func (Resource) Help() *markers.DefinitionHelp { }, FieldHelp: map[string]markers.DetailedHelp{ "Path": { - Summary: "specifies the plural \"resource\" for this CRD. ", - Details: "It generally corresponds to a plural, lower-cased version of the Kind. See https://book.kubebuilder.io/cronjob-tutorial/gvks.html.", + Summary: "specifies the plural \"resource\" for this CRD.", + Details: "It generally corresponds to a plural, lower-cased version of the Kind.\nSee https://book.kubebuilder.io/cronjob-tutorial/gvks.html.", }, "ShortName": { - Summary: "specifies aliases for this CRD. ", - Details: "Short names are often used when people have work with your resource over and over again. For instance, \"rs\" for \"replicaset\" or \"crd\" for customresourcedefinition.", + Summary: "specifies aliases for this CRD.", + Details: "Short names are often used when people have work with your resource\nover and over again. For instance, \"rs\" for \"replicaset\" or\n\"crd\" for customresourcedefinition.", }, "Categories": { - Summary: "specifies which group aliases this resource is part of. ", - Details: "Group aliases are used to work with groups of resources at once. The most common one is \"all\" which covers about a third of the base resources in Kubernetes, and is generally used for \"user-facing\" resources.", + Summary: "specifies which group aliases this resource is part of.", + Details: "Group aliases are used to work with groups of resources at once.\nThe most common one is \"all\" which covers about a third of the base\nresources in Kubernetes, and is generally used for \"user-facing\" resources.", }, "Singular": { - Summary: "overrides the singular form of your resource. ", + Summary: "overrides the singular form of your resource.", Details: "The singular form is otherwise defaulted off the plural (path).", }, "Scope": { - Summary: "overrides the scope of the CRD (Cluster vs Namespaced). ", - Details: "Scope defaults to \"Namespaced\". Cluster-scoped (\"Cluster\") resources don't exist in namespaces.", + Summary: "overrides the scope of the CRD (Cluster vs Namespaced).", + Details: "Scope defaults to \"Namespaced\". Cluster-scoped (\"Cluster\") resources\ndon't exist in namespaces.", }, }, } @@ -347,8 +378,8 @@ func (Schemaless) Help() *markers.DefinitionHelp { return &markers.DefinitionHelp{ Category: "CRD validation", DetailedHelp: markers.DetailedHelp{ - Summary: "marks a field as being a schemaless object. ", - Details: "Schemaless objects are not introspected, so you must provide any type and validation information yourself. One use for this tag is for embedding fields that hold JSONSchema typed objects. Because this field disables all type checking, it is recommended to be used only as a last resort.", + Summary: "marks a field as being a schemaless object.", + Details: "Schemaless objects are not introspected, so you must provide\nany type and validation information yourself. One use for this\ntag is for embedding fields that hold JSONSchema typed objects.\nBecause this field disables all type checking, it is recommended\nto be used only as a last resort.", }, FieldHelp: map[string]markers.DetailedHelp{}, } @@ -358,8 +389,8 @@ func (SkipVersion) Help() *markers.DefinitionHelp { return &markers.DefinitionHelp{ Category: "CRD", DetailedHelp: markers.DetailedHelp{ - Summary: "removes the particular version of the CRD from the CRDs spec. ", - Details: "This is useful if you need to skip generating and listing version entries for 'internal' resource versions, which typically exist if using the Kubernetes upstream conversion-gen tool.", + Summary: "removes the particular version of the CRD from the CRDs spec.", + Details: "This is useful if you need to skip generating and listing version entries\nfor 'internal' resource versions, which typically exist if using the\nKubernetes upstream conversion-gen tool.", }, FieldHelp: map[string]markers.DetailedHelp{}, } @@ -369,8 +400,8 @@ func (StorageVersion) Help() *markers.DefinitionHelp { return &markers.DefinitionHelp{ Category: "CRD", DetailedHelp: markers.DetailedHelp{ - Summary: "marks this version as the \"storage version\" for the CRD for conversion. ", - Details: "When conversion is enabled for a CRD (i.e. it's not a trivial-versions/single-version CRD), one version is set as the \"storage version\" to be stored in etcd. Attempting to store any other version will result in conversion to the storage version via a conversion webhook.", + Summary: "marks this version as the \"storage version\" for the CRD for conversion.", + Details: "When conversion is enabled for a CRD (i.e. it's not a trivial-versions/single-version CRD),\none version is set as the \"storage version\" to be stored in etcd. Attempting to store any\nother version will result in conversion to the storage version via a conversion webhook.", }, FieldHelp: map[string]markers.DetailedHelp{}, } @@ -380,8 +411,8 @@ func (StructType) Help() *markers.DefinitionHelp { return &markers.DefinitionHelp{ Category: "CRD processing", DetailedHelp: markers.DetailedHelp{ - Summary: "specifies the level of atomicity of the struct; i.e. whether each field in the struct is independent of the others, or all fields are treated as a single unit. ", - Details: "Possible values: \n - \"granular\": fields in the struct are independent of each other, and can be manipulated by different actors. This is the default behavior. \n - \"atomic\": all fields are treated as one unit. Any changes have to replace the entire struct.", + Summary: "specifies the level of atomicity of the struct;", + Details: "i.e. whether each field in the struct is independent of the others,\nor all fields are treated as a single unit.\n\n\nPossible values:\n\n\n - \"granular\": fields in the struct are independent of each other,\n and can be manipulated by different actors.\n This is the default behavior.\n\n\n - \"atomic\": all fields are treated as one unit.\n Any changes have to replace the entire struct.", }, FieldHelp: map[string]markers.DetailedHelp{}, } @@ -404,8 +435,8 @@ func (SubresourceScale) Help() *markers.DefinitionHelp { Details: "", }, "SelectorPath": { - Summary: "specifies the jsonpath to the pod label selector field for the scale's status. ", - Details: "The selector field must be the *string* form (serialized form) of a selector. Setting a pod label selector is necessary for your type to work with the HorizontalPodAutoscaler.", + Summary: "specifies the jsonpath to the pod label selector field for the scale's status.", + Details: "The selector field must be the *string* form (serialized form) of a selector.\nSetting a pod label selector is necessary for your type to work with the HorizontalPodAutoscaler.", }, }, } @@ -426,8 +457,8 @@ func (Type) Help() *markers.DefinitionHelp { return &markers.DefinitionHelp{ Category: "CRD validation", DetailedHelp: markers.DetailedHelp{ - Summary: "overrides the type for this field (which defaults to the equivalent of the Go type). ", - Details: "This generally must be paired with custom serialization. For example, the metav1.Time field would be marked as \"type: string\" and \"format: date-time\".", + Summary: "overrides the type for this field (which defaults to the equivalent of the Go type).", + Details: "This generally must be paired with custom serialization. For example, the\nmetav1.Time field would be marked as \"type: string\" and \"format: date-time\".", }, FieldHelp: map[string]markers.DetailedHelp{}, } @@ -448,7 +479,7 @@ func (UnservedVersion) Help() *markers.DefinitionHelp { return &markers.DefinitionHelp{ Category: "CRD", DetailedHelp: markers.DetailedHelp{ - Summary: "does not serve this version. ", + Summary: "does not serve this version.", Details: "This is useful if you need to drop support for a version in favor of a newer version.", }, FieldHelp: map[string]markers.DetailedHelp{}, @@ -459,8 +490,8 @@ func (XEmbeddedResource) Help() *markers.DefinitionHelp { return &markers.DefinitionHelp{ Category: "CRD validation", DetailedHelp: markers.DetailedHelp{ - Summary: "EmbeddedResource marks a fields as an embedded resource with apiVersion, kind and metadata fields. ", - Details: "An embedded resource is a value that has apiVersion, kind and metadata fields. They are validated implicitly according to the semantics of the currently running apiserver. It is not necessary to add any additional schema for these field, yet it is possible. This can be combined with PreserveUnknownFields.", + Summary: "EmbeddedResource marks a fields as an embedded resource with apiVersion, kind and metadata fields.", + Details: "An embedded resource is a value that has apiVersion, kind and metadata fields.\nThey are validated implicitly according to the semantics of the currently\nrunning apiserver. It is not necessary to add any additional schema for these\nfield, yet it is possible. This can be combined with PreserveUnknownFields.", }, FieldHelp: map[string]markers.DetailedHelp{}, } @@ -470,8 +501,8 @@ func (XIntOrString) Help() *markers.DefinitionHelp { return &markers.DefinitionHelp{ Category: "CRD validation", DetailedHelp: markers.DetailedHelp{ - Summary: "IntOrString marks a fields as an IntOrString. ", - Details: "This is required when applying patterns or other validations to an IntOrString field. Knwon information about the type is applied during the collapse phase and as such is not normally available during marker application.", + Summary: "IntOrString marks a fields as an IntOrString.", + Details: "This is required when applying patterns or other validations to an IntOrString\nfield. Knwon information about the type is applied during the collapse phase\nand as such is not normally available during marker application.", }, FieldHelp: map[string]markers.DetailedHelp{}, } @@ -481,8 +512,8 @@ func (XPreserveUnknownFields) Help() *markers.DefinitionHelp { return &markers.DefinitionHelp{ Category: "CRD processing", DetailedHelp: markers.DetailedHelp{ - Summary: "PreserveUnknownFields stops the apiserver from pruning fields which are not specified. ", - Details: "By default the apiserver drops unknown fields from the request payload during the decoding step. This marker stops the API server from doing so. It affects fields recursively, but switches back to normal pruning behaviour if nested properties or additionalProperties are specified in the schema. This can either be true or undefined. False is forbidden. \n NB: The kubebuilder:validation:XPreserveUnknownFields variant is deprecated in favor of the kubebuilder:pruning:PreserveUnknownFields variant. They function identically.", + Summary: "PreserveUnknownFields stops the apiserver from pruning fields which are not specified.", + Details: "By default the apiserver drops unknown fields from the request payload\nduring the decoding step. This marker stops the API server from doing so.\nIt affects fields recursively, but switches back to normal pruning behaviour\nif nested properties or additionalProperties are specified in the schema.\nThis can either be true or undefined. False\nis forbidden.\n\n\nNB: The kubebuilder:validation:XPreserveUnknownFields variant is deprecated\nin favor of the kubebuilder:pruning:PreserveUnknownFields variant. They function\nidentically.", }, FieldHelp: map[string]markers.DetailedHelp{}, } @@ -492,8 +523,8 @@ func (XValidation) Help() *markers.DefinitionHelp { return &markers.DefinitionHelp{ Category: "CRD validation", DetailedHelp: markers.DetailedHelp{ - Summary: "marks a field as requiring a value for which a given expression evaluates to true. ", - Details: "This marker may be repeated to specify multiple expressions, all of which must evaluate to true.", + Summary: "marks a field as requiring a value for which a given", + Details: "expression evaluates to true.\n\n\nThis marker may be repeated to specify multiple expressions, all of\nwhich must evaluate to true.", }, FieldHelp: map[string]markers.DetailedHelp{ "Rule": { @@ -504,6 +535,18 @@ func (XValidation) Help() *markers.DefinitionHelp { Summary: "", Details: "", }, + "MessageExpression": { + Summary: "", + Details: "", + }, + "Reason": { + Summary: "", + Details: "", + }, + "FieldPath": { + Summary: "", + Details: "", + }, }, } } diff --git a/pkg/crd/parser_integration_test.go b/pkg/crd/parser_integration_test.go index 772e21da7..7e020d07a 100644 --- a/pkg/crd/parser_integration_test.go +++ b/pkg/crd/parser_integration_test.go @@ -18,7 +18,6 @@ package crd_test import ( "fmt" - "io/ioutil" "os" "github.com/google/go-cmp/cmp" @@ -101,9 +100,9 @@ var _ = Describe("CRD Generation From Parsing to CustomResourceDefinition", func } }) - assertCRD := func(pkg *loader.Package, kind, fileName string) { - By(fmt.Sprintf("requesting that the %s CRD be generated", kind)) - groupKind := schema.GroupKind{Kind: kind, Group: "testdata.kubebuilder.io"} + assertCRDForGroupKind := func(pkg *loader.Package, groupKind schema.GroupKind, fileName string) { + kind := groupKind.Kind + By(fmt.Sprintf("requesting that the %s CRD be generated in group %s", kind, groupKind.Group)) parser.NeedCRDFor(groupKind, nil) By(fmt.Sprintf("fixing top level ObjectMeta on the %s CRD", kind)) @@ -116,7 +115,7 @@ var _ = Describe("CRD Generation From Parsing to CustomResourceDefinition", func ExpectWithOffset(1, parser.CustomResourceDefinitions).To(HaveKey(groupKind)) By(fmt.Sprintf("loading the desired %s YAML", kind)) - expectedFile, err := ioutil.ReadFile(fileName) + expectedFile, err := os.ReadFile(fileName) ExpectWithOffset(1, err).NotTo(HaveOccurred()) By(fmt.Sprintf("parsing the desired %s YAML", kind)) @@ -132,6 +131,22 @@ var _ = Describe("CRD Generation From Parsing to CustomResourceDefinition", func ExpectWithOffset(1, parser.CustomResourceDefinitions[groupKind]).To(Equal(crd), "type not as expected, check pkg/crd/testdata/README.md for more details.\n\nDiff:\n\n%s", cmp.Diff(parser.CustomResourceDefinitions[groupKind], crd)) } + assertCRD := func(pkg *loader.Package, kind, fileName string) { + assertCRDForGroupKind(pkg, schema.GroupKind{Group: "testdata.kubebuilder.io", Kind: kind}, fileName) + } + + assertError := func(pkg *loader.Package, kind, errorMsg string) { + By(fmt.Sprintf("requesting that the %s CRD be generated", kind)) + groupKind := schema.GroupKind{Kind: kind, Group: "testdata.kubebuilder.io"} + parser.NeedCRDFor(groupKind, nil) + + By(fmt.Sprintf("fixing top level ObjectMeta on the %s CRD", kind)) + crd.FixTopLevelMetadata(parser.CustomResourceDefinitions[groupKind]) + + By("checking that specific errors occurred along the way") + Expect(packageErrors(pkg)).To(MatchError(ContainSubstring(errorMsg))) + } + Context("CronJob API", func() { BeforeEach(func() { pkgPaths = []string{"./", "./unserved", "./deprecated"} @@ -162,6 +177,26 @@ var _ = Describe("CRD Generation From Parsing to CustomResourceDefinition", func assertCRD(pkgs[3], "Job", "testdata.kubebuilder.io_jobs.yaml") }) }) + + Context("CronJob API with Wrong Annotation Format", func() { + BeforeEach(func() { + pkgPaths = []string{"./wrong_annotation_format"} + expPkgLen = 1 + }) + It("can not successfully generate the CronJob CRD", func() { + assertError(pkgs[0], "CronJob", "is not in 'xxx=xxx' format") + }) + }) + + Context("CronJob API without group", func() { + BeforeEach(func() { + pkgPaths = []string{"./nogroup"} + expPkgLen = 1 + }) + It("should successfully generate the CronJob CRD", func() { + assertCRDForGroupKind(pkgs[0], schema.GroupKind{Kind: "CronJob"}, "testdata._cronjobs.yaml") + }) + }) }) It("should generate plural words for Kind correctly", func() { @@ -197,7 +232,7 @@ var _ = Describe("CRD Generation From Parsing to CustomResourceDefinition", func crd.FixTopLevelMetadata(parser.CustomResourceDefinitions[groupKind]) By("loading the desired YAML") - expectedFile, err := ioutil.ReadFile("plural.example.com_testquotas.yaml") + expectedFile, err := os.ReadFile("plural.example.com_testquotas.yaml") Expect(err).NotTo(HaveOccurred()) By("parsing the desired YAML") @@ -244,4 +279,52 @@ var _ = Describe("CRD Generation From Parsing to CustomResourceDefinition", func By("checking that no errors occurred along the way (expect for type errors)") Expect(packageErrors(cronJobPkg, packages.TypeError)).NotTo(HaveOccurred()) }) + + It("should generate markers properly among several package versions", func() { + By("switching into testdata to appease go modules") + cwd, err := os.Getwd() + Expect(err).NotTo(HaveOccurred()) + Expect(os.Chdir("./testdata/multiple_versions")).To(Succeed()) + defer func() { Expect(os.Chdir(cwd)).To(Succeed()) }() + + By("loading the roots") + pkgs, err := loader.LoadRoots("./v1beta1", "./v1beta2") + Expect(err).NotTo(HaveOccurred()) + Expect(pkgs).To(HaveLen(2)) + + By("setting up the parser") + reg := &markers.Registry{} + Expect(crdmarkers.Register(reg)).To(Succeed()) + parser := &crd.Parser{ + Collector: &markers.Collector{Registry: reg}, + Checker: &loader.TypeChecker{}, + } + crd.AddKnownTypes(parser) + + By("requesting that the package be parsed") + for _, pkg := range pkgs { + parser.NeedPackage(pkg) + } + + By("requesting that the CRD be generated") + groupKind := schema.GroupKind{Kind: "VersionedResource", Group: "testdata.kubebuilder.io"} + parser.NeedCRDFor(groupKind, nil) + + By("fixing top level ObjectMeta on the CRD") + crd.FixTopLevelMetadata(parser.CustomResourceDefinitions[groupKind]) + + By("loading the desired YAML") + expectedFile, err := os.ReadFile("testdata.kubebuilder.io_versionedresources.yaml") + Expect(err).NotTo(HaveOccurred()) + + By("parsing the desired YAML") + var crd apiext.CustomResourceDefinition + Expect(yaml.Unmarshal(expectedFile, &crd)).To(Succeed()) + // clear the annotations -- we don't care about the attribution annotation + crd.Annotations = nil + + By("comparing the two") + Expect(parser.CustomResourceDefinitions[groupKind]).To(Equal(crd), "type not as expected, check pkg/crd/testdata/README.md for more details.\n\nDiff:\n\n%s", cmp.Diff(parser.CustomResourceDefinitions[groupKind], crd)) + }) + }) diff --git a/pkg/crd/schema.go b/pkg/crd/schema.go index 769752c0f..ab5cb6add 100644 --- a/pkg/crd/schema.go +++ b/pkg/crd/schema.go @@ -22,6 +22,7 @@ import ( "go/ast" "go/token" "go/types" + "sort" "strings" apiext "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" @@ -124,39 +125,64 @@ func infoToSchema(ctx *schemaContext) *apiext.JSONSchemaProps { return typeToSchema(ctx, ctx.info.RawSpec.Type) } -// applyMarkers applies schema markers to the given schema, respecting "apply first" markers. +// applyMarkers applies schema markers given their priority to the given schema func applyMarkers(ctx *schemaContext, markerSet markers.MarkerValues, props *apiext.JSONSchemaProps, node ast.Node) { - // apply "apply first" markers first... - for _, markerValues := range markerSet { + markers := make([]SchemaMarker, 0, len(markerSet)) + itemsMarkers := make([]SchemaMarker, 0, len(markerSet)) + itemsMarkerNames := make(map[SchemaMarker]string) + + for markerName, markerValues := range markerSet { for _, markerValue := range markerValues { - if _, isApplyFirst := markerValue.(applyFirstMarker); !isApplyFirst { - continue + if schemaMarker, isSchemaMarker := markerValue.(SchemaMarker); isSchemaMarker { + if strings.HasPrefix(markerName, crdmarkers.ValidationItemsPrefix) { + itemsMarkers = append(itemsMarkers, schemaMarker) + itemsMarkerNames[schemaMarker] = markerName + } else { + markers = append(markers, schemaMarker) + } } + } + } - schemaMarker, isSchemaMarker := markerValue.(SchemaMarker) - if !isSchemaMarker { - continue - } + cmpPriority := func(markers []SchemaMarker, i, j int) bool { + var iPriority, jPriority crdmarkers.ApplyPriority - if err := schemaMarker.ApplyToSchema(props); err != nil { - ctx.pkg.AddError(loader.ErrFromNode(err /* an okay guess */, node)) - } + switch m := markers[i].(type) { + case crdmarkers.ApplyPriorityMarker: + iPriority = m.ApplyPriority() + case applyFirstMarker: + iPriority = crdmarkers.ApplyPriorityFirst + default: + iPriority = crdmarkers.ApplyPriorityDefault + } + + switch m := markers[j].(type) { + case crdmarkers.ApplyPriorityMarker: + jPriority = m.ApplyPriority() + case applyFirstMarker: + jPriority = crdmarkers.ApplyPriorityFirst + default: + jPriority = crdmarkers.ApplyPriorityDefault } + + return iPriority < jPriority } + sort.Slice(markers, func(i, j int) bool { return cmpPriority(markers, i, j) }) + sort.Slice(itemsMarkers, func(i, j int) bool { return cmpPriority(itemsMarkers, i, j) }) - // ...then the rest of the markers - for _, markerValues := range markerSet { - for _, markerValue := range markerValues { - if _, isApplyFirst := markerValue.(applyFirstMarker); isApplyFirst { - // skip apply-first markers, which were already applied - continue - } + for _, schemaMarker := range markers { + if err := schemaMarker.ApplyToSchema(props); err != nil { + ctx.pkg.AddError(loader.ErrFromNode(err /* an okay guess */, node)) + } + } - schemaMarker, isSchemaMarker := markerValue.(SchemaMarker) - if !isSchemaMarker { - continue - } - if err := schemaMarker.ApplyToSchema(props); err != nil { + for _, schemaMarker := range itemsMarkers { + if props.Type != "array" || props.Items == nil || props.Items.Schema == nil { + err := fmt.Errorf("must apply %s to an array value, found %s", itemsMarkerNames[schemaMarker], props.Type) + ctx.pkg.AddError(loader.ErrFromNode(err, node)) + } else { + itemsSchema := props.Items.Schema + if err := schemaMarker.ApplyToSchema(itemsSchema); err != nil { ctx.pkg.AddError(loader.ErrFromNode(err /* an okay guess */, node)) } } @@ -382,20 +408,28 @@ func structToSchema(ctx *schemaContext, structType *ast.StructType) *apiext.JSON defaultMode = "optional" } - switch defaultMode { + switch { + case field.Markers.Get("kubebuilder:validation:Optional") != nil: + // explicity optional - kubebuilder + case field.Markers.Get("kubebuilder:validation:Required") != nil: + // explicitly required - kubebuilder + props.Required = append(props.Required, fieldName) + case field.Markers.Get("optional") != nil: + // explicity optional - kubernetes + case field.Markers.Get("required") != nil: + // explicitly required - kubernetes + props.Required = append(props.Required, fieldName) + // if this package isn't set to optional default... - case "required": - // ...everything that's not inline, omitempty, or explicitly optional is required - if !inline && !omitEmpty && field.Markers.Get("kubebuilder:validation:Optional") == nil && field.Markers.Get("optional") == nil { + case defaultMode == "required": + // ...everything that's not inline / omitempty is required + if !inline && !omitEmpty { props.Required = append(props.Required, fieldName) } // if this package isn't set to required default... - case "optional": - // ...everything that isn't explicitly required is optional - if field.Markers.Get("kubebuilder:validation:Required") != nil { - props.Required = append(props.Required, fieldName) - } + case defaultMode == "optional": + // implicitly optional } var propSchema *apiext.JSONSchemaProps @@ -457,7 +491,7 @@ func builtinToType(basic *types.Basic, allowDangerousTypes bool) (typ string, fo // Open coded go/types representation of encoding/json.Marshaller var jsonMarshaler = types.NewInterfaceType([]*types.Func{ types.NewFunc(token.NoPos, nil, "MarshalJSON", - types.NewSignature(nil, nil, + types.NewSignatureType(nil, nil, nil, nil, types.NewTuple( types.NewVar(token.NoPos, nil, "", types.NewSlice(types.Universe.Lookup("byte").Type())), types.NewVar(token.NoPos, nil, "", types.Universe.Lookup("error").Type())), false)), diff --git a/pkg/crd/schema_test.go b/pkg/crd/schema_test.go index 5b8fa03fc..9c0581d6f 100644 --- a/pkg/crd/schema_test.go +++ b/pkg/crd/schema_test.go @@ -25,6 +25,7 @@ import ( "golang.org/x/tools/go/packages" pkgstest "golang.org/x/tools/go/packages/packagestest" apiext "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" + crdmarkers "sigs.k8s.io/controller-tools/pkg/crd/markers" testloader "sigs.k8s.io/controller-tools/pkg/loader/testutils" "sigs.k8s.io/controller-tools/pkg/markers" ) @@ -110,3 +111,68 @@ func Test_Schema_MapOfStringToArrayOfFloat32(t *testing.T) { }, })) } + +func Test_Schema_ApplyMarkers(t *testing.T) { + g := gomega.NewWithT(t) + + props := &apiext.JSONSchemaProps{} + ctx := &schemaContext{} + + var invocations []string + + applyMarkers(ctx, markers.MarkerValues{ + "blah": []interface{}{ + &testPriorityMarker{ + priority: 0, callback: func() { + invocations = append(invocations, "0") + }, + }, + &testPriorityMarker{priority: 2, callback: func() { + invocations = append(invocations, "2") + }}, + &testPriorityMarker{priority: 11, callback: func() { + invocations = append(invocations, "11") + }}, + &defaultPriorityMarker{callback: func() { + invocations = append(invocations, "default") + }}, + &testapplyFirstMarker{callback: func() { + invocations = append(invocations, "applyFirst") + }}, + }}, props, nil) + + g.Expect(invocations).To(gomega.Equal([]string{"0", "applyFirst", "2", "default", "11"})) +} + +type defaultPriorityMarker struct { + callback func() +} + +func (m *defaultPriorityMarker) ApplyToSchema(*apiext.JSONSchemaProps) error { + m.callback() + return nil +} + +type testPriorityMarker struct { + priority crdmarkers.ApplyPriority + callback func() +} + +func (m *testPriorityMarker) ApplyPriority() crdmarkers.ApplyPriority { + return m.priority +} + +func (m *testPriorityMarker) ApplyToSchema(*apiext.JSONSchemaProps) error { + m.callback() + return nil +} + +type testapplyFirstMarker struct { + callback func() +} + +func (m *testapplyFirstMarker) ApplyFirst() {} +func (m *testapplyFirstMarker) ApplyToSchema(*apiext.JSONSchemaProps) error { + m.callback() + return nil +} diff --git a/pkg/crd/testdata/cronjob_types.go b/pkg/crd/testdata/cronjob_types.go index 279b81157..50cd689b6 100644 --- a/pkg/crd/testdata/cronjob_types.go +++ b/pkg/crd/testdata/cronjob_types.go @@ -38,7 +38,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. +const DefaultRefValue = "defaultRefValue" + // CronJobSpec defines the desired state of CronJob +// +kubebuilder:validation:XValidation:rule="has(oldSelf.forbiddenInt) || !has(self.forbiddenInt)",message="forbiddenInt is not allowed",fieldPath=".forbiddenInt",reason="FieldValueForbidden" type CronJobSpec struct { // The schedule in Cron format, see https://en.wikipedia.org/wiki/Cron. Schedule string `json:"schedule"` @@ -107,16 +110,64 @@ type CronJobSpec struct { // This tests that primitive defaulting can be performed. // +kubebuilder:default=forty-two + // +kubebuilder:example=forty-two DefaultedString string `json:"defaultedString"` // This tests that slice defaulting can be performed. // +kubebuilder:default={a,b} + // +kubebuilder:example={a,b} DefaultedSlice []string `json:"defaultedSlice"` - // This tests that object defaulting can be performed. - // +kubebuilder:default={{nested: {foo: "baz", bar: true}},{nested: {bar: false}}} + // This tests that slice and object defaulting can be performed. + // +kubebuilder:default={{nested: {foo: "baz", bar: true}},{nested: {foo: "qux", bar: false}}} + // +kubebuilder:example={{nested: {foo: "baz", bar: true}},{nested: {foo: "qux", bar: false}}} DefaultedObject []RootObject `json:"defaultedObject"` + // This tests that empty slice defaulting can be performed. + // +kubebuilder:default={} + DefaultedEmptySlice []string `json:"defaultedEmptySlice"` + + // This tests that an empty object defaulting can be performed on a map. + // +kubebuilder:default={} + DefaultedEmptyMap map[string]string `json:"defaultedEmptyMap"` + + // This tests that an empty object defaulting can be performed on an object. + // +kubebuilder:default={} + DefaultedEmptyObject EmpiableObject `json:"defaultedEmptyObject"` + + // This tests that kubebuilder defaulting takes precedence. + // +kubebuilder:default="kubebuilder-default" + // +default="kubernetes-default" + DoubleDefaultedString string `json:"doubleDefaultedString"` + + // This tests that primitive defaulting can be performed. + // +default="forty-two" + KubernetesDefaultedString string `json:"kubernetesDefaultedString"` + + // This tests that slice defaulting can be performed. + // +default=["a","b"] + KubernetesDefaultedSlice []string `json:"kubernetesDefaultedSlice"` + + // This tests that slice and object defaulting can be performed. + // +default=[{"nested": {"foo": "baz", "bar": true}},{"nested": {"foo": "qux", "bar": false}}] + KubernetesDefaultedObject []RootObject `json:"kubernetesDefaultedObject"` + + // This tests that empty slice defaulting can be performed. + // +default=[] + KubernetesDefaultedEmptySlice []string `json:"kubernetesDefaultedEmptySlice"` + + // This tests that an empty object defaulting can be performed on a map. + // +default={} + KubernetesDefaultedEmptyMap map[string]string `json:"kubernetesDefaultedEmptyMap"` + + // This tests that an empty object defaulting can be performed on an object. + // +default={} + KubernetesDefaultedEmptyObject EmpiableObject `json:"kubernetesDefaultedEmptyObject"` + + // This tests that use of +default=ref(...) doesn't break generation + // +default=ref(DefaultRefValue) + KubernetesDefaultedRef string `json:"kubernetesDefaultedRef,omitempty"` + // This tests that pattern validator is properly applied. // +kubebuilder:validation:Pattern=`^$|^((https):\/\/?)[^\s()<>]+(?:\([\w\d]+\)|([^[:punct:]\s]|\/?))$` PatternObject string `json:"patternObject"` @@ -162,13 +213,33 @@ type CronJobSpec struct { StructWithSeveralFields NestedObject `json:"structWithSeveralFields"` // A struct that can only be entirely replaced via a nested type. - // +structType=atomic NestedStructWithSeveralFields NestedStructWithSeveralFields `json:"nestedStructWithSeveralFields"` + // A struct that can only be entirely replaced via a nested type and + // field markers. + // +structType=atomic + NestedStructWithSeveralFieldsDoubleMarked NestedStructWithSeveralFields `json:"nestedStructWithSeveralFieldsDoubleMarked"` + // This tests that type references are properly flattened // +kubebuilder:validation:optional JustNestedObject *JustNestedObject `json:"justNestedObject,omitempty"` + // This tests explicitly optional kubebuilder fields + // +kubebuilder:validation:Optional + ExplicitlyOptionalKubebuilder string `json:"explicitlyOptionalKubebuilder"` + + // This tests explicitly optional kubernetes fields + // +optional + ExplicitlyOptionalKubernetes string `json:"explicitlyOptionalKubernetes"` + + // This tests explicitly required kubebuilder fields + // +kubebuilder:validation:Required + ExplicitlyRequiredKubebuilder string `json:"explicitlyRequiredKubebuilder,omitempty"` + + // This tests explicitly required kubernetes fields + // +required + ExplicitlyRequiredKubernetes string `json:"explicitlyRequiredKubernetes,omitempty"` + // This tests that min/max properties work MinMaxProperties MinMaxObject `json:"minMaxProperties,omitempty"` @@ -178,7 +249,7 @@ type CronJobSpec struct { // This tests that an IntOrString can also have a pattern attached // to it. - // This can be useful if you want to limit the string to a perecentage or integer. + // This can be useful if you want to limit the string to a percentage or integer. // The XIntOrString marker is a requirement for having a pattern on this type. // +kubebuilder:validation:XIntOrString // +kubebuilder:validation:Pattern="^((100|[0-9]{1,2})%|[0-9]+)$" @@ -228,11 +299,45 @@ type CronJobSpec struct { // +kubebuilder:validation:XValidation:rule="true" StringWithEvenLength string `json:"stringWithEvenLength,omitempty"` + // Test of the expression-based validation with messageExpression marker. + // +kubebuilder:validation:XValidation:rule="self.size() % 2 == 0",messageExpression="'Length has to be even but is ' + len(self.stringWithEvenLengthAndMessageExpression) + ' instead'" + StringWithEvenLengthAndMessageExpression string `json:"stringWithEvenLengthAndMessageExpression,omitempty"` + + // Test that we can add a forbidden field using XValidation Reason and FieldPath. + // The validation is applied to the spec struct itself and not the field. + ForbiddenInt int `json:"forbiddenInt,omitempty"` + // Checks that fixed-length arrays work Array [3]int `json:"array,omitempty"` // Checks that arrays work when the type contains a composite literal ArrayUsingCompositeLiteral [len(struct{ X [3]int }{}.X)]string `json:"arrayUsingCompositeLiteral,omitempty"` + + // This tests string slice item validation. + // +kubebuilder:validation:MinItems=1 + // +kubebuilder:validation:items:MinLength=1 + // +kubebuilder:validation:items:MaxLength=255 + // +kubebuilder:validation:items:Pattern=^[a-z0-9]([-a-z0-9]*[a-z0-9])?([.][a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + // +listType=set + Hosts []string `json:"hosts,omitempty"` + + HostsAlias Hosts `json:"hostsAlias,omitempty"` + + // This tests string slice validation. + // +kubebuilder:validation:MinItems=2 + // +kubebuilder:validation:MaxItems=2 + StringPair []string `json:"stringPair"` + + // This tests string alias slice item validation. + // +kubebuilder:validation:MinItems=3 + LongerStringArray []LongerString `json:"longerStringArray,omitempty"` + + // This tests that a slice of IntOrString can also have a pattern attached to it. + // This can be useful if you want to limit the string to a percentage or integer. + // The XIntOrString marker is a requirement for having a pattern on this type. + // +kubebuilder:validation:items:XIntOrString + // +kubebuilder:validation:items:Pattern="^((100|[0-9]{1,2})%|[0-9]+)$" + IntOrStringArrayWithAPattern []*intstr.IntOrString `json:"intOrStringArrayWithAPattern,omitempty"` } type ContainsNestedMap struct { @@ -290,6 +395,12 @@ type MinMaxObject struct { Baz string `json:"baz,omitempty"` } +type EmpiableObject struct { + // +kubebuilder:default=forty-two + Foo string `json:"foo,omitempty"` + Bar string `json:"bar,omitempty"` +} + type unexportedStruct struct { // This tests that exported fields are not skipped in the schema generation Foo string `json:"foo"` @@ -334,6 +445,14 @@ type LongerString string // TotallyABool is a bool that serializes as a string. type TotallyABool bool +// This tests string slice item validation. +// +kubebuilder:validation:MinItems=1 +// +kubebuilder:validation:items:MinLength=1 +// +kubebuilder:validation:items:MaxLength=255 +// +kubebuilder:validation:items:Pattern=^[a-z0-9]([-a-z0-9]*[a-z0-9])?([.][a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ +// +listType=set +type Hosts []string + func (t TotallyABool) MarshalJSON() ([]byte, error) { if t { return []byte(`"true"`), nil diff --git a/pkg/crd/testdata/gen/bar.example.com_foos.v1beta1.yaml b/pkg/crd/testdata/gen/bar.example.com_foos.v1beta1.yaml index c0626821b..e7bee22c9 100644 --- a/pkg/crd/testdata/gen/bar.example.com_foos.v1beta1.yaml +++ b/pkg/crd/testdata/gen/bar.example.com_foos.v1beta1.yaml @@ -4,7 +4,6 @@ kind: CustomResourceDefinition metadata: annotations: controller-gen.kubebuilder.io/version: (devel) - creationTimestamp: null name: foos.bar.example.com spec: group: bar.example.com diff --git a/pkg/crd/testdata/gen/bar.example.com_foos.yaml b/pkg/crd/testdata/gen/bar.example.com_foos.yaml index 87ab52507..06c3b4f34 100644 --- a/pkg/crd/testdata/gen/bar.example.com_foos.yaml +++ b/pkg/crd/testdata/gen/bar.example.com_foos.yaml @@ -4,7 +4,6 @@ kind: CustomResourceDefinition metadata: annotations: controller-gen.kubebuilder.io/version: (devel) - creationTimestamp: null name: foos.bar.example.com spec: group: bar.example.com @@ -20,14 +19,19 @@ spec: 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' + 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' + 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 @@ -36,8 +40,10 @@ spec: properties: defaultedString: default: fooDefaultString - description: This tests that defaulted fields are stripped for v1beta1, + description: |- + This tests that defaulted fields are stripped for v1beta1, but not for v1 + example: fooExampleString type: string required: - defaultedString diff --git a/pkg/crd/testdata/gen/foo_types.go b/pkg/crd/testdata/gen/foo_types.go index 5d86117e7..089904770 100644 --- a/pkg/crd/testdata/gen/foo_types.go +++ b/pkg/crd/testdata/gen/foo_types.go @@ -28,6 +28,7 @@ type FooSpec struct { // This tests that defaulted fields are stripped for v1beta1, // but not for v1 // +kubebuilder:default=fooDefaultString + // +kubebuilder:example=fooExampleString DefaultedString string `json:"defaultedString"` } type FooStatus struct{} diff --git a/pkg/crd/testdata/gen/zoo/bar.example.com_zooes.v1beta1.yaml b/pkg/crd/testdata/gen/zoo/bar.example.com_zoos.v1beta1.yaml similarity index 97% rename from pkg/crd/testdata/gen/zoo/bar.example.com_zooes.v1beta1.yaml rename to pkg/crd/testdata/gen/zoo/bar.example.com_zoos.v1beta1.yaml index 2de49adb5..c6de8b08b 100644 --- a/pkg/crd/testdata/gen/zoo/bar.example.com_zooes.v1beta1.yaml +++ b/pkg/crd/testdata/gen/zoo/bar.example.com_zoos.v1beta1.yaml @@ -4,14 +4,13 @@ kind: CustomResourceDefinition metadata: annotations: controller-gen.kubebuilder.io/version: (devel) - creationTimestamp: null name: zoos.bar.example.com spec: group: bar.example.com names: kind: Zoo listKind: ZooList - plural: zooes + plural: zoos singular: zoo scope: Namespaced validation: diff --git a/pkg/crd/testdata/gen/zoo/bar.example.com_zooes.yaml b/pkg/crd/testdata/gen/zoo/bar.example.com_zoos.yaml similarity index 50% rename from pkg/crd/testdata/gen/zoo/bar.example.com_zooes.yaml rename to pkg/crd/testdata/gen/zoo/bar.example.com_zoos.yaml index 5663360a7..c4e12c616 100644 --- a/pkg/crd/testdata/gen/zoo/bar.example.com_zooes.yaml +++ b/pkg/crd/testdata/gen/zoo/bar.example.com_zoos.yaml @@ -4,14 +4,13 @@ kind: CustomResourceDefinition metadata: annotations: controller-gen.kubebuilder.io/version: (devel) - creationTimestamp: null - name: zooes.bar.example.com + name: zoos.bar.example.com spec: group: bar.example.com names: kind: Zoo listKind: ZooList - plural: zooes + plural: zoos singular: zoo scope: Namespaced versions: @@ -20,14 +19,19 @@ spec: 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' + 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' + 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 @@ -36,8 +40,10 @@ spec: properties: defaultedString: default: zooDefaultString - description: This tests that defaulted fields are stripped for v1beta1, + description: |- + This tests that defaulted fields are stripped for v1beta1, but not for v1 + example: zooExampleString type: string required: - defaultedString diff --git a/pkg/crd/testdata/gen/zoo/zoo_types.go b/pkg/crd/testdata/gen/zoo/zoo_types.go index cf9fafd66..430d8dfa4 100644 --- a/pkg/crd/testdata/gen/zoo/zoo_types.go +++ b/pkg/crd/testdata/gen/zoo/zoo_types.go @@ -13,9 +13,9 @@ See the License for the specific language governing permissions and limitations under the License. */ -//go:generate ../../../../.run-controller-gen.sh crd:crdVersions=v1beta1 paths=. output:dir=. -//go:generate mv bar.example.com_zooes.yaml bar.example.com_zooes.v1beta1.yaml -//go:generate ../../../../.run-controller-gen.sh crd:crdVersions=v1 paths=. output:dir=. +//go:generate ../../../../../.run-controller-gen.sh crd:crdVersions=v1beta1 paths=. output:dir=. +//go:generate mv bar.example.com_zoos.yaml bar.example.com_zoos.v1beta1.yaml +//go:generate ../../../../../.run-controller-gen.sh crd:crdVersions=v1 paths=. output:dir=. // +groupName=bar.example.com package zoo @@ -28,6 +28,7 @@ type ZooSpec struct { // This tests that defaulted fields are stripped for v1beta1, // but not for v1 // +kubebuilder:default=zooDefaultString + // +kubebuilder:example=zooExampleString DefaultedString string `json:"defaultedString"` } type ZooStatus struct{} diff --git a/pkg/crd/testdata/multiple_versions/common.go b/pkg/crd/testdata/multiple_versions/common.go new file mode 100644 index 000000000..bfe26252c --- /dev/null +++ b/pkg/crd/testdata/multiple_versions/common.go @@ -0,0 +1,12 @@ +//go:generate ../../../../.run-controller-gen.sh crd paths=./v1beta1;./v1beta2 output:dir=. + +package multiple_versions + +type InnerStruct struct { + Foo string `json:"foo,omitempty"` +} + +type OuterStruct struct { + // +structType=atomic + Struct InnerStruct `json:"struct,omitempty"` +} diff --git a/pkg/crd/testdata/multiple_versions/testdata.kubebuilder.io_versionedresources.yaml b/pkg/crd/testdata/multiple_versions/testdata.kubebuilder.io_versionedresources.yaml new file mode 100644 index 000000000..66786fd0b --- /dev/null +++ b/pkg/crd/testdata/multiple_versions/testdata.kubebuilder.io_versionedresources.yaml @@ -0,0 +1,96 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: (devel) + name: versionedresources.testdata.kubebuilder.io +spec: + group: testdata.kubebuilder.io + names: + kind: VersionedResource + listKind: VersionedResourceList + plural: versionedresources + singular: versionedresource + scope: Namespaced + versions: + - name: v1beta1 + 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: + properties: + struct: + properties: + struct: + properties: + foo: + type: string + type: object + x-kubernetes-map-type: atomic + type: object + type: object + required: + - spec + type: object + served: true + storage: false + subresources: + status: {} + - name: v1beta2 + 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: + properties: + struct: + properties: + struct: + properties: + foo: + type: string + type: object + x-kubernetes-map-type: atomic + type: object + type: object + required: + - spec + type: object + served: true + storage: true + subresources: + status: {} diff --git a/pkg/crd/testdata/multiple_versions/v1beta1/types.go b/pkg/crd/testdata/multiple_versions/v1beta1/types.go new file mode 100644 index 000000000..207ef5c74 --- /dev/null +++ b/pkg/crd/testdata/multiple_versions/v1beta1/types.go @@ -0,0 +1,45 @@ +/* + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// +groupName=testdata.kubebuilder.io +package v1beta1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + multiver "testdata.kubebuilder.io/cronjob/multiple_versions" +) + +type VersionedResourceSpec struct { + Struct multiver.OuterStruct `json:"struct,omitempty"` +} + +// +kubebuilder:object:root=true +// +kubebuilder:subresource:status +// +kubebuilder:resource:singular=versionedresource + +type VersionedResource struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec VersionedResourceSpec `json:"spec"` +} + +// +kubebuilder:object:root=true + +type VersionedResourceList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []VersionedResource `json:"items"` +} diff --git a/pkg/crd/testdata/multiple_versions/v1beta2/types.go b/pkg/crd/testdata/multiple_versions/v1beta2/types.go new file mode 100644 index 000000000..8d98b8768 --- /dev/null +++ b/pkg/crd/testdata/multiple_versions/v1beta2/types.go @@ -0,0 +1,46 @@ +/* + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// +groupName=testdata.kubebuilder.io +package v1beta2 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + multiver "testdata.kubebuilder.io/cronjob/multiple_versions" +) + +type VersionedResourceSpec struct { + Struct multiver.OuterStruct `json:"struct,omitempty"` +} + +// +kubebuilder:storageversion +// +kubebuilder:object:root=true +// +kubebuilder:subresource:status +// +kubebuilder:resource:singular=versionedresource + +type VersionedResource struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec VersionedResourceSpec `json:"spec"` +} + +// +kubebuilder:object:root=true + +type VersionedResourceList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []VersionedResource `json:"items"` +} diff --git a/pkg/crd/testdata/nogroup/types.go b/pkg/crd/testdata/nogroup/types.go new file mode 100644 index 000000000..0d6983c20 --- /dev/null +++ b/pkg/crd/testdata/nogroup/types.go @@ -0,0 +1,29 @@ +/* + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// +groupName= +package nogroup + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// +kubebuilder:object:root=true + +// CronJob is the Schema for the cronjobs API +type CronJob struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` +} diff --git a/pkg/crd/testdata/plural/plural.example.com_testquotas.yaml b/pkg/crd/testdata/plural/plural.example.com_testquotas.yaml index 646179112..fdd5bfa02 100644 --- a/pkg/crd/testdata/plural/plural.example.com_testquotas.yaml +++ b/pkg/crd/testdata/plural/plural.example.com_testquotas.yaml @@ -1,11 +1,9 @@ - --- apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: controller-gen.kubebuilder.io/version: (devel) - creationTimestamp: null name: testquotas.plural.example.com spec: group: plural.example.com @@ -21,14 +19,19 @@ spec: 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' + 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' + 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 diff --git a/pkg/crd/testdata/testdata._cronjobs.yaml b/pkg/crd/testdata/testdata._cronjobs.yaml new file mode 100644 index 000000000..218674c4a --- /dev/null +++ b/pkg/crd/testdata/testdata._cronjobs.yaml @@ -0,0 +1,41 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: (devel) + name: cronjobs. +spec: + group: "" + names: + kind: CronJob + listKind: CronJobList + plural: cronjobs + singular: cronjob + scope: Namespaced + versions: + - name: nogroup + schema: + openAPIV3Schema: + description: CronJob is the Schema for the cronjobs 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 + type: object + served: true + storage: true diff --git a/pkg/crd/testdata/testdata.kubebuilder.io_cronjobs.yaml b/pkg/crd/testdata/testdata.kubebuilder.io_cronjobs.yaml index ead8723de..95a5d870b 100644 --- a/pkg/crd/testdata/testdata.kubebuilder.io_cronjobs.yaml +++ b/pkg/crd/testdata/testdata.kubebuilder.io_cronjobs.yaml @@ -3,10 +3,9 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: (devel) api-approved.kubernetes.io: https://github.com/kubernetes-sigs/controller-tools cert-manager.io/inject-ca-from-secret: cert-manager/cert-manager-webhook-ca - creationTimestamp: null + controller-gen.kubebuilder.io/version: (devel) name: cronjobs.testdata.kubebuilder.io spec: group: testdata.kubebuilder.io @@ -23,14 +22,19 @@ spec: description: CronJob is the Schema for the cronjobs 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' + 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' + 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 @@ -87,16 +91,41 @@ spec: nullable: true type: string concurrencyPolicy: - description: 'Specifies how to treat concurrent executions of a Job. - Valid values are: - "Allow" (default): allows CronJobs to run concurrently; - - "Forbid": forbids concurrent runs, skipping next run if previous - run hasn''t finished yet; - "Replace": cancels currently running - job and replaces it with a new one' + description: |- + Specifies how to treat concurrent executions of a Job. + Valid values are: + - "Allow" (default): allows CronJobs to run concurrently; + - "Forbid": forbids concurrent runs, skipping next run if previous run hasn't finished yet; + - "Replace": cancels currently running job and replaces it with a new one enum: - Allow - Forbid - Replace type: string + defaultedEmptyMap: + additionalProperties: + type: string + default: {} + description: This tests that an empty object defaulting can be performed + on a map. + type: object + defaultedEmptyObject: + default: {} + description: This tests that an empty object defaulting can be performed + on an object. + properties: + bar: + type: string + foo: + default: forty-two + type: string + type: object + defaultedEmptySlice: + default: [] + description: This tests that empty slice defaulting can be performed. + items: + type: string + type: array defaultedObject: default: - nested: @@ -104,7 +133,15 @@ spec: foo: baz - nested: bar: false - description: This tests that object defaulting can be performed. + foo: qux + description: This tests that slice and object defaulting can be performed. + example: + - nested: + bar: true + foo: baz + - nested: + bar: false + foo: qux items: properties: nested: @@ -126,20 +163,105 @@ spec: - a - b description: This tests that slice defaulting can be performed. + example: + - a + - b items: type: string type: array defaultedString: default: forty-two description: This tests that primitive defaulting can be performed. + example: forty-two + type: string + explicitlyOptionalKubebuilder: + description: This tests explicitly optional kubebuilder fields + type: string + explicitlyOptionalKubernetes: + description: This tests explicitly optional kubernetes fields + type: string + explicitlyRequiredKubebuilder: + description: This tests explicitly required kubebuilder fields + type: string + explicitlyRequiredKubernetes: + description: This tests explicitly required kubernetes fields + type: string + doubleDefaultedString: + default: kubebuilder-default + description: This tests that kubebuilder defaulting takes precedence. + type: string + kubernetesDefaultedEmptyMap: + additionalProperties: + type: string + default: {} + description: This tests that an empty object defaulting can be performed + on a map. + type: object + kubernetesDefaultedEmptyObject: + default: {} + description: This tests that an empty object defaulting can be performed + on an object. + properties: + bar: + type: string + foo: + default: forty-two + type: string + type: object + kubernetesDefaultedEmptySlice: + default: [] + description: This tests that empty slice defaulting can be performed. + items: + type: string + type: array + kubernetesDefaultedObject: + default: + - nested: + bar: true + foo: baz + - nested: + bar: false + foo: qux + description: This tests that slice and object defaulting can be performed. + items: + properties: + nested: + properties: + bar: + type: boolean + foo: + type: string + required: + - bar + - foo + type: object + required: + - nested + type: object + type: array + kubernetesDefaultedSlice: + default: + - a + - b + description: This tests that slice defaulting can be performed. + items: + type: string + type: array + kubernetesDefaultedString: + default: forty-two + description: This tests that primitive defaulting can be performed. + type: string + kubernetesDefaultedRef: + description: This tests that use of +default=ref(...) doesn't break generation type: string embeddedResource: type: object x-kubernetes-embedded-resource: true x-kubernetes-preserve-unknown-fields: true failedJobsHistoryLimit: - description: The number of failed finished jobs to retain. This is - a pointer to distinguish between explicit zero and not specified. + description: |- + The number of failed finished jobs to retain. + This is a pointer to distinguish between explicit zero and not specified. format: int32 type: integer float64WithValidations: @@ -156,20 +278,58 @@ spec: description: This tests that exported fields are not skipped in the schema generation type: string + forbiddenInt: + description: |- + Test that we can add a forbidden field using XValidation Reason and FieldPath. + The validation is applied to the spec struct itself and not the field. + type: integer + hosts: + description: This tests string slice item validation. + items: + maxLength: 255 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?([.][a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + minItems: 1 + type: array + x-kubernetes-list-type: set + hostsAlias: + description: This tests string slice item validation. + items: + maxLength: 255 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?([.][a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + minItems: 1 + type: array + x-kubernetes-list-type: set int32WithValidations: format: int32 maximum: 2 minimum: -2 multipleOf: 2 type: integer + intOrStringArrayWithAPattern: + description: |- + This tests that a slice of IntOrString can also have a pattern attached to it. + This can be useful if you want to limit the string to a percentage or integer. + The XIntOrString marker is a requirement for having a pattern on this type. + items: + anyOf: + - type: integer + - type: string + pattern: ^((100|[0-9]{1,2})%|[0-9]+)$ + x-kubernetes-int-or-string: true + type: array intOrStringWithAPattern: anyOf: - type: integer - type: string - description: This tests that an IntOrString can also have a pattern - attached to it. This can be useful if you want to limit the string - to a perecentage or integer. The XIntOrString marker is a requirement - for having a pattern on this type. + description: |- + This tests that an IntOrString can also have a pattern attached + to it. + This can be useful if you want to limit the string to a percentage or integer. + The XIntOrString marker is a requirement for having a pattern on this type. pattern: ^((100|[0-9]{1,2})%|[0-9]+)$ x-kubernetes-int-or-string: true intWithValidations: @@ -182,65 +342,71 @@ spec: a CronJob. properties: metadata: - description: 'Standard object''s metadata of the jobs created - from this template. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata' + description: |- + Standard object's metadata of the jobs created from this template. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata type: object spec: - description: 'Specification of the desired behavior of the job. - More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status' + description: |- + Specification of the desired behavior of the job. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status properties: activeDeadlineSeconds: - description: Specifies the duration in seconds relative to - the startTime that the job may be active before the system - tries to terminate it; value must be positive integer + description: |- + Specifies the duration in seconds relative to the startTime that the job may be active + before the system tries to terminate it; value must be positive integer format: int64 type: integer backoffLimit: - description: Specifies the number of retries before marking - this job failed. Defaults to 6 + description: |- + Specifies the number of retries before marking this job failed. + Defaults to 6 format: int32 type: integer completions: - description: 'Specifies the desired number of successfully - finished pods the job should be run with. Setting to nil - means that the success of any pod signals the success of - all pods, and allows parallelism to have any positive value. Setting - to 1 means that parallelism is limited to 1 and the success - of that pod signals the success of the job. More info: https://kubernetes.io/docs/concepts/workloads/controllers/jobs-run-to-completion/' + description: |- + Specifies the desired number of successfully finished pods the + job should be run with. Setting to nil means that the success of any + pod signals the success of all pods, and allows parallelism to have any positive + value. Setting to 1 means that parallelism is limited to 1 and the success of that + pod signals the success of the job. + More info: https://kubernetes.io/docs/concepts/workloads/controllers/jobs-run-to-completion/ format: int32 type: integer manualSelector: - description: 'manualSelector controls generation of pod labels - and pod selectors. Leave `manualSelector` unset unless you - are certain what you are doing. When false or unset, the - system pick labels unique to this job and appends those - labels to the pod template. When true, the user is responsible - for picking unique labels and specifying the selector. Failure - to pick a unique label may cause this and other jobs to - not function correctly. However, You may see `manualSelector=true` - in jobs that were created with the old `extensions/v1beta1` - API. More info: https://kubernetes.io/docs/concepts/workloads/controllers/jobs-run-to-completion/#specifying-your-own-pod-selector' + description: |- + manualSelector controls generation of pod labels and pod selectors. + Leave `manualSelector` unset unless you are certain what you are doing. + When false or unset, the system pick labels unique to this job + and appends those labels to the pod template. When true, + the user is responsible for picking unique labels and specifying + the selector. Failure to pick a unique label may cause this + and other jobs to not function correctly. However, You may see + `manualSelector=true` in jobs that were created with the old `extensions/v1beta1` + API. + More info: https://kubernetes.io/docs/concepts/workloads/controllers/jobs-run-to-completion/#specifying-your-own-pod-selector type: boolean parallelism: - description: 'Specifies the maximum desired number of pods - the job should run at any given time. The actual number - of pods running in steady state will be less than this number - when ((.spec.completions - .status.successful) < .spec.parallelism), + description: |- + Specifies the maximum desired number of pods the job should + run at any given time. The actual number of pods running in steady state will + be less than this number when ((.spec.completions - .status.successful) < .spec.parallelism), i.e. when the work left to do is less than max parallelism. - More info: https://kubernetes.io/docs/concepts/workloads/controllers/jobs-run-to-completion/' + More info: https://kubernetes.io/docs/concepts/workloads/controllers/jobs-run-to-completion/ format: int32 type: integer selector: - description: 'A label query over pods that should match the - pod count. Normally, the system sets this field for you. - More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#label-selectors' + description: |- + A label query over pods that should match the pod count. + Normally, the system sets this field for you. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#label-selectors 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 + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. properties: key: @@ -248,17 +414,16 @@ spec: applies 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: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. type: string values: - description: values is an array of string values. - If the operator is In or NotIn, the values array - must be non-empty. If the operator is Exists or - DoesNotExist, the values array must be empty. - This array is replaced during a strategic merge - patch. + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. items: type: string type: array @@ -270,31 +435,32 @@ spec: 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. + 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 template: - description: 'Describes the pod that will be created when - executing a job. More info: https://kubernetes.io/docs/concepts/workloads/controllers/jobs-run-to-completion/' + description: |- + Describes the pod that will be created when executing a job. + More info: https://kubernetes.io/docs/concepts/workloads/controllers/jobs-run-to-completion/ properties: metadata: - description: 'Standard object''s metadata. More info: - https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata' + description: |- + Standard object's metadata. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata type: object spec: - description: 'Specification of the desired behavior of - the pod. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status' + description: |- + Specification of the desired behavior of the pod. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status properties: activeDeadlineSeconds: - description: Optional duration in seconds the pod - may be active on the node relative to StartTime - before the system will actively try to mark it failed - and kill associated containers. Value must be a - positive integer. + description: |- + Optional duration in seconds the pod may be active on the node relative to + StartTime before the system will actively try to mark it failed and kill associated containers. + Value must be a positive integer. format: int64 type: integer affinity: @@ -305,27 +471,20 @@ spec: rules for the pod. properties: preferredDuringSchedulingIgnoredDuringExecution: - description: The scheduler will prefer to - schedule pods to nodes that satisfy the - affinity expressions specified by this field, - but it may choose a node that violates one - or more of the expressions. The node that - is most preferred is the one with the greatest - sum of weights, i.e. for each node that - meets all of the scheduling requirements - (resource request, requiredDuringScheduling - affinity expressions, etc.), compute a sum - by iterating through the elements of this - field and adding "weight" to the sum if - the node matches the corresponding matchExpressions; - the node(s) with the highest sum are the - most preferred. + description: |- + The scheduler will prefer to schedule pods to nodes that satisfy + the affinity expressions specified by this field, but it may choose + a node that violates one or more of the expressions. The node that is + most preferred is the one with the greatest sum of weights, i.e. + for each node that meets all of the scheduling requirements (resource + request, requiredDuringScheduling affinity expressions, etc.), + compute a sum by iterating through the elements of this field and adding + "weight" to the sum if the node matches the corresponding matchExpressions; the + node(s) with the highest sum are the most preferred. items: - description: An empty preferred scheduling - term matches all objects with implicit - weight 0 (i.e. it's a no-op). A null preferred - scheduling term matches no objects (i.e. - is also a no-op). + description: |- + An empty preferred scheduling term matches all objects with implicit weight 0 + (i.e. it's a no-op). A null preferred scheduling term matches no objects (i.e. is also a no-op). properties: preference: description: A node selector term, associated @@ -335,9 +494,8 @@ spec: description: A list of node selector requirements by node's labels. items: - description: A node selector requirement - is a selector that contains - values, a key, and an operator + description: |- + A node selector requirement is a selector that contains values, a key, and an operator that relates the key and values. properties: key: @@ -346,27 +504,17 @@ spec: to. type: string operator: - description: Represents a - key's relationship to a - set of values. Valid operators - are In, NotIn, Exists, DoesNotExist. - Gt, and Lt. + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. type: string values: - description: An array of string - values. If the operator - is In or NotIn, the values - array must be non-empty. - If the operator is Exists - or DoesNotExist, the values - array must be empty. If - the operator is Gt or Lt, - the values array must have - a single element, which - will be interpreted as an - integer. This array is replaced - during a strategic merge - patch. + description: |- + An array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + This array is replaced during a strategic merge patch. items: type: string type: array @@ -379,9 +527,8 @@ spec: description: A list of node selector requirements by node's fields. items: - description: A node selector requirement - is a selector that contains - values, a key, and an operator + description: |- + A node selector requirement is a selector that contains values, a key, and an operator that relates the key and values. properties: key: @@ -390,27 +537,17 @@ spec: to. type: string operator: - description: Represents a - key's relationship to a - set of values. Valid operators - are In, NotIn, Exists, DoesNotExist. - Gt, and Lt. + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. type: string values: - description: An array of string - values. If the operator - is In or NotIn, the values - array must be non-empty. - If the operator is Exists - or DoesNotExist, the values - array must be empty. If - the operator is Gt or Lt, - the values array must have - a single element, which - will be interpreted as an - integer. This array is replaced - during a strategic merge - patch. + description: |- + An array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + This array is replaced during a strategic merge patch. items: type: string type: array @@ -432,31 +569,28 @@ spec: type: object type: array requiredDuringSchedulingIgnoredDuringExecution: - description: If the affinity requirements - specified by this field are not met at scheduling - time, the pod will not be scheduled onto - the node. If the affinity requirements specified - by this field cease to be met at some point - during pod execution (e.g. due to an update), - the system may or may not try to eventually - evict the pod from its node. + description: |- + If the affinity requirements specified by this field are not met at + scheduling time, the pod will not be scheduled onto the node. + If the affinity requirements specified by this field cease to be met + at some point during pod execution (e.g. due to an update), the system + may or may not try to eventually evict the pod from its node. properties: nodeSelectorTerms: description: Required. A list of node selector terms. The terms are ORed. items: - description: A null or empty node selector - term matches no objects. The requirements - of them are ANDed. The TopologySelectorTerm - type implements a subset of the NodeSelectorTerm. + description: |- + A null or empty node selector term matches no objects. The requirements of + them are ANDed. + The TopologySelectorTerm type implements a subset of the NodeSelectorTerm. properties: matchExpressions: description: A list of node selector requirements by node's labels. items: - description: A node selector requirement - is a selector that contains - values, a key, and an operator + description: |- + A node selector requirement is a selector that contains values, a key, and an operator that relates the key and values. properties: key: @@ -465,27 +599,17 @@ spec: to. type: string operator: - description: Represents a - key's relationship to a - set of values. Valid operators - are In, NotIn, Exists, DoesNotExist. - Gt, and Lt. + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. type: string values: - description: An array of string - values. If the operator - is In or NotIn, the values - array must be non-empty. - If the operator is Exists - or DoesNotExist, the values - array must be empty. If - the operator is Gt or Lt, - the values array must have - a single element, which - will be interpreted as an - integer. This array is replaced - during a strategic merge - patch. + description: |- + An array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + This array is replaced during a strategic merge patch. items: type: string type: array @@ -498,9 +622,8 @@ spec: description: A list of node selector requirements by node's fields. items: - description: A node selector requirement - is a selector that contains - values, a key, and an operator + description: |- + A node selector requirement is a selector that contains values, a key, and an operator that relates the key and values. properties: key: @@ -509,27 +632,17 @@ spec: to. type: string operator: - description: Represents a - key's relationship to a - set of values. Valid operators - are In, NotIn, Exists, DoesNotExist. - Gt, and Lt. + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. type: string values: - description: An array of string - values. If the operator - is In or NotIn, the values - array must be non-empty. - If the operator is Exists - or DoesNotExist, the values - array must be empty. If - the operator is Gt or Lt, - the values array must have - a single element, which - will be interpreted as an - integer. This array is replaced - during a strategic merge - patch. + description: |- + An array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + This array is replaced during a strategic merge patch. items: type: string type: array @@ -550,21 +663,16 @@ spec: zone, etc. as some other pod(s)). properties: preferredDuringSchedulingIgnoredDuringExecution: - description: The scheduler will prefer to - schedule pods to nodes that satisfy the - affinity expressions specified by this field, - but it may choose a node that violates one - or more of the expressions. The node that - is most preferred is the one with the greatest - sum of weights, i.e. for each node that - meets all of the scheduling requirements - (resource request, requiredDuringScheduling - affinity expressions, etc.), compute a sum - by iterating through the elements of this - field and adding "weight" to the sum if - the node has pods which matches the corresponding - podAffinityTerm; the node(s) with the highest - sum are the most preferred. + description: |- + The scheduler will prefer to schedule pods to nodes that satisfy + the affinity expressions specified by this field, but it may choose + a node that violates one or more of the expressions. The node that is + most preferred is the one with the greatest sum of weights, i.e. + for each node that meets all of the scheduling requirements (resource + request, requiredDuringScheduling affinity expressions, etc.), + compute a sum by iterating through the elements of this field and adding + "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the + node(s) with the highest sum are the most preferred. items: description: The weights of all of the matched WeightedPodAffinityTerm fields are added @@ -586,10 +694,8 @@ spec: requirements. The requirements are ANDed. items: - description: A label selector - requirement is a selector - that contains values, a - key, and an operator that + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. properties: key: @@ -598,24 +704,15 @@ spec: applies 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: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. type: string values: - description: values is - an array of string values. - If the operator is In - or NotIn, the values - array must be non-empty. - If the operator is Exists - or DoesNotExist, the - values array must be - empty. This array is - replaced during a strategic + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic merge patch. items: type: string @@ -628,46 +725,33 @@ spec: 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. + 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 namespaces: - description: namespaces specifies - which namespaces the labelSelector - applies to (matches against); - null or empty list means "this - pod's namespace" + description: |- + namespaces specifies which namespaces the labelSelector applies to (matches against); + null or empty list means "this pod's namespace" items: type: string type: array topologyKey: - description: This pod should be - co-located (affinity) or not co-located - (anti-affinity) with the pods - matching the labelSelector in - the specified namespaces, where - co-located is defined as running - on a node whose value of the label - with key topologyKey matches that - of any node on which any of the - selected pods is running. Empty - topologyKey is not allowed. + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. type: string required: - topologyKey type: object weight: - description: weight associated with - matching the corresponding podAffinityTerm, + description: |- + weight associated with matching the corresponding podAffinityTerm, in the range 1-100. format: int32 type: integer @@ -677,28 +761,22 @@ spec: type: object type: array requiredDuringSchedulingIgnoredDuringExecution: - description: If the affinity requirements - specified by this field are not met at scheduling - time, the pod will not be scheduled onto - the node. If the affinity requirements specified - by this field cease to be met at some point - during pod execution (e.g. due to a pod - label update), the system may or may not - try to eventually evict the pod from its - node. When there are multiple elements, - the lists of nodes corresponding to each - podAffinityTerm are intersected, i.e. all - terms must be satisfied. + description: |- + If the affinity requirements specified by this field are not met at + scheduling time, the pod will not be scheduled onto the node. + If the affinity requirements specified by this field cease to be met + at some point during pod execution (e.g. due to a pod label update), the + system may or may not try to eventually evict the pod from its node. + When there are multiple elements, the lists of nodes corresponding to each + podAffinityTerm are intersected, i.e. all terms must be satisfied. items: - description: Defines a set of pods (namely - those matching the labelSelector relative - to the given namespace(s)) that this pod - should be co-located (affinity) or not - co-located (anti-affinity) with, where - co-located is defined as running on a - node whose value of the label with key - matches that of any node - on which a pod of the set of pods is running + description: |- + Defines a set of pods (namely those matching the labelSelector + relative to the given namespace(s)) that this pod should be + co-located (affinity) or not co-located (anti-affinity) with, + where co-located is defined as running on a node whose value of + the label with key matches that of any node on which + a pod of the set of pods is running properties: labelSelector: description: A label query over a set @@ -709,11 +787,9 @@ spec: 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. + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. properties: key: description: key is the label @@ -721,23 +797,16 @@ spec: 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: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. type: string values: - description: values is an - array of string values. - If the operator is In or - NotIn, the values array - must be non-empty. If the - operator is Exists or DoesNotExist, - the values array must be - empty. This array is replaced - during a strategic merge - patch. + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. items: type: string type: array @@ -749,36 +818,26 @@ spec: 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. + 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 namespaces: - description: namespaces specifies which - namespaces the labelSelector applies - to (matches against); null or empty - list means "this pod's namespace" + description: |- + namespaces specifies which namespaces the labelSelector applies to (matches against); + null or empty list means "this pod's namespace" items: type: string type: array topologyKey: - description: This pod should be co-located - (affinity) or not co-located (anti-affinity) - with the pods matching the labelSelector - in the specified namespaces, where - co-located is defined as running on - a node whose value of the label with - key topologyKey matches that of any - node on which any of the selected - pods is running. Empty topologyKey - is not allowed. + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. type: string required: - topologyKey @@ -791,21 +850,16 @@ spec: node, zone, etc. as some other pod(s)). properties: preferredDuringSchedulingIgnoredDuringExecution: - description: The scheduler will prefer to - schedule pods to nodes that satisfy the - anti-affinity expressions specified by this - field, but it may choose a node that violates - one or more of the expressions. The node - that is most preferred is the one with the - greatest sum of weights, i.e. for each node - that meets all of the scheduling requirements - (resource request, requiredDuringScheduling - anti-affinity expressions, etc.), compute - a sum by iterating through the elements - of this field and adding "weight" to the - sum if the node has pods which matches the - corresponding podAffinityTerm; the node(s) - with the highest sum are the most preferred. + description: |- + The scheduler will prefer to schedule pods to nodes that satisfy + the anti-affinity expressions specified by this field, but it may choose + a node that violates one or more of the expressions. The node that is + most preferred is the one with the greatest sum of weights, i.e. + for each node that meets all of the scheduling requirements (resource + request, requiredDuringScheduling anti-affinity expressions, etc.), + compute a sum by iterating through the elements of this field and adding + "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the + node(s) with the highest sum are the most preferred. items: description: The weights of all of the matched WeightedPodAffinityTerm fields are added @@ -827,10 +881,8 @@ spec: requirements. The requirements are ANDed. items: - description: A label selector - requirement is a selector - that contains values, a - key, and an operator that + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. properties: key: @@ -839,24 +891,15 @@ spec: applies 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: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. type: string values: - description: values is - an array of string values. - If the operator is In - or NotIn, the values - array must be non-empty. - If the operator is Exists - or DoesNotExist, the - values array must be - empty. This array is - replaced during a strategic + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic merge patch. items: type: string @@ -869,46 +912,33 @@ spec: 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. + 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 namespaces: - description: namespaces specifies - which namespaces the labelSelector - applies to (matches against); - null or empty list means "this - pod's namespace" + description: |- + namespaces specifies which namespaces the labelSelector applies to (matches against); + null or empty list means "this pod's namespace" items: type: string type: array topologyKey: - description: This pod should be - co-located (affinity) or not co-located - (anti-affinity) with the pods - matching the labelSelector in - the specified namespaces, where - co-located is defined as running - on a node whose value of the label - with key topologyKey matches that - of any node on which any of the - selected pods is running. Empty - topologyKey is not allowed. + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. type: string required: - topologyKey type: object weight: - description: weight associated with - matching the corresponding podAffinityTerm, + description: |- + weight associated with matching the corresponding podAffinityTerm, in the range 1-100. format: int32 type: integer @@ -918,28 +948,22 @@ spec: type: object type: array requiredDuringSchedulingIgnoredDuringExecution: - description: If the anti-affinity requirements - specified by this field are not met at scheduling - time, the pod will not be scheduled onto - the node. If the anti-affinity requirements - specified by this field cease to be met - at some point during pod execution (e.g. - due to a pod label update), the system may - or may not try to eventually evict the pod - from its node. When there are multiple elements, - the lists of nodes corresponding to each - podAffinityTerm are intersected, i.e. all - terms must be satisfied. + description: |- + If the anti-affinity requirements specified by this field are not met at + scheduling time, the pod will not be scheduled onto the node. + If the anti-affinity requirements specified by this field cease to be met + at some point during pod execution (e.g. due to a pod label update), the + system may or may not try to eventually evict the pod from its node. + When there are multiple elements, the lists of nodes corresponding to each + podAffinityTerm are intersected, i.e. all terms must be satisfied. items: - description: Defines a set of pods (namely - those matching the labelSelector relative - to the given namespace(s)) that this pod - should be co-located (affinity) or not - co-located (anti-affinity) with, where - co-located is defined as running on a - node whose value of the label with key - matches that of any node - on which a pod of the set of pods is running + description: |- + Defines a set of pods (namely those matching the labelSelector + relative to the given namespace(s)) that this pod should be + co-located (affinity) or not co-located (anti-affinity) with, + where co-located is defined as running on a node whose value of + the label with key matches that of any node on which + a pod of the set of pods is running properties: labelSelector: description: A label query over a set @@ -950,11 +974,9 @@ spec: 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. + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. properties: key: description: key is the label @@ -962,23 +984,16 @@ spec: 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: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. type: string values: - description: values is an - array of string values. - If the operator is In or - NotIn, the values array - must be non-empty. If the - operator is Exists or DoesNotExist, - the values array must be - empty. This array is replaced - during a strategic merge - patch. + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. items: type: string type: array @@ -990,36 +1005,26 @@ spec: 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. + 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 namespaces: - description: namespaces specifies which - namespaces the labelSelector applies - to (matches against); null or empty - list means "this pod's namespace" + description: |- + namespaces specifies which namespaces the labelSelector applies to (matches against); + null or empty list means "this pod's namespace" items: type: string type: array topologyKey: - description: This pod should be co-located - (affinity) or not co-located (anti-affinity) - with the pods matching the labelSelector - in the specified namespaces, where - co-located is defined as running on - a node whose value of the label with - key topologyKey matches that of any - node on which any of the selected - pods is running. Empty topologyKey - is not allowed. + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. type: string required: - topologyKey @@ -1033,48 +1038,45 @@ spec: mounted. type: boolean containers: - description: List of containers belonging to the pod. + description: |- + List of containers belonging to the pod. Containers cannot currently be added or removed. - There must be at least one container in a Pod. Cannot - be updated. + There must be at least one container in a Pod. + Cannot be updated. items: description: A single application container that you want to run within a pod. properties: args: - description: 'Arguments to the entrypoint. The - docker 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. The - $(VAR_NAME) syntax can be escaped with a double - $$, ie: $$(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' + description: |- + Arguments to the entrypoint. + The docker 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. The $(VAR_NAME) syntax + can be escaped with a double $$, ie: $$(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 docker 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. The $(VAR_NAME) - syntax can be escaped with a double $$, ie: - $$(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' + description: |- + Entrypoint array. Not executed within a shell. + The docker 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. The $(VAR_NAME) syntax + can be escaped with a double $$, ie: $$(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. + description: |- + List of environment variables to set in the container. + Cannot be updated. items: description: EnvVar represents an environment variable present in a Container. @@ -1084,17 +1086,15 @@ spec: Must be a C_IDENTIFIER. type: string value: - description: 'Variable references $(VAR_NAME) - are expanded using the previous 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. The $(VAR_NAME) syntax can - be escaped with a double $$, ie: $$(VAR_NAME). - Escaped references will never be expanded, - regardless of whether the variable exists - or not. Defaults to "".' + description: |- + Variable references $(VAR_NAME) are expanded + using the previous 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. The $(VAR_NAME) + syntax can be escaped with a double $$, ie: $$(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 @@ -1108,10 +1108,9 @@ spec: description: The key to select. type: string name: - description: 'Name of the referent. + 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 @@ -1122,11 +1121,9 @@ spec: - key type: object 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.' + 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 @@ -1142,12 +1139,9 @@ spec: - fieldPath type: object 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.' + 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: @@ -1180,10 +1174,9 @@ spec: secret key. type: string name: - description: 'Name of the referent. + 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 @@ -1198,15 +1191,13 @@ spec: 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. + 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 @@ -1215,10 +1206,9 @@ spec: description: The ConfigMap to select from properties: name: - description: 'Name of the referent. + 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 @@ -1234,10 +1224,9 @@ spec: description: The Secret to select from properties: name: - description: 'Name of the referent. + 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 @@ -1247,51 +1236,44 @@ spec: type: object type: array image: - description: 'Docker 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.' + description: |- + Docker 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' + 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. + 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' + 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: One and only one of the - following should be specified. Exec - specifies the action to take. + description: |- + One and only one of the following should be specified. + 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. + 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 @@ -1301,10 +1283,9 @@ spec: 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. + 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 @@ -1336,23 +1317,23 @@ spec: 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. + 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. + description: |- + Scheme to use for connecting to the host. + Defaults to HTTP. type: string required: - port type: object tcpSocket: - description: 'TCPSocket specifies an - action involving a TCP port. TCP hooks - not yet supported TODO: implement - a realistic TCP lifecycle hook' + description: |- + TCPSocket specifies an action involving a TCP port. + TCP hooks not yet supported properties: host: description: 'Optional: Host name @@ -1363,52 +1344,40 @@ spec: 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. + 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 reason for termination is - passed to the handler. The Pod''s termination - grace period countdown begins before the - PreStop hooked is executed. Regardless - of the outcome of the handler, the container - will eventually terminate within the Pod''s - termination grace period. 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' + 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 reason for termination is passed to the + handler. The Pod's termination grace period countdown begins before the + PreStop hooked is executed. Regardless of the outcome of the handler, the + container will eventually terminate within the Pod's termination grace + period. 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: One and only one of the - following should be specified. Exec - specifies the action to take. + description: |- + One and only one of the following should be specified. + 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. + 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 @@ -1418,10 +1387,9 @@ spec: 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. + 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 @@ -1453,23 +1421,23 @@ spec: 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. + 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. + description: |- + Scheme to use for connecting to the host. + Defaults to HTTP. type: string required: - port type: object tcpSocket: - description: 'TCPSocket specifies an - action involving a TCP port. TCP hooks - not yet supported TODO: implement - a realistic TCP lifecycle hook' + description: |- + TCPSocket specifies an action involving a TCP port. + TCP hooks not yet supported properties: host: description: 'Optional: Host name @@ -1480,10 +1448,10 @@ spec: 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. + 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 @@ -1491,36 +1459,32 @@ spec: type: object type: object livenessProbe: - description: 'Periodic probe of container liveness. + 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' + Cannot be updated. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes properties: exec: - description: One and only one of the following - should be specified. Exec specifies the - action to take. + description: |- + One and only one of the following should be specified. + 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. + 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. + 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 httpGet: @@ -1528,10 +1492,9 @@ spec: 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. + 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 @@ -1563,43 +1526,41 @@ spec: 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. + 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. + 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' + 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. + 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. + 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. TCP hooks not yet - supported TODO: implement a realistic - TCP lifecycle hook' + description: |- + TCPSocket specifies an action involving a TCP port. + TCP hooks not yet supported properties: host: description: 'Optional: Host name to @@ -1609,46 +1570,45 @@ spec: 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. + 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 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' + 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. + 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. Exposing a port here gives the - system additional information about the network - connections a container uses, but is primarily - informational. 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. Cannot be - updated. + description: |- + List of ports to expose from the container. Exposing a port here gives + the system additional information about the network connections a + container uses, but is primarily informational. 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. + 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. + 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: @@ -1656,25 +1616,24 @@ spec: 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. + 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. + 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". + description: |- + Protocol for port. Must be UDP, TCP, or SCTP. + Defaults to "TCP". type: string required: - containerPort @@ -1685,37 +1644,32 @@ spec: - 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' + 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: One and only one of the following - should be specified. Exec specifies the - action to take. + description: |- + One and only one of the following should be specified. + 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. + 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. + 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 httpGet: @@ -1723,10 +1677,9 @@ spec: 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. + 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 @@ -1758,43 +1711,41 @@ spec: 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. + 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. + 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' + 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. + 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. + 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. TCP hooks not yet - supported TODO: implement a realistic - TCP lifecycle hook' + description: |- + TCPSocket specifies an action involving a TCP port. + TCP hooks not yet supported properties: host: description: 'Optional: Host name to @@ -1804,25 +1755,27 @@ spec: 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. + 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 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' + 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 resources: - description: 'Compute Resources required by - this container. Cannot be updated. More info: - https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/' + description: |- + Compute Resources required by this container. + Cannot be updated. + More info: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/ properties: limits: additionalProperties: @@ -1831,9 +1784,9 @@ spec: - 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-compute-resources-container/' + description: |- + Limits describes the maximum amount of compute resources allowed. + More info: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/ type: object requests: additionalProperties: @@ -1842,33 +1795,32 @@ spec: - 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. More info: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/' + 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. + More info: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/ type: object type: object securityContext: - description: 'Security options the pod should - run with. More info: https://kubernetes.io/docs/concepts/policy/security-context/ - More info: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/' + description: |- + Security options the pod should run with. + More info: https://kubernetes.io/docs/concepts/policy/security-context/ + 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' + 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 type: boolean capabilities: - description: The capabilities to add/drop - when running containers. Defaults to the - default set of capabilities granted by - the container runtime. + description: |- + The capabilities to add/drop when running containers. + Defaults to the default set of capabilities granted by the container runtime. properties: add: description: Added capabilities @@ -1886,66 +1838,54 @@ spec: 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. + description: |- + Run container in privileged mode. + Processes in privileged containers are essentially equivalent to root on the host. + Defaults to false. 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. + 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. type: string readOnlyRootFilesystem: - description: Whether this container has - a read-only root filesystem. Default is - false. + description: |- + Whether this container has a read-only root filesystem. + Default is false. 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. + 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. 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. + 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. + 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. 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. + 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. properties: level: description: Level is SELinux level @@ -1965,49 +1905,41 @@ spec: 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. + 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. 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 only be set - if type is "Localhost". + 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 only be set if type is "Localhost". 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." + 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. 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. + 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. 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. + 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 @@ -2015,57 +1947,45 @@ spec: spec to use. type: string 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. + 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. - This is a beta feature enabled by the StartupProbe - feature flag. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + 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. + This is a beta feature enabled by the StartupProbe feature flag. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes properties: exec: - description: One and only one of the following - should be specified. Exec specifies the - action to take. + description: |- + One and only one of the following should be specified. + 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. + 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. + 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 httpGet: @@ -2073,10 +1993,9 @@ spec: 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. + 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 @@ -2108,43 +2027,41 @@ spec: 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. + 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. + 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' + 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. + 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. + 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. TCP hooks not yet - supported TODO: implement a realistic - TCP lifecycle hook' + description: |- + TCPSocket specifies an action involving a TCP port. + TCP hooks not yet supported properties: host: description: 'Optional: Host name to @@ -2154,71 +2071,62 @@ spec: 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. + 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 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' + 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. + 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 + 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.' + 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. + 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. + 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 @@ -2242,48 +2150,45 @@ spec: type: object type: array volumeMounts: - description: Pod volumes to mount into the container's - filesystem. Cannot be updated. + 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 + 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 + 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. + 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). + 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). + 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. + 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 @@ -2291,34 +2196,36 @@ spec: 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. + 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 type: array dnsConfig: - description: Specifies the DNS parameters of a pod. - Parameters specified here will be merged to the - generated DNS configuration based on DNSPolicy. + description: |- + Specifies the DNS parameters of a pod. + Parameters specified here will be merged to the generated DNS + configuration based on DNSPolicy. properties: nameservers: - description: A list of DNS name server IP addresses. - This will be appended to the base nameservers - generated from DNSPolicy. Duplicated nameservers - will be removed. + description: |- + A list of DNS name server IP addresses. + This will be appended to the base nameservers generated from DNSPolicy. + Duplicated nameservers will be removed. items: type: string type: array options: - description: A list of DNS resolver options. This - will be merged with the base options generated - from DNSPolicy. Duplicated entries will be removed. - Resolution options given in Options will override - those that appear in the base DNSPolicy. + description: |- + A list of DNS resolver options. + This will be merged with the base options generated from DNSPolicy. + Duplicated entries will be removed. Resolution options given in Options + will override those that appear in the base DNSPolicy. items: description: PodDNSConfigOption defines DNS resolver options of a pod. @@ -2331,89 +2238,78 @@ spec: type: object type: array searches: - description: A list of DNS search domains for - host-name lookup. This will be appended to the - base search paths generated from DNSPolicy. + description: |- + A list of DNS search domains for host-name lookup. + This will be appended to the base search paths generated from DNSPolicy. Duplicated search paths will be removed. items: type: string type: array type: object dnsPolicy: - description: Set DNS policy for the pod. Defaults - to "ClusterFirst". Valid values are 'ClusterFirstWithHostNet', - 'ClusterFirst', 'Default' or 'None'. DNS parameters - given in DNSConfig will be merged with the policy - selected with DNSPolicy. To have DNS options set - along with hostNetwork, you have to specify DNS - policy explicitly to 'ClusterFirstWithHostNet'. + description: |- + Set DNS policy for the pod. + Defaults to "ClusterFirst". + Valid values are 'ClusterFirstWithHostNet', 'ClusterFirst', 'Default' or 'None'. + DNS parameters given in DNSConfig will be merged with the policy selected with DNSPolicy. + To have DNS options set along with hostNetwork, you have to specify DNS policy + explicitly to 'ClusterFirstWithHostNet'. type: string enableServiceLinks: - description: 'EnableServiceLinks indicates whether - information about services should be injected into - pod''s environment variables, matching the syntax - of Docker links. Optional: Defaults to true.' + description: |- + EnableServiceLinks indicates whether information about services should be injected into pod's + environment variables, matching the syntax of Docker links. + Optional: Defaults to true. type: boolean ephemeralContainers: - description: List of ephemeral containers run in this - pod. Ephemeral containers may be run in an existing - pod to perform user-initiated actions such as debugging. - This list cannot be specified when creating a pod, - and it cannot be modified by updating the pod spec. - In order to add an ephemeral container to an existing - pod, use the pod's ephemeralcontainers subresource. - This field is alpha-level and is only honored by - servers that enable the EphemeralContainers feature. + description: |- + List of ephemeral containers run in this pod. Ephemeral containers may be run in an existing + pod to perform user-initiated actions such as debugging. This list cannot be specified when + creating a pod, and it cannot be modified by updating the pod spec. In order to add an + ephemeral container to an existing pod, use the pod's ephemeralcontainers subresource. + This field is alpha-level and is only honored by servers that enable the EphemeralContainers feature. items: - description: An EphemeralContainer is a container - that may be added temporarily to an existing pod - for user-initiated activities such as debugging. - Ephemeral containers have no resource or scheduling - guarantees, and they will not be restarted when - they exit or when a pod is removed or restarted. - If an ephemeral container causes a pod to exceed - its resource allocation, the pod may be evicted. - Ephemeral containers may not be added by directly - updating the pod spec. They must be added via - the pod's ephemeralcontainers subresource, and - they will appear in the pod spec once added. This - is an alpha feature enabled by the EphemeralContainers - feature flag. + description: |- + An EphemeralContainer is a container that may be added temporarily to an existing pod for + user-initiated activities such as debugging. Ephemeral containers have no resource or + scheduling guarantees, and they will not be restarted when they exit or when a pod is + removed or restarted. If an ephemeral container causes a pod to exceed its resource + allocation, the pod may be evicted. + Ephemeral containers may not be added by directly updating the pod spec. They must be added + via the pod's ephemeralcontainers subresource, and they will appear in the pod spec + once added. + This is an alpha feature enabled by the EphemeralContainers feature flag. properties: args: - description: 'Arguments to the entrypoint. The - docker 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. The - $(VAR_NAME) syntax can be escaped with a double - $$, ie: $$(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' + description: |- + Arguments to the entrypoint. + The docker 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. The $(VAR_NAME) syntax + can be escaped with a double $$, ie: $$(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 docker 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. The $(VAR_NAME) - syntax can be escaped with a double $$, ie: - $$(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' + description: |- + Entrypoint array. Not executed within a shell. + The docker 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. The $(VAR_NAME) syntax + can be escaped with a double $$, ie: $$(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. + description: |- + List of environment variables to set in the container. + Cannot be updated. items: description: EnvVar represents an environment variable present in a Container. @@ -2423,17 +2319,15 @@ spec: Must be a C_IDENTIFIER. type: string value: - description: 'Variable references $(VAR_NAME) - are expanded using the previous 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. The $(VAR_NAME) syntax can - be escaped with a double $$, ie: $$(VAR_NAME). - Escaped references will never be expanded, - regardless of whether the variable exists - or not. Defaults to "".' + description: |- + Variable references $(VAR_NAME) are expanded + using the previous 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. The $(VAR_NAME) + syntax can be escaped with a double $$, ie: $$(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 @@ -2447,10 +2341,9 @@ spec: description: The key to select. type: string name: - description: 'Name of the referent. + 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 @@ -2461,11 +2354,9 @@ spec: - key type: object 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.' + 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 @@ -2481,12 +2372,9 @@ spec: - fieldPath type: object 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.' + 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: @@ -2519,10 +2407,9 @@ spec: secret key. type: string name: - description: 'Name of the referent. + 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 @@ -2537,15 +2424,13 @@ spec: 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. + 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 @@ -2554,10 +2439,9 @@ spec: description: The ConfigMap to select from properties: name: - description: 'Name of the referent. + 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 @@ -2573,10 +2457,9 @@ spec: description: The Secret to select from properties: name: - description: 'Name of the referent. + 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 @@ -2586,46 +2469,41 @@ spec: type: object type: array image: - description: 'Docker image name. More info: - https://kubernetes.io/docs/concepts/containers/images' + description: |- + Docker image name. + More info: https://kubernetes.io/docs/concepts/containers/images 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' + 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: Lifecycle is not allowed for ephemeral containers. 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' + 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: One and only one of the - following should be specified. Exec - specifies the action to take. + description: |- + One and only one of the following should be specified. + 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. + 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 @@ -2635,10 +2513,9 @@ spec: 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. + 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 @@ -2670,23 +2547,23 @@ spec: 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. + 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. + description: |- + Scheme to use for connecting to the host. + Defaults to HTTP. type: string required: - port type: object tcpSocket: - description: 'TCPSocket specifies an - action involving a TCP port. TCP hooks - not yet supported TODO: implement - a realistic TCP lifecycle hook' + description: |- + TCPSocket specifies an action involving a TCP port. + TCP hooks not yet supported properties: host: description: 'Optional: Host name @@ -2697,52 +2574,40 @@ spec: 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. + 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 reason for termination is - passed to the handler. The Pod''s termination - grace period countdown begins before the - PreStop hooked is executed. Regardless - of the outcome of the handler, the container - will eventually terminate within the Pod''s - termination grace period. 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' + 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 reason for termination is passed to the + handler. The Pod's termination grace period countdown begins before the + PreStop hooked is executed. Regardless of the outcome of the handler, the + container will eventually terminate within the Pod's termination grace + period. 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: One and only one of the - following should be specified. Exec - specifies the action to take. + description: |- + One and only one of the following should be specified. + 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. + 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 @@ -2752,10 +2617,9 @@ spec: 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. + 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 @@ -2787,23 +2651,23 @@ spec: 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. + 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. + description: |- + Scheme to use for connecting to the host. + Defaults to HTTP. type: string required: - port type: object tcpSocket: - description: 'TCPSocket specifies an - action involving a TCP port. TCP hooks - not yet supported TODO: implement - a realistic TCP lifecycle hook' + description: |- + TCPSocket specifies an action involving a TCP port. + TCP hooks not yet supported properties: host: description: 'Optional: Host name @@ -2814,10 +2678,10 @@ spec: 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. + 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 @@ -2829,31 +2693,25 @@ spec: containers. properties: exec: - description: One and only one of the following - should be specified. Exec specifies the - action to take. + description: |- + One and only one of the following should be specified. + 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. + 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. + 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 httpGet: @@ -2861,10 +2719,9 @@ spec: 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. + 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 @@ -2896,43 +2753,41 @@ spec: 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. + 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. + 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' + 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. + 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. + 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. TCP hooks not yet - supported TODO: implement a realistic - TCP lifecycle hook' + description: |- + TCPSocket specifies an action involving a TCP port. + TCP hooks not yet supported properties: host: description: 'Optional: Host name to @@ -2942,26 +2797,26 @@ spec: 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. + 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 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' + 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 ephemeral container - specified as a DNS_LABEL. This name must be - unique among all containers, init containers - and ephemeral containers. + description: |- + Name of the ephemeral container specified as a DNS_LABEL. + This name must be unique among all containers, init containers and ephemeral containers. type: string ports: description: Ports are not allowed for ephemeral @@ -2971,9 +2826,9 @@ spec: 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. + 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: @@ -2981,25 +2836,24 @@ spec: 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. + 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. + 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". + description: |- + Protocol for port. Must be UDP, TCP, or SCTP. + Defaults to "TCP". type: string required: - containerPort @@ -3010,31 +2864,25 @@ spec: containers. properties: exec: - description: One and only one of the following - should be specified. Exec specifies the - action to take. + description: |- + One and only one of the following should be specified. + 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. + 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. + 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 httpGet: @@ -3042,10 +2890,9 @@ spec: 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. + 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 @@ -3077,43 +2924,41 @@ spec: 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. + 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. + 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' + 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. + 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. + 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. TCP hooks not yet - supported TODO: implement a realistic - TCP lifecycle hook' + description: |- + TCPSocket specifies an action involving a TCP port. + TCP hooks not yet supported properties: host: description: 'Optional: Host name to @@ -3123,25 +2968,26 @@ spec: 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. + 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 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' + 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 resources: - description: Resources are not allowed for ephemeral - containers. Ephemeral containers use spare - resources already allocated to the pod. + description: |- + Resources are not allowed for ephemeral containers. Ephemeral containers use spare resources + already allocated to the pod. properties: limits: additionalProperties: @@ -3150,9 +2996,9 @@ spec: - 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-compute-resources-container/' + description: |- + Limits describes the maximum amount of compute resources allowed. + More info: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/ type: object requests: additionalProperties: @@ -3161,12 +3007,11 @@ spec: - 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. More info: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/' + 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. + More info: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/ type: object type: object securityContext: @@ -3174,19 +3019,18 @@ spec: for ephemeral containers. 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' + 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 type: boolean capabilities: - description: The capabilities to add/drop - when running containers. Defaults to the - default set of capabilities granted by - the container runtime. + description: |- + The capabilities to add/drop when running containers. + Defaults to the default set of capabilities granted by the container runtime. properties: add: description: Added capabilities @@ -3204,66 +3048,54 @@ spec: 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. + description: |- + Run container in privileged mode. + Processes in privileged containers are essentially equivalent to root on the host. + Defaults to false. 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. + 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. type: string readOnlyRootFilesystem: - description: Whether this container has - a read-only root filesystem. Default is - false. + description: |- + Whether this container has a read-only root filesystem. + Default is false. 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. + 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. 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. + 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. + 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. 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. + 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. properties: level: description: Level is SELinux level @@ -3283,49 +3115,41 @@ spec: 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. + 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. 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 only be set - if type is "Localhost". + 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 only be set if type is "Localhost". 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." + 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. 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. + 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. 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. + 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 @@ -3333,14 +3157,11 @@ spec: spec to use. type: string 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. + 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 @@ -3349,31 +3170,25 @@ spec: containers. properties: exec: - description: One and only one of the following - should be specified. Exec specifies the - action to take. + description: |- + One and only one of the following should be specified. + 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. + 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. + 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 httpGet: @@ -3381,10 +3196,9 @@ spec: 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. + 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 @@ -3416,43 +3230,41 @@ spec: 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. + 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. + 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' + 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. + 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. + 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. TCP hooks not yet - supported TODO: implement a realistic - TCP lifecycle hook' + description: |- + TCPSocket specifies an action involving a TCP port. + TCP hooks not yet supported properties: host: description: 'Optional: Host name to @@ -3462,81 +3274,69 @@ spec: 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. + 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 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' + 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. + 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 + 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 targetContainerName: - description: If set, the name of the container - from PodSpec that this ephemeral container - targets. The ephemeral container will be run - in the namespaces (IPC, PID, etc) of this - container. If not set then the ephemeral container - is run in whatever namespaces are shared for - the pod. Note that the container runtime must - support this feature. + description: |- + If set, the name of the container from PodSpec that this ephemeral container targets. + The ephemeral container will be run in the namespaces (IPC, PID, etc) of this container. + If not set then the ephemeral container is run in whatever namespaces are shared + for the pod. Note that the container runtime must support this feature. type: string 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.' + 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. + 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. + 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 @@ -3560,48 +3360,45 @@ spec: type: object type: array volumeMounts: - description: Pod volumes to mount into the container's - filesystem. Cannot be updated. + 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 + 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 + 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. + 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). + 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). + 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. + 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 @@ -3609,24 +3406,24 @@ spec: 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. + 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 type: array hostAliases: - description: HostAliases is an optional list of hosts - and IPs that will be injected into the pod's hosts - file if specified. This is only valid for non-hostNetwork - pods. + description: |- + HostAliases is an optional list of hosts and IPs that will be injected into the pod's hosts + file if specified. This is only valid for non-hostNetwork pods. items: - description: HostAlias holds the mapping between - IP and hostnames that will be injected as an entry - in the pod's hosts file. + description: |- + HostAlias holds the mapping between IP and hostnames that will be injected as an entry in the + pod's hosts file. properties: hostnames: description: Hostnames for the above IP address. @@ -3639,100 +3436,93 @@ spec: type: object type: array hostIPC: - description: 'Use the host''s ipc namespace. Optional: - Default to false.' + description: |- + Use the host's ipc namespace. + Optional: Default to false. type: boolean hostNetwork: - description: Host networking requested for this pod. - Use the host's network namespace. If this option - is set, the ports that will be used must be specified. + description: |- + Host networking requested for this pod. Use the host's network namespace. + If this option is set, the ports that will be used must be specified. Default to false. type: boolean hostPID: - description: 'Use the host''s pid namespace. Optional: - Default to false.' + description: |- + Use the host's pid namespace. + Optional: Default to false. type: boolean hostname: - description: Specifies the hostname of the Pod If - not specified, the pod's hostname will be set to - a system-defined value. + description: |- + Specifies the hostname of the Pod + If not specified, the pod's hostname will be set to a system-defined value. type: string imagePullSecrets: - description: 'ImagePullSecrets is an optional list - of references to secrets in the same namespace to - use for pulling any of the images used by this PodSpec. - If specified, these secrets will be passed to individual - puller implementations for them to use. For example, - in the case of docker, only DockerConfig type secrets - are honored. More info: https://kubernetes.io/docs/concepts/containers/images#specifying-imagepullsecrets-on-a-pod' + description: |- + ImagePullSecrets is an optional list of references to secrets in the same namespace to use for pulling any of the images used by this PodSpec. + If specified, these secrets will be passed to individual puller implementations for them to use. For example, + in the case of docker, only DockerConfig type secrets are honored. + More info: https://kubernetes.io/docs/concepts/containers/images#specifying-imagepullsecrets-on-a-pod items: - description: LocalObjectReference contains enough - information to let you locate the referenced object - inside the same namespace. + 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?' + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string type: object type: array initContainers: - description: 'List of initialization containers belonging - to the pod. Init containers are executed in order - prior to containers being started. If any init container - fails, the pod is considered to have failed and - is handled according to its restartPolicy. The name - for an init container or normal container must be - unique among all containers. Init containers may - not have Lifecycle actions, Readiness probes, Liveness - probes, or Startup probes. The resourceRequirements - of an init container are taken into account during - scheduling by finding the highest request/limit - for each resource type, and then using the max of - of that value or the sum of the normal containers. - Limits are applied to init containers in a similar - fashion. Init containers cannot currently be added - or removed. Cannot be updated. More info: https://kubernetes.io/docs/concepts/workloads/pods/init-containers/' + description: |- + List of initialization containers belonging to the pod. + Init containers are executed in order prior to containers being started. If any + init container fails, the pod is considered to have failed and is handled according + to its restartPolicy. The name for an init container or normal container must be + unique among all containers. + Init containers may not have Lifecycle actions, Readiness probes, Liveness probes, or Startup probes. + The resourceRequirements of an init container are taken into account during scheduling + by finding the highest request/limit for each resource type, and then using the max of + of that value or the sum of the normal containers. Limits are applied to init containers + in a similar fashion. + Init containers cannot currently be added or removed. + Cannot be updated. + More info: https://kubernetes.io/docs/concepts/workloads/pods/init-containers/ items: description: A single application container that you want to run within a pod. properties: args: - description: 'Arguments to the entrypoint. The - docker 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. The - $(VAR_NAME) syntax can be escaped with a double - $$, ie: $$(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' + description: |- + Arguments to the entrypoint. + The docker 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. The $(VAR_NAME) syntax + can be escaped with a double $$, ie: $$(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 docker 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. The $(VAR_NAME) - syntax can be escaped with a double $$, ie: - $$(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' + description: |- + Entrypoint array. Not executed within a shell. + The docker 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. The $(VAR_NAME) syntax + can be escaped with a double $$, ie: $$(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. + description: |- + List of environment variables to set in the container. + Cannot be updated. items: description: EnvVar represents an environment variable present in a Container. @@ -3742,17 +3532,15 @@ spec: Must be a C_IDENTIFIER. type: string value: - description: 'Variable references $(VAR_NAME) - are expanded using the previous 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. The $(VAR_NAME) syntax can - be escaped with a double $$, ie: $$(VAR_NAME). - Escaped references will never be expanded, - regardless of whether the variable exists - or not. Defaults to "".' + description: |- + Variable references $(VAR_NAME) are expanded + using the previous 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. The $(VAR_NAME) + syntax can be escaped with a double $$, ie: $$(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 @@ -3766,10 +3554,9 @@ spec: description: The key to select. type: string name: - description: 'Name of the referent. + 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 @@ -3780,11 +3567,9 @@ spec: - key type: object 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.' + 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 @@ -3800,12 +3585,9 @@ spec: - fieldPath type: object 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.' + 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: @@ -3838,10 +3620,9 @@ spec: secret key. type: string name: - description: 'Name of the referent. + 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 @@ -3856,15 +3637,13 @@ spec: 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. + 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 @@ -3873,10 +3652,9 @@ spec: description: The ConfigMap to select from properties: name: - description: 'Name of the referent. + 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 @@ -3892,10 +3670,9 @@ spec: description: The Secret to select from properties: name: - description: 'Name of the referent. + 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 @@ -3905,51 +3682,44 @@ spec: type: object type: array image: - description: 'Docker 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.' + description: |- + Docker 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' + 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. + 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' + 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: One and only one of the - following should be specified. Exec - specifies the action to take. + description: |- + One and only one of the following should be specified. + 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. + 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 @@ -3959,10 +3729,9 @@ spec: 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. + 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 @@ -3994,23 +3763,23 @@ spec: 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. + 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. + description: |- + Scheme to use for connecting to the host. + Defaults to HTTP. type: string required: - port type: object tcpSocket: - description: 'TCPSocket specifies an - action involving a TCP port. TCP hooks - not yet supported TODO: implement - a realistic TCP lifecycle hook' + description: |- + TCPSocket specifies an action involving a TCP port. + TCP hooks not yet supported properties: host: description: 'Optional: Host name @@ -4021,52 +3790,40 @@ spec: 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. + 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 reason for termination is - passed to the handler. The Pod''s termination - grace period countdown begins before the - PreStop hooked is executed. Regardless - of the outcome of the handler, the container - will eventually terminate within the Pod''s - termination grace period. 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' + 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 reason for termination is passed to the + handler. The Pod's termination grace period countdown begins before the + PreStop hooked is executed. Regardless of the outcome of the handler, the + container will eventually terminate within the Pod's termination grace + period. 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: One and only one of the - following should be specified. Exec - specifies the action to take. + description: |- + One and only one of the following should be specified. + 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. + 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 @@ -4076,10 +3833,9 @@ spec: 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. + 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 @@ -4111,23 +3867,23 @@ spec: 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. + 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. + description: |- + Scheme to use for connecting to the host. + Defaults to HTTP. type: string required: - port type: object tcpSocket: - description: 'TCPSocket specifies an - action involving a TCP port. TCP hooks - not yet supported TODO: implement - a realistic TCP lifecycle hook' + description: |- + TCPSocket specifies an action involving a TCP port. + TCP hooks not yet supported properties: host: description: 'Optional: Host name @@ -4138,10 +3894,10 @@ spec: 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. + 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 @@ -4149,36 +3905,32 @@ spec: type: object type: object livenessProbe: - description: 'Periodic probe of container liveness. + 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' + Cannot be updated. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes properties: exec: - description: One and only one of the following - should be specified. Exec specifies the - action to take. + description: |- + One and only one of the following should be specified. + 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. + 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. + 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 httpGet: @@ -4186,10 +3938,9 @@ spec: 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. + 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 @@ -4221,43 +3972,41 @@ spec: 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. + 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. + 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' + 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. + 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. + 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. TCP hooks not yet - supported TODO: implement a realistic - TCP lifecycle hook' + description: |- + TCPSocket specifies an action involving a TCP port. + TCP hooks not yet supported properties: host: description: 'Optional: Host name to @@ -4267,46 +4016,45 @@ spec: 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. + 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 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' + 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. + 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. Exposing a port here gives the - system additional information about the network - connections a container uses, but is primarily - informational. 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. Cannot be - updated. + description: |- + List of ports to expose from the container. Exposing a port here gives + the system additional information about the network connections a + container uses, but is primarily informational. 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. + 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. + 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: @@ -4314,25 +4062,24 @@ spec: 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. + 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. + 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". + description: |- + Protocol for port. Must be UDP, TCP, or SCTP. + Defaults to "TCP". type: string required: - containerPort @@ -4343,37 +4090,32 @@ spec: - 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' + 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: One and only one of the following - should be specified. Exec specifies the - action to take. + description: |- + One and only one of the following should be specified. + 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. + 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. + 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 httpGet: @@ -4381,10 +4123,9 @@ spec: 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. + 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 @@ -4416,43 +4157,41 @@ spec: 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. + 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. + 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' + 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. + 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. + 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. TCP hooks not yet - supported TODO: implement a realistic - TCP lifecycle hook' + description: |- + TCPSocket specifies an action involving a TCP port. + TCP hooks not yet supported properties: host: description: 'Optional: Host name to @@ -4462,25 +4201,27 @@ spec: 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. + 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 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' + 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 resources: - description: 'Compute Resources required by - this container. Cannot be updated. More info: - https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/' + description: |- + Compute Resources required by this container. + Cannot be updated. + More info: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/ properties: limits: additionalProperties: @@ -4489,9 +4230,9 @@ spec: - 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-compute-resources-container/' + description: |- + Limits describes the maximum amount of compute resources allowed. + More info: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/ type: object requests: additionalProperties: @@ -4500,33 +4241,32 @@ spec: - 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. More info: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/' + 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. + More info: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/ type: object type: object securityContext: - description: 'Security options the pod should - run with. More info: https://kubernetes.io/docs/concepts/policy/security-context/ - More info: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/' + description: |- + Security options the pod should run with. + More info: https://kubernetes.io/docs/concepts/policy/security-context/ + 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' + 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 type: boolean capabilities: - description: The capabilities to add/drop - when running containers. Defaults to the - default set of capabilities granted by - the container runtime. + description: |- + The capabilities to add/drop when running containers. + Defaults to the default set of capabilities granted by the container runtime. properties: add: description: Added capabilities @@ -4544,66 +4284,54 @@ spec: 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. + description: |- + Run container in privileged mode. + Processes in privileged containers are essentially equivalent to root on the host. + Defaults to false. 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. + 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. type: string readOnlyRootFilesystem: - description: Whether this container has - a read-only root filesystem. Default is - false. + description: |- + Whether this container has a read-only root filesystem. + Default is false. 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. + 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. 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. + 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. + 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. 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. + 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. properties: level: description: Level is SELinux level @@ -4623,49 +4351,41 @@ spec: 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. + 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. 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 only be set - if type is "Localhost". + 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 only be set if type is "Localhost". 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." + 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. 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. + 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. 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. + 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 @@ -4673,57 +4393,45 @@ spec: spec to use. type: string 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. + 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. - This is a beta feature enabled by the StartupProbe - feature flag. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + 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. + This is a beta feature enabled by the StartupProbe feature flag. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes properties: exec: - description: One and only one of the following - should be specified. Exec specifies the - action to take. + description: |- + One and only one of the following should be specified. + 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. + 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. + 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 httpGet: @@ -4731,10 +4439,9 @@ spec: 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. + 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 @@ -4766,43 +4473,41 @@ spec: 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. + 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. + 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' + 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. + 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. + 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. TCP hooks not yet - supported TODO: implement a realistic - TCP lifecycle hook' + description: |- + TCPSocket specifies an action involving a TCP port. + TCP hooks not yet supported properties: host: description: 'Optional: Host name to @@ -4812,71 +4517,62 @@ spec: 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. + 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 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' + 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. + 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 + 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.' + 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. + 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. + 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 @@ -4900,48 +4596,45 @@ spec: type: object type: array volumeMounts: - description: Pod volumes to mount into the container's - filesystem. Cannot be updated. + 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 + 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 + 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. + 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). + 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). + 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. + 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 @@ -4949,28 +4642,29 @@ spec: 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. + 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 type: array nodeName: - description: NodeName 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. + description: |- + NodeName 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. type: string nodeSelector: additionalProperties: type: string - description: 'NodeSelector is a selector which must - be true for the pod to fit on a node. Selector which - must match a node''s labels for the pod to be scheduled - on that node. More info: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/' + description: |- + NodeSelector is a selector which must be true for the pod to fit on a node. + Selector which must match a node's labels for the pod to be scheduled on that node. + More info: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/ type: object overhead: additionalProperties: @@ -4979,54 +4673,47 @@ spec: - 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: 'Overhead represents the resource overhead - associated with running a pod for a given RuntimeClass. - This field will be autopopulated at admission time - by the RuntimeClass admission controller. If the - RuntimeClass admission controller is enabled, overhead - must not be set in Pod create requests. The RuntimeClass - admission controller will reject Pod create requests - which have the overhead already set. If RuntimeClass - is configured and selected in the PodSpec, Overhead - will be set to the value defined in the corresponding - RuntimeClass, otherwise it will remain unset and - treated as zero. More info: https://git.k8s.io/enhancements/keps/sig-node/20190226-pod-overhead.md - This field is alpha-level as of Kubernetes v1.16, - and is only honored by servers that enable the PodOverhead - feature.' + description: |- + Overhead represents the resource overhead associated with running a pod for a given RuntimeClass. + This field will be autopopulated at admission time by the RuntimeClass admission controller. If + the RuntimeClass admission controller is enabled, overhead must not be set in Pod create requests. + The RuntimeClass admission controller will reject Pod create requests which have the overhead already + set. If RuntimeClass is configured and selected in the PodSpec, Overhead will be set to the value + defined in the corresponding RuntimeClass, otherwise it will remain unset and treated as zero. + More info: https://git.k8s.io/enhancements/keps/sig-node/20190226-pod-overhead.md + This field is alpha-level as of Kubernetes v1.16, and is only honored by servers that enable the PodOverhead feature. type: object preemptionPolicy: - description: PreemptionPolicy is the Policy for preempting - pods with lower priority. One of Never, PreemptLowerPriority. - Defaults to PreemptLowerPriority if unset. This - field is beta-level, gated by the NonPreemptingPriority - feature-gate. + description: |- + PreemptionPolicy is the Policy for preempting pods with lower priority. + One of Never, PreemptLowerPriority. + Defaults to PreemptLowerPriority if unset. + This field is beta-level, gated by the NonPreemptingPriority feature-gate. type: string priority: - description: The priority value. Various system components - use this field to find the priority of the pod. - When Priority Admission Controller is enabled, it - prevents users from setting this field. The admission - controller populates this field from PriorityClassName. + description: |- + The priority value. Various system components use this field to find the + priority of the pod. When Priority Admission Controller is enabled, it + prevents users from setting this field. The admission controller populates + this field from PriorityClassName. The higher the value, the higher the priority. format: int32 type: integer priorityClassName: - description: If specified, indicates the pod's priority. - "system-node-critical" and "system-cluster-critical" - are two special keywords which indicate the highest - priorities with the former being the highest priority. - Any other name must be defined by creating a PriorityClass - object with that name. If not specified, the pod - priority will be default or zero if there is no + description: |- + If specified, indicates the pod's priority. "system-node-critical" and + "system-cluster-critical" are two special keywords which indicate the + highest priorities with the former being the highest priority. Any other + name must be defined by creating a PriorityClass object with that name. + If not specified, the pod priority will be default or zero if there is no default. type: string readinessGates: - description: 'If specified, all readiness gates will - be evaluated for pod readiness. A pod is ready when - all its containers are ready AND all conditions - specified in the readiness gates have status equal - to "True" More info: https://git.k8s.io/enhancements/keps/sig-network/0007-pod-ready%2B%2B.md' + description: |- + If specified, all readiness gates will be evaluated for pod readiness. + A pod is ready when all its containers are ready AND + all conditions specified in the readiness gates have status equal to "True" + More info: https://git.k8s.io/enhancements/keps/sig-network/0007-pod-ready%2B%2B.md items: description: PodReadinessGate contains the reference to a pod condition @@ -5041,95 +4728,87 @@ spec: type: object type: array restartPolicy: - description: 'Restart policy for all containers within - the pod. One of Always, OnFailure, Never. Default - to Always. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#restart-policy' + description: |- + Restart policy for all containers within the pod. + One of Always, OnFailure, Never. + Default to Always. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#restart-policy type: string runtimeClassName: - description: 'RuntimeClassName refers to a RuntimeClass - object in the node.k8s.io group, which should be - used to run this pod. If no RuntimeClass resource - matches the named class, the pod will not be run. - If unset or empty, the "legacy" RuntimeClass will - be used, which is an implicit class with an empty - definition that uses the default runtime handler. + description: |- + RuntimeClassName refers to a RuntimeClass object in the node.k8s.io group, which should be used + to run this pod. If no RuntimeClass resource matches the named class, the pod will not be run. + If unset or empty, the "legacy" RuntimeClass will be used, which is an implicit class with an + empty definition that uses the default runtime handler. More info: https://git.k8s.io/enhancements/keps/sig-node/runtime-class.md - This is a beta feature as of Kubernetes v1.14.' + This is a beta feature as of Kubernetes v1.14. type: string schedulerName: - description: If specified, the pod will be dispatched - by specified scheduler. If not specified, the pod - will be dispatched by default scheduler. + description: |- + If specified, the pod will be dispatched by specified scheduler. + If not specified, the pod will be dispatched by default scheduler. type: string securityContext: - description: 'SecurityContext holds pod-level security - attributes and common container settings. Optional: - Defaults to empty. See type description for default - values of each field.' + description: |- + SecurityContext holds pod-level security attributes and common container settings. + Optional: Defaults to empty. See type description for default values of each field. properties: fsGroup: - description: "A special supplemental group that - applies to all containers in a pod. Some volume - types allow the Kubelet to change the ownership - of that volume to be owned by the pod: \n 1. - The owning GID will be the FSGroup 2. The setgid - bit is set (new files created in the volume - will be owned by FSGroup) 3. The permission - bits are OR'd with rw-rw---- \n If unset, the - Kubelet will not modify the ownership and permissions - of any volume." + description: |- + A special supplemental group that applies to all containers in a pod. + Some volume types allow the Kubelet to change the ownership of that volume + to be owned by the pod: + + 1. The owning GID will be the FSGroup + 2. The setgid bit is set (new files created in the volume will be owned by FSGroup) + 3. The permission bits are OR'd with rw-rw---- + + If unset, the Kubelet will not modify the ownership and permissions of any volume. format: int64 type: integer fsGroupChangePolicy: - description: 'fsGroupChangePolicy defines behavior - of changing ownership and permission of the - volume before being exposed inside Pod. This - field will only apply to volume types which - support fsGroup based ownership(and permissions). - It will have no effect on ephemeral volume types - such as: secret, configmaps and emptydir. Valid - values are "OnRootMismatch" and "Always". If - not specified defaults to "Always".' + description: |- + fsGroupChangePolicy defines behavior of changing ownership and permission of the volume + before being exposed inside Pod. This field will only apply to + volume types which support fsGroup based ownership(and permissions). + It will have no effect on ephemeral volume types such as: secret, configmaps + and emptydir. + Valid values are "OnRootMismatch" and "Always". If not specified defaults to "Always". type: string runAsGroup: - description: The GID to run the entrypoint of - the container process. Uses runtime default - if unset. May also be set in SecurityContext. If - set in both SecurityContext and PodSecurityContext, - the value specified in SecurityContext takes - precedence for that container. + description: |- + The GID to run the entrypoint of the container process. + Uses runtime default if unset. + May also be set in SecurityContext. If set in both SecurityContext and + PodSecurityContext, the value specified in SecurityContext takes precedence + for that container. 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 SecurityContext. If set - in both SecurityContext and PodSecurityContext, - the value specified in SecurityContext takes - precedence. + 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 SecurityContext. 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 SecurityContext. If set in both SecurityContext - and PodSecurityContext, the value specified - in SecurityContext takes precedence for that - container. + 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 SecurityContext. If set in both SecurityContext and + PodSecurityContext, the value specified in SecurityContext takes precedence + for that container. format: int64 type: integer seLinuxOptions: - description: The SELinux context to be applied - to all containers. If unspecified, the container - runtime will allocate a random SELinux context - for each container. May also be set in SecurityContext. If - set in both SecurityContext and PodSecurityContext, - the value specified in SecurityContext takes - precedence for that container. + description: |- + The SELinux context to be applied to all containers. + If unspecified, the container runtime will allocate a random SELinux context for each + container. May also be set in SecurityContext. If set in + both SecurityContext and PodSecurityContext, the value specified in SecurityContext + takes precedence for that container. properties: level: description: Level is SELinux level label @@ -5153,40 +4832,37 @@ spec: containers in this pod. 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 only be set - if type is "Localhost". + 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 only be set if type is "Localhost". 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." + 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. type: string required: - type type: object supplementalGroups: - description: A list of groups applied to the first - process run in each container, in addition to - the container's primary GID. If unspecified, - no groups will be added to any container. + description: |- + A list of groups applied to the first process run in each container, in addition + to the container's primary GID. If unspecified, no groups will be added to + any container. items: format: int64 type: integer type: array sysctls: - description: Sysctls hold a list of namespaced - sysctls used for the pod. Pods with unsupported - sysctls (by the container runtime) might fail - to launch. + description: |- + Sysctls hold a list of namespaced sysctls used for the pod. Pods with unsupported + sysctls (by the container runtime) might fail to launch. items: description: Sysctl defines a kernel parameter to be set @@ -5203,146 +4879,124 @@ spec: type: object type: array windowsOptions: - description: The Windows specific settings applied - to all containers. If unspecified, the options - within a container's SecurityContext will be - used. If set in both SecurityContext and PodSecurityContext, - the value specified in SecurityContext takes - precedence. + description: |- + The Windows specific settings applied to all containers. + If unspecified, the options within a container's SecurityContext will be used. + If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence. 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. + 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 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. + 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 serviceAccount: - description: 'DeprecatedServiceAccount is a depreciated - alias for ServiceAccountName. Deprecated: Use serviceAccountName - instead.' + description: |- + DeprecatedServiceAccount is a depreciated alias for ServiceAccountName. + Deprecated: Use serviceAccountName instead. type: string serviceAccountName: - description: 'ServiceAccountName is the name of the - ServiceAccount to use to run this pod. More info: - https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/' + description: |- + ServiceAccountName is the name of the ServiceAccount to use to run this pod. + More info: https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/ type: string setHostnameAsFQDN: - description: If true the pod's hostname will be configured - as the pod's FQDN, rather than the leaf name (the - default). In Linux containers, this means setting - the FQDN in the hostname field of the kernel (the - nodename field of struct utsname). In Windows containers, - this means setting the registry value of hostname - for the registry key HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters - to FQDN. If a pod does not have FQDN, this has no - effect. Default to false. + description: |- + If true the pod's hostname will be configured as the pod's FQDN, rather than the leaf name (the default). + In Linux containers, this means setting the FQDN in the hostname field of the kernel (the nodename field of struct utsname). + In Windows containers, this means setting the registry value of hostname for the registry key HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters to FQDN. + If a pod does not have FQDN, this has no effect. + Default to false. type: boolean shareProcessNamespace: - description: 'Share a single process namespace between - all of the containers in a pod. When this is set - containers will be able to view and signal processes - from other containers in the same pod, and the first - process in each container will not be assigned PID - 1. HostPID and ShareProcessNamespace cannot both - be set. Optional: Default to false.' + description: |- + Share a single process namespace between all of the containers in a pod. + When this is set containers will be able to view and signal processes from other containers + in the same pod, and the first process in each container will not be assigned PID 1. + HostPID and ShareProcessNamespace cannot both be set. + Optional: Default to false. type: boolean subdomain: - description: If specified, the fully qualified Pod - hostname will be "...svc.". If not specified, the pod will not have - a domainname at all. + description: |- + If specified, the fully qualified Pod hostname will be "...svc.". + If not specified, the pod will not have a domainname at all. type: string terminationGracePeriodSeconds: - description: Optional duration in seconds the pod - needs to terminate gracefully. May be decreased - in delete request. Value must be non-negative integer. - The value zero indicates delete immediately. If - this value is nil, the default grace period will - be used instead. 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. Defaults to 30 seconds. + description: |- + Optional duration in seconds the pod needs to terminate gracefully. May be decreased in delete request. + Value must be non-negative integer. The value zero indicates delete immediately. + If this value is nil, the default grace period will be used instead. + 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. + Defaults to 30 seconds. format: int64 type: integer tolerations: description: If specified, the pod's tolerations. items: - description: The pod this Toleration is attached - to tolerates any taint that matches the triple - using the matching operator - . + description: |- + The pod this Toleration is attached to tolerates any taint that matches + the triple using the matching operator . properties: effect: - description: Effect indicates the taint effect - to match. Empty means match all taint effects. - When specified, allowed values are NoSchedule, - PreferNoSchedule and NoExecute. + description: |- + Effect indicates the taint effect to match. Empty means match all taint effects. + When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute. type: string key: - description: Key is the taint key that the toleration - applies to. Empty means match all taint keys. - If the key is empty, operator must be Exists; - this combination means to match all values - and all keys. + description: |- + Key is the taint key that the toleration applies to. Empty means match all taint keys. + If the key is empty, operator must be Exists; this combination means to match all values and all keys. type: string operator: - description: Operator represents a key's relationship - to the value. Valid operators are Exists and - Equal. Defaults to Equal. Exists is equivalent - to wildcard for value, so that a pod can tolerate - all taints of a particular category. + description: |- + Operator represents a key's relationship to the value. + Valid operators are Exists and Equal. Defaults to Equal. + Exists is equivalent to wildcard for value, so that a pod can + tolerate all taints of a particular category. type: string tolerationSeconds: - description: TolerationSeconds represents the - period of time the toleration (which must - be of effect NoExecute, otherwise this field - is ignored) tolerates the taint. By default, - it is not set, which means tolerate the taint - forever (do not evict). Zero and negative - values will be treated as 0 (evict immediately) - by the system. + description: |- + TolerationSeconds represents the period of time the toleration (which must be + of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default, + it is not set, which means tolerate the taint forever (do not evict). Zero and + negative values will be treated as 0 (evict immediately) by the system. format: int64 type: integer value: - description: Value is the taint value the toleration - matches to. If the operator is Exists, the - value should be empty, otherwise just a regular - string. + description: |- + Value is the taint value the toleration matches to. + If the operator is Exists, the value should be empty, otherwise just a regular string. type: string type: object type: array topologySpreadConstraints: - description: TopologySpreadConstraints describes how - a group of pods ought to spread across topology - domains. Scheduler will schedule pods in a way which - abides by the constraints. All topologySpreadConstraints - are ANDed. + description: |- + TopologySpreadConstraints describes how a group of pods ought to spread across topology + domains. Scheduler will schedule pods in a way which abides by the constraints. + All topologySpreadConstraints are ANDed. items: description: TopologySpreadConstraint specifies how to spread matching pods among the given topology. properties: labelSelector: - description: LabelSelector is used to find matching - pods. Pods that match this label selector - are counted to determine the number of pods + description: |- + LabelSelector is used to find matching pods. + Pods that match this label selector are counted to determine the number of pods in their corresponding topology domain. properties: matchExpressions: @@ -5350,30 +5004,25 @@ spec: 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. + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. properties: key: description: key is the label key that the selector applies 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: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. type: string values: - description: values is an array of - string values. If the operator is - In or NotIn, the values array must - be non-empty. If the operator is - Exists or DoesNotExist, the values - array must be empty. This array - is replaced during a strategic merge - patch. + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. items: type: string type: array @@ -5385,66 +5034,58 @@ spec: 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. + 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 maxSkew: - description: 'MaxSkew describes the degree to - which pods may be unevenly distributed. When - `whenUnsatisfiable=DoNotSchedule`, it is the - maximum permitted difference between the number - of matching pods in the target topology and - the global minimum. For example, in a 3-zone - cluster, MaxSkew is set to 1, and pods with - the same labelSelector spread as 1/1/0: | - zone1 | zone2 | zone3 | | P | P | | - - if MaxSkew is 1, incoming pod can only be - scheduled to zone3 to become 1/1/1; scheduling - it onto zone1(zone2) would make the ActualSkew(2-0) - on zone1(zone2) violate MaxSkew(1). - if MaxSkew - is 2, incoming pod can be scheduled onto any - zone. When `whenUnsatisfiable=ScheduleAnyway`, - it is used to give higher precedence to topologies - that satisfy it. It''s a required field. Default - value is 1 and 0 is not allowed.' + description: |- + MaxSkew describes the degree to which pods may be unevenly distributed. + When `whenUnsatisfiable=DoNotSchedule`, it is the maximum permitted difference + between the number of matching pods in the target topology and the global minimum. + For example, in a 3-zone cluster, MaxSkew is set to 1, and pods with the same + labelSelector spread as 1/1/0: + | zone1 | zone2 | zone3 | + | P | P | | + - if MaxSkew is 1, incoming pod can only be scheduled to zone3 to become 1/1/1; + scheduling it onto zone1(zone2) would make the ActualSkew(2-0) on zone1(zone2) + violate MaxSkew(1). + - if MaxSkew is 2, incoming pod can be scheduled onto any zone. + When `whenUnsatisfiable=ScheduleAnyway`, it is used to give higher precedence + to topologies that satisfy it. + It's a required field. Default value is 1 and 0 is not allowed. format: int32 type: integer topologyKey: - description: TopologyKey is the key of node - labels. Nodes that have a label with this - key and identical values are considered to - be in the same topology. We consider each - as a "bucket", and try to put - balanced number of pods into each bucket. + description: |- + TopologyKey is the key of node labels. Nodes that have a label with this key + and identical values are considered to be in the same topology. + We consider each as a "bucket", and try to put balanced number + of pods into each bucket. It's a required field. type: string whenUnsatisfiable: - description: 'WhenUnsatisfiable indicates how - to deal with a pod if it doesn''t satisfy - the spread constraint. - DoNotSchedule (default) - tells the scheduler not to schedule it. - - ScheduleAnyway tells the scheduler to schedule - the pod in any location, but giving higher - precedence to topologies that would help reduce - the skew. A constraint is considered "Unsatisfiable" - for an incoming pod if and only if every possible - node assigment for that pod would violate - "MaxSkew" on some topology. For example, in - a 3-zone cluster, MaxSkew is set to 1, and - pods with the same labelSelector spread as - 3/1/1: | zone1 | zone2 | zone3 | | P P P | P | P | - If WhenUnsatisfiable is set to DoNotSchedule, - incoming pod can only be scheduled to zone2(zone3) - to become 3/2/1(3/1/2) as ActualSkew(2-1) - on zone2(zone3) satisfies MaxSkew(1). In other - words, the cluster can still be imbalanced, - but scheduler won''t make it *more* imbalanced. - It''s a required field.' + description: |- + WhenUnsatisfiable indicates how to deal with a pod if it doesn't satisfy + the spread constraint. + - DoNotSchedule (default) tells the scheduler not to schedule it. + - ScheduleAnyway tells the scheduler to schedule the pod in any location, + but giving higher precedence to topologies that would help reduce the + skew. + A constraint is considered "Unsatisfiable" for an incoming pod + if and only if every possible node assigment for that pod would violate + "MaxSkew" on some topology. + For example, in a 3-zone cluster, MaxSkew is set to 1, and pods with the same + labelSelector spread as 3/1/1: + | zone1 | zone2 | zone3 | + | P P P | P | P | + If WhenUnsatisfiable is set to DoNotSchedule, incoming pod can only be scheduled + to zone2(zone3) to become 3/2/1(3/1/2) as ActualSkew(2-1) on zone2(zone3) satisfies + MaxSkew(1). In other words, the cluster can still be imbalanced, but scheduler + won't make it *more* imbalanced. + It's a required field. type: string required: - maxSkew @@ -5457,49 +5098,45 @@ spec: - whenUnsatisfiable x-kubernetes-list-type: map volumes: - description: 'List of volumes that can be mounted - by containers belonging to the pod. More info: https://kubernetes.io/docs/concepts/storage/volumes' + description: |- + List of volumes that can be mounted by containers belonging to the pod. + More info: https://kubernetes.io/docs/concepts/storage/volumes 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' + 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: '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' + description: |- + 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 type: string partition: - description: '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).' + description: |- + 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: 'Specify "true" to force and - set the ReadOnly property in VolumeMounts - to "true". If omitted, the default is - "false". More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore' + description: |- + Specify "true" to force and set the ReadOnly property in VolumeMounts to "true". + If omitted, the default is "false". + More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore type: boolean volumeID: - description: 'Unique ID of the persistent - disk resource in AWS (Amazon EBS volume). - More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore' + description: |- + 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 @@ -5522,11 +5159,10 @@ spec: blob storage type: string fsType: - description: 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. + description: |- + 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: 'Expected values Shared: multiple @@ -5536,9 +5172,9 @@ spec: availability set). defaults to shared' type: string readOnly: - description: Defaults to false (read/write). - ReadOnly here will force the ReadOnly - setting in VolumeMounts. + description: |- + Defaults to false (read/write). ReadOnly here will force + the ReadOnly setting in VolumeMounts. type: boolean required: - diskName @@ -5550,9 +5186,9 @@ spec: the pod. properties: readOnly: - description: Defaults to false (read/write). - ReadOnly here will force the ReadOnly - setting in VolumeMounts. + description: |- + Defaults to false (read/write). ReadOnly here will force + the ReadOnly setting in VolumeMounts. type: boolean secretName: description: the name of secret that contains @@ -5570,8 +5206,9 @@ spec: on the host that shares a pod's lifetime properties: monitors: - description: 'Required: Monitors is a collection - of Ceph monitors More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' + description: |- + 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 @@ -5581,69 +5218,68 @@ spec: default is /' type: string readOnly: - description: 'Optional: Defaults to false - (read/write). ReadOnly here will force + description: |- + 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' + More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it type: boolean secretFile: - description: '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' + description: |- + 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: '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' + description: |- + 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. + 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 user: - description: 'Optional: User is the rados - user name, default is admin More info: - https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' + description: |- + 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' + 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: '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' + description: |- + 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: 'Optional: Defaults to false - (read/write). ReadOnly here will force + description: |- + Optional: 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' + More info: https://examples.k8s.io/mysql-cinder-pd/README.md type: boolean secretRef: - description: 'Optional: points to a secret - object containing parameters used to connect - to OpenStack.' + description: |- + Optional: points to a secret object containing parameters used to connect + to OpenStack. properties: name: - description: 'Name of the referent. + 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 volumeID: - description: 'volume id used to identify - the volume in cinder. More info: https://examples.k8s.io/mysql-cinder-pd/README.md' + description: |- + volume id used to identify the volume in cinder. + More info: https://examples.k8s.io/mysql-cinder-pd/README.md type: string required: - volumeID @@ -5653,33 +5289,25 @@ spec: that should populate this volume properties: defaultMode: - description: '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.' + description: |- + 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: 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 '..'. + description: |- + 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. @@ -5688,27 +5316,21 @@ spec: description: The key to project. type: string 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.' + 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: 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 '..'. + description: |- + 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 @@ -5716,10 +5338,9 @@ spec: 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?' + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names type: string optional: description: Specify whether the ConfigMap @@ -5732,47 +5353,41 @@ spec: 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. + 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: Filesystem type 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. + description: |- + Filesystem type 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. + 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. + 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 readOnly: - description: Specifies a read-only configuration - for the volume. Defaults to false (read/write). + description: |- + 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. + 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 @@ -5783,20 +5398,15 @@ spec: 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.' + 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: @@ -5826,19 +5436,13 @@ spec: - fieldPath type: object 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.' + 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: @@ -5851,11 +5455,9 @@ spec: 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.' + 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: @@ -5884,146 +5486,127 @@ spec: 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' + 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: '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' + description: |- + 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: '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: - http://kubernetes.io/docs/user-guide/volumes#emptydir' + description: |- + 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: http://kubernetes.io/docs/user-guide/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 - (Alpha feature). 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." + description: |- + Ephemeral represents a volume that is handled by a cluster storage driver (Alpha feature). + 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. properties: readOnly: - description: Specifies a read-only configuration - for the volume. Defaults to false (read/write). + description: |- + Specifies a read-only configuration for the volume. + Defaults to false (read/write). type: boolean 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 + 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. - \n Required, must not be nil." + + 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. + 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 + 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' + 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: 'This field can be - used to specify either: * An existing - VolumeSnapshot object (snapshot.storage.k8s.io/VolumeSnapshot - - Beta) * An existing PVC (PersistentVolumeClaim) - * An existing custom resource/object - that implements data population - (Alpha) In order to use VolumeSnapshot - object types, the appropriate - feature gate must be enabled (VolumeSnapshotDataSource - or AnyVolumeDataSource) 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. If the specified - data source is not supported, - the volume will not be created - and the failure will be reported - as an event. In the future, we - plan to support more data source - types and the behavior of the - provisioner may change.' + description: |- + This field can be used to specify either: + * An existing VolumeSnapshot object (snapshot.storage.k8s.io/VolumeSnapshot - Beta) + * An existing PVC (PersistentVolumeClaim) + * An existing custom resource/object that implements data population (Alpha) + In order to use VolumeSnapshot object types, the appropriate feature gate + must be enabled (VolumeSnapshotDataSource or AnyVolumeDataSource) + 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. + If the specified data source is not supported, the volume will + not be created and the failure will be reported as an event. + In the future, we plan to support more data source types and the behavior + of the provisioner may change. 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. + 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 @@ -6038,9 +5621,9 @@ spec: - name type: object resources: - description: 'Resources represents - the minimum resources the volume - should have. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#resources' + description: |- + Resources represents the minimum resources the volume should have. + More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#resources properties: limits: additionalProperties: @@ -6049,10 +5632,9 @@ spec: - 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-compute-resources-container/' + description: |- + Limits describes the maximum amount of compute resources allowed. + More info: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/ type: object requests: additionalProperties: @@ -6061,14 +5643,11 @@ spec: - 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. More info: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/' + 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. + More info: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/ type: object type: object selector: @@ -6081,10 +5660,8 @@ spec: requirements. The requirements are ANDed. items: - description: A label selector - requirement is a selector - that contains values, a - key, and an operator that + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. properties: key: @@ -6093,24 +5670,15 @@ spec: applies 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: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. type: string values: - description: values is - an array of string values. - If the operator is In - or NotIn, the values - array must be non-empty. - If the operator is Exists - or DoesNotExist, the - values array must be - empty. This array is - replaced during a strategic + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic merge patch. items: type: string @@ -6123,29 +5691,21 @@ spec: 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. + 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 storageClassName: - description: 'Name of the StorageClass - required by the claim. More info: - https://kubernetes.io/docs/concepts/storage/persistent-volumes#class-1' + description: |- + 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. + 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 @@ -6163,22 +5723,19 @@ spec: and then exposed to the pod. properties: fsType: - description: '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' + description: |- + 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 lun: description: 'Optional: FC target lun number' format: int32 type: integer readOnly: - description: 'Optional: Defaults to false - (read/write). ReadOnly here will force - the ReadOnly setting in VolumeMounts.' + description: |- + Optional: Defaults to false (read/write). ReadOnly here will force + the ReadOnly setting in VolumeMounts. type: boolean targetWWNs: description: 'Optional: FC target worldwide @@ -6187,29 +5744,27 @@ spec: type: string type: array wwids: - description: 'Optional: FC volume world - wide identifiers (wwids) Either wwids - or combination of targetWWNs and lun must - be set, but not both simultaneously.' + description: |- + 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. + 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: 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. + description: |- + 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: @@ -6218,24 +5773,22 @@ spec: if any.' type: object readOnly: - description: 'Optional: Defaults to false - (read/write). ReadOnly here will force - the ReadOnly setting in VolumeMounts.' + description: |- + Optional: Defaults to false (read/write). ReadOnly here will force + the ReadOnly setting in VolumeMounts. type: boolean secretRef: - description: '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.' + description: |- + 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. + 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 required: @@ -6248,9 +5801,9 @@ spec: running properties: datasetName: - description: Name of the dataset stored - as metadata -> name on the dataset for - Flocker should be considered as deprecated + description: |- + Name of the dataset stored as metadata -> name on the dataset for Flocker + should be considered as deprecated type: string datasetUUID: description: UUID of the dataset. This is @@ -6258,61 +5811,54 @@ spec: 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' + 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: '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' + description: |- + 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 type: string partition: - description: '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' + description: |- + 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: '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' + description: |- + 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' + 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.' + 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: 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. + description: |- + 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 URL @@ -6325,59 +5871,58 @@ spec: - 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' + 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: 'EndpointsName is the endpoint - name that details Glusterfs topology. - More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod' + description: |- + EndpointsName 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' + 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' + 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.' + 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 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' + 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' + 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' + 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: whether support iSCSI Discovery @@ -6388,63 +5933,56 @@ spec: CHAP authentication type: boolean fsType: - description: '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' + description: |- + 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 type: string initiatorName: - description: Custom iSCSI Initiator Name. - If initiatorName is specified with iscsiInterface - simultaneously, new iSCSI interface : will be created - for the connection. + description: |- + Custom iSCSI Initiator Name. + If initiatorName is specified with iscsiInterface simultaneously, new iSCSI interface + : will be created for the connection. type: string iqn: description: Target iSCSI Qualified Name. type: string iscsiInterface: - description: iSCSI Interface Name that uses - an iSCSI transport. Defaults to 'default' - (tcp). + description: |- + iSCSI Interface Name that uses an iSCSI transport. + Defaults to 'default' (tcp). type: string lun: description: iSCSI Target Lun number. format: int32 type: integer portals: - description: 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). + description: |- + 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. + description: |- + ReadOnly here will force the ReadOnly setting in VolumeMounts. + Defaults to false. type: boolean secretRef: description: CHAP Secret for iSCSI target and initiator authentication properties: name: - description: 'Name of the referent. + 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 targetPortal: - description: 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). + description: |- + 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 @@ -6452,47 +5990,52 @@ spec: - targetPortal type: object name: - description: 'Volume''s name. Must be a DNS_LABEL - and unique within the pod. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' + description: |- + Volume's name. + 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' + 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' + 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' + 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' + 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' + 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' + 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: Will force the ReadOnly setting - in VolumeMounts. Default false. + description: |- + Will force the ReadOnly setting in VolumeMounts. + Default false. type: boolean required: - claimName @@ -6503,11 +6046,10 @@ spec: and mounted on kubelets host machine properties: fsType: - description: 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. + description: |- + 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: ID that identifies Photon Controller @@ -6522,16 +6064,15 @@ spec: 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. + 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: Defaults to false (read/write). - ReadOnly here will force the ReadOnly - setting in VolumeMounts. + description: |- + Defaults to false (read/write). ReadOnly here will force + the ReadOnly setting in VolumeMounts. type: boolean volumeID: description: VolumeID uniquely identifies @@ -6545,17 +6086,13 @@ spec: secrets, configmaps, and downward API properties: defaultMode: - description: 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. + description: |- + 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: @@ -6569,23 +6106,14 @@ spec: configMap data to project properties: items: - description: 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 - '..'. + description: |- + 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. @@ -6595,34 +6123,21 @@ spec: project. type: string 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.' + 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: 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 '..'. + description: |- + 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 @@ -6630,10 +6145,9 @@ spec: type: object type: array name: - description: 'Name of the referent. + 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 @@ -6678,24 +6192,13 @@ spec: - fieldPath type: object 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.' + 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: @@ -6711,13 +6214,9 @@ spec: ''..''' 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.' + 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 @@ -6752,22 +6251,14 @@ spec: secret data to project properties: items: - description: 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 '..'. + description: |- + 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. @@ -6777,34 +6268,21 @@ spec: project. type: string 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.' + 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: 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 '..'. + description: |- + 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 @@ -6812,10 +6290,9 @@ spec: type: object type: array name: - description: 'Name of the referent. + 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 @@ -6827,37 +6304,26 @@ spec: 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. + 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. + 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. + description: |- + Path is the path relative to the mount point of the file to project the + token into. type: string required: - path @@ -6872,30 +6338,29 @@ spec: on the host that shares a pod's lifetime properties: group: - description: Group to map volume access - to Default is no 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. + 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 + 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 + 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 + description: |- + User to map volume access to Defaults to serivceaccount user type: string volume: @@ -6907,59 +6372,65 @@ spec: - 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' + 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: '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' + description: |- + 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 type: string image: - description: 'The rados image name. More - info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + description: |- + 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' + 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: 'A collection of Ceph monitors. - More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + description: |- + 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: 'The rados pool name. Default - is rbd. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + description: |- + 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' + 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' + 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. + 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 user: - description: 'The rados user name. Default - is admin. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + description: |- + 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 @@ -6971,10 +6442,11 @@ spec: nodes. properties: fsType: - description: Filesystem type to mount. Must - be a filesystem type supported by the - host operating system. Ex. "ext4", "xfs", - "ntfs". Default is "xfs". + description: |- + 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: The host address of the ScaleIO @@ -6985,21 +6457,19 @@ spec: Domain for the configured storage. type: string readOnly: - description: Defaults to false (read/write). - ReadOnly here will force the ReadOnly - setting in VolumeMounts. + description: |- + 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. + 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. + 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 sslEnabled: @@ -7007,9 +6477,9 @@ spec: communication with Gateway, default false type: boolean storageMode: - description: Indicates whether the storage - for a volume should be ThickProvisioned - or ThinProvisioned. Default is ThinProvisioned. + description: |- + Indicates whether the storage for a volume should be ThickProvisioned or ThinProvisioned. + Default is ThinProvisioned. type: string storagePool: description: The ScaleIO Storage Pool associated @@ -7020,9 +6490,9 @@ spec: as configured in ScaleIO. type: string volumeName: - description: The name of a volume already - created in the ScaleIO system that is - associated with this volume source. + description: |- + The name of a volume already created in the ScaleIO system + that is associated with this volume source. type: string required: - gateway @@ -7030,37 +6500,30 @@ spec: - system type: object secret: - description: 'Secret represents a secret that - should populate this volume. More info: https://kubernetes.io/docs/concepts/storage/volumes#secret' + description: |- + Secret represents a secret that should populate this volume. + More info: https://kubernetes.io/docs/concepts/storage/volumes#secret properties: defaultMode: - description: '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.' + description: |- + 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: 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 '..'. + description: |- + 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. @@ -7069,27 +6532,21 @@ spec: description: The key to project. type: string 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.' + 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: 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 '..'. + description: |- + 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 @@ -7101,8 +6558,9 @@ spec: or its keys must be defined type: boolean secretName: - description: 'Name of the secret in the - pod''s namespace to use. More info: https://kubernetes.io/docs/concepts/storage/volumes#secret' + description: |- + 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: @@ -7111,47 +6569,40 @@ spec: nodes. properties: fsType: - description: 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. + description: |- + 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: Defaults to false (read/write). - ReadOnly here will force the ReadOnly - setting in VolumeMounts. + description: |- + 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. + 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. + 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 volumeName: - description: VolumeName is the human-readable - name of the StorageOS volume. Volume + 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. + 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: @@ -7160,11 +6611,10 @@ spec: machine properties: fsType: - description: 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. + description: |- + 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: Storage Policy Based Management @@ -7191,16 +6641,16 @@ spec: type: object type: object ttlSecondsAfterFinished: - description: ttlSecondsAfterFinished limits the lifetime of - a Job that has finished execution (either Complete or Failed). - If this field is set, ttlSecondsAfterFinished after the - Job finishes, it is eligible to be automatically deleted. - When the Job is being deleted, its lifecycle guarantees - (e.g. finalizers) will be honored. If this field is unset, - the Job won't be automatically deleted. If this field is - set to zero, the Job becomes eligible to be deleted immediately - after it finishes. This field is alpha-level and is only - honored by servers that enable the TTLAfterFinished feature. + description: |- + ttlSecondsAfterFinished limits the lifetime of a Job that has finished + execution (either Complete or Failed). If this field is set, + ttlSecondsAfterFinished after the Job finishes, it is eligible to be + automatically deleted. When the Job is being deleted, its lifecycle + guarantees (e.g. finalizers) will be honored. If this field is unset, + the Job won't be automatically deleted. If this field is set to zero, + the Job becomes eligible to be deleted immediately after it finishes. + This field is alpha-level and is only honored by servers that enable the + TTLAfterFinished feature. format: int32 type: integer required: @@ -7218,6 +6668,15 @@ spec: - bar - foo type: object + longerStringArray: + description: This tests string alias slice item validation. + items: + description: This tests that markers that are allowed on both fields + and types are applied to types + minLength: 4 + type: string + minItems: 3 + type: array mapOfArraysOfFloats: additionalProperties: items: @@ -7292,6 +6751,20 @@ spec: - foo type: object x-kubernetes-map-type: atomic + nestedStructWithSeveralFieldsDoubleMarked: + description: |- + A struct that can only be entirely replaced via a nested type and + field markers. + properties: + bar: + type: boolean + foo: + type: string + required: + - bar + - foo + type: object + x-kubernetes-map-type: atomic nestedassociativeList: description: This tests that associative lists work via a nested type. items: @@ -7313,8 +6786,9 @@ spec: - secondary x-kubernetes-list-type: map noReallySuspend: - description: This flag is like suspend, but for when you really mean - it. It helps test the +kubebuilder:validation:Type marker. + description: |- + This flag is like suspend, but for when you really mean it. + It helps test the +kubebuilder:validation:Type marker. type: string patternObject: description: This tests that pattern validator is properly applied. @@ -7331,11 +6805,18 @@ spec: schemaless: description: This tests that the schemaless marker works startingDeadlineSeconds: - description: Optional deadline in seconds for starting the job if - it misses scheduled time for any reason. Missed jobs executions - will be counted as failed ones. + description: |- + Optional deadline in seconds for starting the job if it misses scheduled + time for any reason. Missed jobs executions will be counted as failed ones. format: int64 type: integer + stringPair: + description: This tests string slice validation. + items: + type: string + maxItems: 2 + minItems: 2 + type: array stringSliceData: additionalProperties: items: @@ -7351,6 +6832,14 @@ spec: - message: must have even length rule: self.size() % 2 == 0 - rule: "true" + stringWithEvenLengthAndMessageExpression: + description: Test of the expression-based validation with messageExpression + marker. + type: string + x-kubernetes-validations: + - messageExpression: '''Length has to be even but is '' + len(self.stringWithEvenLengthAndMessageExpression) + + '' instead''' + rule: self.size() % 2 == 0 structWithSeveralFields: description: A struct that can only be entirely replaced properties: @@ -7364,14 +6853,15 @@ spec: type: object x-kubernetes-map-type: atomic successfulJobsHistoryLimit: - description: The number of successful finished jobs to retain. This - is a pointer to distinguish between explicit zero and not specified. + description: |- + The number of successful finished jobs to retain. + This is a pointer to distinguish between explicit zero and not specified. format: int32 type: integer suspend: - description: This flag tells the controller to suspend subsequent - executions, it does not apply to already started executions. Defaults - to false. + description: |- + This flag tells the controller to suspend subsequent executions, it does + not apply to already started executions. Defaults to false. type: boolean twoOfAKindPart0: description: This tests that markers that are allowed on both fields @@ -7412,22 +6902,36 @@ spec: - baz - binaryName - canBeNull + - defaultedEmptyMap + - defaultedEmptyObject + - defaultedEmptySlice - defaultedObject - defaultedSlice - defaultedString + - doubleDefaultedString - embeddedResource + - explicitlyRequiredKubebuilder + - explicitlyRequiredKubernetes - float64WithValidations - floatWithValidations - foo - int32WithValidations - intWithValidations - jobTemplate + - kubernetesDefaultedEmptyMap + - kubernetesDefaultedEmptyObject + - kubernetesDefaultedEmptySlice + - kubernetesDefaultedObject + - kubernetesDefaultedSlice + - kubernetesDefaultedString - mapOfInfo - nestedMapOfInfo - nestedStructWithSeveralFields + - nestedStructWithSeveralFieldsDoubleMarked - nestedassociativeList - patternObject - schedule + - stringPair - structWithSeveralFields - twoOfAKindPart0 - twoOfAKindPart1 @@ -7436,81 +6940,71 @@ spec: - unprunedFomTypeAndField - unprunedJSON type: object + x-kubernetes-validations: + - fieldPath: .forbiddenInt + message: forbiddenInt is not allowed + reason: FieldValueForbidden + rule: has(oldSelf.forbiddenInt) || !has(self.forbiddenInt) status: description: CronJobStatus defines the observed state of CronJob properties: active: description: A list of pointers to currently running jobs. 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. 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 - .' + description: ObjectReference contains enough information to let + you inspect or modify the referred object. 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.' + 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. type: string kind: - description: 'Kind of the referent. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + 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' + 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/' + 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' + 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' + description: |- + UID of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#uids type: string type: object type: array duration: - description: Duration has a custom Marshaler but no markers. We want - the CRD generation to infer type information from the go types and - ignore the presense of the Marshaler. + description: |- + Duration has a custom Marshaler but no markers. + We want the CRD generation to infer type information + from the go types and ignore the presense of the Marshaler. properties: value: - description: A Duration represents the elapsed time between two - instants as an int64 nanosecond count. The representation limits - the largest representable duration to approximately 290 years. + description: |- + A Duration represents the elapsed time between two instants + as an int64 nanosecond count. The representation limits the + largest representable duration to approximately 290 years. format: int64 type: integer required: @@ -7525,8 +7019,9 @@ spec: started job type: string lastScheduleMicroTime: - description: Information about the last time the job was successfully - scheduled, with microsecond precision. + description: |- + Information about the last time the job was successfully scheduled, + with microsecond precision. format: date-time type: string lastScheduleTime: @@ -7546,14 +7041,19 @@ spec: description: CronJob is the Schema for the cronjobs 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' + 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' + 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 @@ -7589,14 +7089,19 @@ spec: description: CronJob is the Schema for the cronjobs 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' + 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' + 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 diff --git a/pkg/crd/testdata/testdata.kubebuilder.io_jobs.yaml b/pkg/crd/testdata/testdata.kubebuilder.io_jobs.yaml index e4eed5463..37a7da98c 100644 --- a/pkg/crd/testdata/testdata.kubebuilder.io_jobs.yaml +++ b/pkg/crd/testdata/testdata.kubebuilder.io_jobs.yaml @@ -4,7 +4,6 @@ kind: CustomResourceDefinition metadata: annotations: controller-gen.kubebuilder.io/version: (devel) - creationTimestamp: null name: jobs.testdata.kubebuilder.io spec: group: testdata.kubebuilder.io @@ -21,14 +20,19 @@ spec: description: Job is the Schema for the jobs 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' + 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' + 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 diff --git a/pkg/crd/testdata/wrong_annotation_format/cronjob_types.go b/pkg/crd/testdata/wrong_annotation_format/cronjob_types.go new file mode 100644 index 000000000..7c84ab81e --- /dev/null +++ b/pkg/crd/testdata/wrong_annotation_format/cronjob_types.go @@ -0,0 +1,522 @@ +/* + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// TODO(directxman12): test this across both versions (right now we're just +// trusting k/k conversion, which is probably fine though) + +//go:generate ../../../.run-controller-gen.sh crd:ignoreUnexportedFields=true,allowDangerousTypes=true paths=./;./deprecated;./unserved;./job/... output:dir=. + +// +groupName=testdata.kubebuilder.io +// +versionName=v1 +package cronjob + +import ( + "encoding/json" + "fmt" + "net/url" + "time" + + batchv1beta1 "k8s.io/api/batch/v1beta1" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/util/intstr" +) + +// 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. + +// CronJobSpec defines the desired state of CronJob +type CronJobSpec struct { + // The schedule in Cron format, see https://en.wikipedia.org/wiki/Cron. + Schedule string `json:"schedule"` + + // Optional deadline in seconds for starting the job if it misses scheduled + // time for any reason. Missed jobs executions will be counted as failed ones. + // +optional + StartingDeadlineSeconds *int64 `json:"startingDeadlineSeconds,omitempty"` + + // Specifies how to treat concurrent executions of a Job. + // Valid values are: + // - "Allow" (default): allows CronJobs to run concurrently; + // - "Forbid": forbids concurrent runs, skipping next run if previous run hasn't finished yet; + // - "Replace": cancels currently running job and replaces it with a new one + // +optional + ConcurrencyPolicy ConcurrencyPolicy `json:"concurrencyPolicy,omitempty"` + + // This flag tells the controller to suspend subsequent executions, it does + // not apply to already started executions. Defaults to false. + // +optional + Suspend *bool `json:"suspend,omitempty"` + + // This tests that non-serialized fields aren't included in the schema. + InternalData string `json:"-"` + + // This flag is like suspend, but for when you really mean it. + // It helps test the +kubebuilder:validation:Type marker. + // +optional + NoReallySuspend *TotallyABool `json:"noReallySuspend,omitempty"` + + // This tests byte slice schema generation. + BinaryName []byte `json:"binaryName"` + + // This tests that nullable works correctly + // +nullable + CanBeNull string `json:"canBeNull"` + + // Specifies the job that will be created when executing a CronJob. + JobTemplate batchv1beta1.JobTemplateSpec `json:"jobTemplate"` + + // The number of successful finished jobs to retain. + // This is a pointer to distinguish between explicit zero and not specified. + // +optional + SuccessfulJobsHistoryLimit *int32 `json:"successfulJobsHistoryLimit,omitempty"` + + // The number of failed finished jobs to retain. + // This is a pointer to distinguish between explicit zero and not specified. + // +optional + FailedJobsHistoryLimit *int32 `json:"failedJobsHistoryLimit,omitempty"` + + // This tests byte slices are allowed as map values. + ByteSliceData map[string][]byte `json:"byteSliceData,omitempty"` + + // This tests string slices are allowed as map values. + StringSliceData map[string][]string `json:"stringSliceData,omitempty"` + + // This tests pointers are allowed as map values. + PtrData map[string]*string `json:"ptrData,omitempty"` + + // This tests that markers that are allowed on both fields and types are applied to fields + // +kubebuilder:validation:MinLength=4 + TwoOfAKindPart0 string `json:"twoOfAKindPart0"` + + // This tests that markers that are allowed on both fields and types are applied to types + TwoOfAKindPart1 LongerString `json:"twoOfAKindPart1"` + + // This tests that primitive defaulting can be performed. + // +kubebuilder:default=forty-two + DefaultedString string `json:"defaultedString"` + + // This tests that slice defaulting can be performed. + // +kubebuilder:default={a,b} + DefaultedSlice []string `json:"defaultedSlice"` + + // This tests that object defaulting can be performed. + // +kubebuilder:default={{nested: {foo: "baz", bar: true}},{nested: {bar: false}}} + DefaultedObject []RootObject `json:"defaultedObject"` + + // This tests that pattern validator is properly applied. + // +kubebuilder:validation:Pattern=`^$|^((https):\/\/?)[^\s()<>]+(?:\([\w\d]+\)|([^[:punct:]\s]|\/?))$` + PatternObject string `json:"patternObject"` + + // +kubebuilder:validation:EmbeddedResource + // +kubebuilder:validation:nullable + EmbeddedResource runtime.RawExtension `json:"embeddedResource"` + + // +kubebuilder:validation:nullable + // +kubebuilder:pruning:PreserveUnknownFields + UnprunedJSON NestedObject `json:"unprunedJSON"` + + // +kubebuilder:pruning:PreserveUnknownFields + // +kubebuilder:validation:EmbeddedResource + // +kubebuilder:validation:nullable + UnprunedEmbeddedResource runtime.RawExtension `json:"unprunedEmbeddedResource"` + + // This tests that a type-level pruning marker works. + UnprunedFromType Preserved `json:"unprunedFomType"` + + // This tests that a type-level pruning marker combined with a field-level pruning marker works. + // +kubebuilder:pruning:PreserveUnknownFields + UnprunedFromTypeAndField Preserved `json:"unprunedFomTypeAndField"` + + // This tests that associative lists work. + // +listType=map + // +listMapKey=name + // +listMapKey=secondary + AssociativeList []AssociativeType `json:"associativeList"` + + // This tests that associative lists work via a nested type. + NestedAssociativeList NestedAssociativeList `json:"nestedassociativeList"` + + // A map that allows different actors to manage different fields + // +mapType=granular + MapOfInfo map[string][]byte `json:"mapOfInfo"` + + // A map that allows different actors to manage different fields via a nested type. + NestedMapOfInfo NestedMapOfInfo `json:"nestedMapOfInfo"` + + // A struct that can only be entirely replaced + // +structType=atomic + StructWithSeveralFields NestedObject `json:"structWithSeveralFields"` + + // A struct that can only be entirely replaced via a nested type. + // +structType=atomic + NestedStructWithSeveralFields NestedStructWithSeveralFields `json:"nestedStructWithSeveralFields"` + + // This tests that type references are properly flattened + // +kubebuilder:validation:optional + JustNestedObject *JustNestedObject `json:"justNestedObject,omitempty"` + + // This tests that min/max properties work + MinMaxProperties MinMaxObject `json:"minMaxProperties,omitempty"` + + // This tests that the schemaless marker works + // +kubebuilder:validation:Schemaless + Schemaless []byte `json:"schemaless,omitempty"` + + // This tests that an IntOrString can also have a pattern attached + // to it. + // This can be useful if you want to limit the string to a perecentage or integer. + // The XIntOrString marker is a requirement for having a pattern on this type. + // +kubebuilder:validation:XIntOrString + // +kubebuilder:validation:Pattern="^((100|[0-9]{1,2})%|[0-9]+)$" + IntOrStringWithAPattern *intstr.IntOrString `json:"intOrStringWithAPattern,omitempty"` + + // Checks that nested maps work + NestedMap map[string]map[string]string `json:"nestedMap,omitempty"` + + // Checks that multiply-nested maps work + NestedNestedMap map[string]map[string]map[string]string `json:"nestedNestedMap,omitempty"` + + // Checks that maps containing types that contain maps work + ContainsNestedMapMap map[string]ContainsNestedMap `json:"nestedMapInStruct,omitempty"` + + // Maps of arrays of things-that-aren’t-strings are permitted + MapOfArraysOfFloats map[string][]bool `json:"mapOfArraysOfFloats,omitempty"` + + // +kubebuilder:validation:Minimum=-0.5 + // +kubebuilder:validation:Maximum=1.5 + // +kubebuilder:validation:MultipleOf=0.5 + FloatWithValidations float64 `json:"floatWithValidations"` + + // +kubebuilder:validation:Minimum=-0.5 + // +kubebuilder:validation:Maximum=1.5 + // +kubebuilder:validation:MultipleOf=0.5 + Float64WithValidations float64 `json:"float64WithValidations"` + + // +kubebuilder:validation:Minimum=-2 + // +kubebuilder:validation:Maximum=2 + // +kubebuilder:validation:MultipleOf=2 + IntWithValidations int `json:"intWithValidations"` + + // +kubebuilder:validation:Minimum=-2 + // +kubebuilder:validation:Maximum=2 + // +kubebuilder:validation:MultipleOf=2 + Int32WithValidations int32 `json:"int32WithValidations"` + + // This tests that unexported fields are skipped in the schema generation + unexportedField string + + // This tests that both unexported and exported inline fields are not skipped in the schema generation + unexportedStruct `json:",inline"` + ExportedStruct `json:",inline"` + + // Test of the expression-based validation rule marker, with optional message. + // +kubebuilder:validation:XValidation:rule="self.size() % 2 == 0",message="must have even length" + // +kubebuilder:validation:XValidation:rule="true" + StringWithEvenLength string `json:"stringWithEvenLength,omitempty"` + + // Checks that fixed-length arrays work + Array [3]int `json:"array,omitempty"` + + // Checks that arrays work when the type contains a composite literal + ArrayUsingCompositeLiteral [len(struct{ X [3]int }{}.X)]string `json:"arrayUsingCompositeLiteral,omitempty"` +} + +type ContainsNestedMap struct { + InnerMap map[string]string `json:"innerMap,omitempty"` +} + +// +kubebuilder:validation:Type=object +// +kubebuilder:pruning:PreserveUnknownFields +type Preserved struct { + ConcreteField string `json:"concreteField"` + Rest map[string]interface{} `json:"-"` +} + +func (p *Preserved) UnmarshalJSON(data []byte) error { + if err := json.Unmarshal(data, &p.Rest); err != nil { + return err + } + conc, found := p.Rest["concreteField"] + if !found { + return nil + } + concStr, isStr := conc.(string) + if !isStr { + return fmt.Errorf("concreteField was not string") + } + delete(p.Rest, "concreteField") + p.ConcreteField = concStr + return nil +} + +func (p *Preserved) MarshalJSON() ([]byte, error) { + full := make(map[string]interface{}, len(p.Rest)+1) + for k, v := range p.Rest { + full[k] = v + } + full["concreteField"] = p.ConcreteField + return json.Marshal(full) +} + +type NestedObject struct { + Foo string `json:"foo"` + Bar bool `json:"bar"` +} + +// +structType=atomic +type NestedStructWithSeveralFields NestedObject + +type JustNestedObject NestedObject + +// +kubebuilder:validation:MinProperties=1 +// +kubebuilder:validation:MaxProperties=2 +type MinMaxObject struct { + Foo string `json:"foo,omitempty"` + Bar string `json:"bar,omitempty"` + Baz string `json:"baz,omitempty"` +} + +type unexportedStruct struct { + // This tests that exported fields are not skipped in the schema generation + Foo string `json:"foo"` + + // This tests that unexported fields are skipped in the schema generation + bar string +} + +type ExportedStruct struct { + // This tests that exported fields are not skipped in the schema generation + Baz string `json:"baz"` + + // This tests that unexported fields are skipped in the schema generation + qux string +} + +type RootObject struct { + Nested NestedObject `json:"nested"` +} + +type AssociativeType struct { + Name string `json:"name"` + Secondary int `json:"secondary"` + Foo string `json:"foo"` +} + +// +listType=map +// +listMapKey=name +// +listMapKey=secondary +type NestedAssociativeList []AssociativeType + +// +mapType=granular +type NestedMapOfInfo map[string][]byte + +// +kubebuilder:validation:MinLength=4 +// This tests that markers that are allowed on both fields and types are applied to types +type LongerString string + +// use an explicit type marker to verify that apply-first markers generate properly + +// +kubebuilder:validation:Type=string +// TotallyABool is a bool that serializes as a string. +type TotallyABool bool + +func (t TotallyABool) MarshalJSON() ([]byte, error) { + if t { + return []byte(`"true"`), nil + } else { + return []byte(`"false"`), nil + } +} + +func (t *TotallyABool) UnmarshalJSON(in []byte) error { + switch string(in) { + case `"true"`: + *t = true + return nil + case `"false"`: + *t = false + default: + return fmt.Errorf("bad TotallyABool value %q", string(in)) + } + return nil +} + +// +kubebuilder:validation:Type=string +// URL wraps url.URL. +// It has custom json marshal methods that enable it to be used in K8s CRDs +// such that the CRD resource will have the URL but operator code can can work with url.URL struct +type URL struct { + url.URL +} + +func (u *URL) MarshalJSON() ([]byte, error) { + return []byte(fmt.Sprintf("%q", u.String())), nil +} + +func (u *URL) UnmarshalJSON(b []byte) error { + var ref string + if err := json.Unmarshal(b, &ref); err != nil { + return err + } + if ref == "" { + *u = URL{} + return nil + } + + r, err := url.Parse(ref) + if err != nil { + return err + } else if r != nil { + *u = URL{*r} + } else { + *u = URL{} + } + return nil +} + +func (u *URL) String() string { + if u == nil { + return "" + } + return u.URL.String() +} + +// +kubebuilder:validation:Type=string +// URL2 is an alias of url.URL. +// It has custom json marshal methods that enable it to be used in K8s CRDs +// such that the CRD resource will have the URL but operator code can can work with url.URL struct +type URL2 url.URL + +func (u *URL2) MarshalJSON() ([]byte, error) { + return []byte(fmt.Sprintf("%q", u.String())), nil +} + +func (u *URL2) UnmarshalJSON(b []byte) error { + var ref string + if err := json.Unmarshal(b, &ref); err != nil { + return err + } + if ref == "" { + *u = URL2{} + return nil + } + + r, err := url.Parse(ref) + if err != nil { + return err + } else if r != nil { + *u = *(*URL2)(r) + } else { + *u = URL2{} + } + return nil +} + +func (u *URL2) String() string { + if u == nil { + return "" + } + return (*url.URL)(u).String() +} + +// Duration has a custom Marshaler but no markers. +// We want the CRD generation to infer type information +// from the go types and ignore the presense of the Marshaler. +type Duration struct { + Value time.Duration `json:"value"` +} + +func (d Duration) MarshalJSON() ([]byte, error) { + type durationWithoutUnmarshaler Duration + return json.Marshal(durationWithoutUnmarshaler(d)) +} + +var _ json.Marshaler = Duration{} + +// ConcurrencyPolicy describes how the job will be handled. +// Only one of the following concurrent policies may be specified. +// If none of the following policies is specified, the default one +// is AllowConcurrent. +// +kubebuilder:validation:Enum=Allow;Forbid;Replace +type ConcurrencyPolicy string + +const ( + // AllowConcurrent allows CronJobs to run concurrently. + AllowConcurrent ConcurrencyPolicy = "Allow" + + // ForbidConcurrent forbids concurrent runs, skipping next run if previous + // hasn't finished yet. + ForbidConcurrent ConcurrencyPolicy = "Forbid" + + // ReplaceConcurrent cancels currently running job and replaces it with a new one. + ReplaceConcurrent ConcurrencyPolicy = "Replace" +) + +// CronJobStatus defines the observed state of CronJob +type CronJobStatus struct { + // INSERT ADDITIONAL STATUS FIELD - define observed state of cluster + // Important: Run "make" to regenerate code after modifying this file + + // A list of pointers to currently running jobs. + // +optional + Active []corev1.ObjectReference `json:"active,omitempty"` + + // Information when was the last time the job was successfully scheduled. + // +optional + LastScheduleTime *metav1.Time `json:"lastScheduleTime,omitempty"` + + // Information about the last time the job was successfully scheduled, + // with microsecond precision. + // +optional + LastScheduleMicroTime *metav1.MicroTime `json:"lastScheduleMicroTime,omitempty"` + + // LastActiveLogURL specifies the logging url for the last started job + // +optional + LastActiveLogURL *URL `json:"lastActiveLogURL,omitempty"` + + // LastActiveLogURL2 specifies the logging url for the last started job + // +optional + LastActiveLogURL2 *URL2 `json:"lastActiveLogURL2,omitempty"` + + Runtime *Duration `json:"duration,omitempty"` +} + +// +kubebuilder:object:root=true +// +kubebuilder:subresource:status +// +kubebuilder:resource:singular=mycronjob +// +kubebuilder:storageversion +// +kubebuilder:metadata:annotations="api-approved.kubernetes.io:https://github.com/kubernetes-sigs/controller-tools";"cert-manager.io/inject-ca-from-secret:cert-manager/cert-manager-webhook-ca" + +// CronJob is the Schema for the cronjobs API +type CronJob struct { + /* + */ + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec CronJobSpec `json:"spec,omitempty"` + Status CronJobStatus `json:"status,omitempty"` +} + +// +kubebuilder:object:root=true + +// CronJobList contains a list of CronJob +type CronJobList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []CronJob `json:"items"` +} diff --git a/pkg/crd/zz_generated.markerhelp.go b/pkg/crd/zz_generated.markerhelp.go index fee8de4b9..c1aa3853f 100644 --- a/pkg/crd/zz_generated.markerhelp.go +++ b/pkg/crd/zz_generated.markerhelp.go @@ -1,5 +1,4 @@ //go:build !ignore_autogenerated -// +build !ignore_autogenerated /* Copyright2019 The Kubernetes Authors. @@ -34,25 +33,37 @@ func (Generator) Help() *markers.DefinitionHelp { }, FieldHelp: map[string]markers.DetailedHelp{ "IgnoreUnexportedFields": { - Summary: "indicates that we should skip unexported fields. ", + Summary: "indicates that we should skip unexported fields.", Details: "Left unspecified, the default is false.", }, "AllowDangerousTypes": { - Summary: "allows types which are usually omitted from CRD generation because they are not recommended. ", - Details: "Currently the following additional types are allowed when this is true: float32 float64 \n Left unspecified, the default is false", + Summary: "allows types which are usually omitted from CRD generation", + Details: "because they are not recommended.\n\n\nCurrently the following additional types are allowed when this is true:\nfloat32\nfloat64\n\n\nLeft unspecified, the default is false", }, "MaxDescLen": { - Summary: "specifies the maximum description length for fields in CRD's OpenAPI schema. ", - Details: "0 indicates drop the description for all fields completely. n indicates limit the description to at most n characters and truncate the description to closest sentence boundary if it exceeds n characters.", + Summary: "specifies the maximum description length for fields in CRD's OpenAPI schema.", + Details: "0 indicates drop the description for all fields completely.\nn indicates limit the description to at most n characters and truncate the description to\nclosest sentence boundary if it exceeds n characters.", }, "CRDVersions": { - Summary: "specifies the target API versions of the CRD type itself to generate. Defaults to v1. ", - Details: "Currently, the only supported value is v1. \n The first version listed will be assumed to be the \"default\" version and will not get a version suffix in the output filename. \n You'll need to use \"v1\" to get support for features like defaulting, along with an API server that supports it (Kubernetes 1.16+).", + Summary: "specifies the target API versions of the CRD type itself to", + Details: "generate. Defaults to v1.\n\n\nCurrently, the only supported value is v1.\n\n\nThe first version listed will be assumed to be the \"default\" version and\nwill not get a version suffix in the output filename.\n\n\nYou'll need to use \"v1\" to get support for features like defaulting,\nalong with an API server that supports it (Kubernetes 1.16+).", }, "GenerateEmbeddedObjectMeta": { Summary: "specifies if any embedded ObjectMeta in the CRD should be generated", Details: "", }, + "HeaderFile": { + Summary: "specifies the header text (e.g. license) to prepend to generated files.", + Details: "", + }, + "Year": { + Summary: "specifies the year to substitute for \" YEAR\" in the header file.", + Details: "", + }, + "DeprecatedV1beta1CompatibilityPreserveUnknownFields": { + Summary: "indicates whether", + Details: "or not we should turn off field pruning for this resource.\n\n\nSpecifies spec.preserveUnknownFields value that is false and omitted by default.\nThis value can only be specified for CustomResourceDefinitions that were created with\n`apiextensions.k8s.io/v1beta1`.\n\n\nThe field can be set for compatiblity reasons, although strongly discouraged, resource\nauthors should move to a structural OpenAPI schema instead.\n\n\nSee https://kubernetes.io/docs/tasks/extend-kubernetes/custom-resources/custom-resource-definitions/#field-pruning\nfor more information about field pruning and v1beta1 resources compatibility.", + }, }, } } diff --git a/pkg/deepcopy/deepcopy_integration_test.go b/pkg/deepcopy/deepcopy_integration_test.go index a81ef190d..608d6e720 100644 --- a/pkg/deepcopy/deepcopy_integration_test.go +++ b/pkg/deepcopy/deepcopy_integration_test.go @@ -18,7 +18,6 @@ package deepcopy_test import ( "io" - "io/ioutil" "os" "sort" @@ -97,7 +96,7 @@ var _ = Describe("CRD Generation From Parsing to CustomResourceDefinition", func Expect(outContents).NotTo(BeNil()) By("loading the desired code") - expectedFile, err := ioutil.ReadFile("zz_generated.deepcopy.go") + expectedFile, err := os.ReadFile("zz_generated.deepcopy.go") Expect(err).NotTo(HaveOccurred()) By("comparing the two") diff --git a/pkg/deepcopy/gen.go b/pkg/deepcopy/gen.go index 7e674a80a..a85cc8577 100644 --- a/pkg/deepcopy/gen.go +++ b/pkg/deepcopy/gen.go @@ -176,7 +176,6 @@ type ObjectGenCtx struct { func writeHeader(pkg *loader.Package, out io.Writer, packageName string, imports *importsList, headerText string) { // NB(directxman12): blank line after build tags to distinguish them from comments _, err := fmt.Fprintf(out, `//go:build !ignore_autogenerated -// +build !ignore_autogenerated %[3]s @@ -192,7 +191,6 @@ import ( if err != nil { pkg.AddError(err) } - } // generateForPackage generates DeepCopy and runtime.Object implementations for diff --git a/pkg/deepcopy/testdata/cronjob_types.go b/pkg/deepcopy/testdata/cronjob_types.go index 567b2aecc..2bd3bb22a 100644 --- a/pkg/deepcopy/testdata/cronjob_types.go +++ b/pkg/deepcopy/testdata/cronjob_types.go @@ -125,6 +125,7 @@ type SpecificCases struct { MapWithNamedKeys map[TotallyAString]int `json:"mapWithNamedKeys"` MapToPtrToDeepCopyIntoRefType map[string]*DeepCopyIntoRef `json:"mapToPtrToDeepCopyIntoRefType"` MapToDeepCopyIntoRefType map[string]DeepCopyIntoRef `json:"mapToDeepCopyIntoRefType"` + MapNested map[string]map[string]string `json:"mapNested,omitempty"` // other slice types SliceToDeepCopyPtr []DeepCopyPtr `json:"sliceToDeepCopyPtr"` diff --git a/pkg/deepcopy/testdata/zz_generated.deepcopy.go b/pkg/deepcopy/testdata/zz_generated.deepcopy.go index 825f1a4fd..f09fe7d41 100644 --- a/pkg/deepcopy/testdata/zz_generated.deepcopy.go +++ b/pkg/deepcopy/testdata/zz_generated.deepcopy.go @@ -1,5 +1,4 @@ //go:build !ignore_autogenerated -// +build !ignore_autogenerated // Code generated by controller-gen. DO NOT EDIT. @@ -644,7 +643,8 @@ func (in *SpecificCases) DeepCopyInto(out *SpecificCases) { if val == nil { (*out)[key] = nil } else { - in, out := &val, &outVal + inVal := (*in)[key] + in, out := &inVal, &outVal *out = make([]string, len(*in)) copy(*out, *in) } @@ -682,6 +682,24 @@ func (in *SpecificCases) DeepCopyInto(out *SpecificCases) { (*out)[key] = val.DeepCopy() } } + if in.MapNested != nil { + in, out := &in.MapNested, &out.MapNested + *out = make(map[string]map[string]string, len(*in)) + for key, val := range *in { + var outVal map[string]string + if val == nil { + (*out)[key] = nil + } else { + inVal := (*in)[key] + in, out := &inVal, &outVal + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + (*out)[key] = outVal + } + } if in.SliceToDeepCopyPtr != nil { in, out := &in.SliceToDeepCopyPtr, &out.SliceToDeepCopyPtr *out = make([]DeepCopyPtr, len(*in)) @@ -1519,7 +1537,8 @@ func (in *TestMaps) DeepCopyInto(out *TestMaps) { if val == nil { (*out)[key] = nil } else { - in, out := &val, &outVal + inVal := (*in)[key] + in, out := &inVal, &outVal *out = new(string) **out = **in } @@ -1534,7 +1553,8 @@ func (in *TestMaps) DeepCopyInto(out *TestMaps) { if val == nil { (*out)[key] = nil } else { - in, out := &val, &outVal + inVal := (*in)[key] + in, out := &inVal, &outVal *out = new(*string) if **in != nil { in, out := *in, *out @@ -1553,7 +1573,8 @@ func (in *TestMaps) DeepCopyInto(out *TestMaps) { if val == nil { (*out)[key] = nil } else { - in, out := &val, &outVal + inVal := (*in)[key] + in, out := &inVal, &outVal *out = make(map[string]string, len(*in)) for key, val := range *in { (*out)[key] = val @@ -1570,7 +1591,8 @@ func (in *TestMaps) DeepCopyInto(out *TestMaps) { if val == nil { (*out)[key] = nil } else { - in, out := &val, &outVal + inVal := (*in)[key] + in, out := &inVal, &outVal *out = new(map[string]string) if **in != nil { in, out := *in, *out @@ -1591,7 +1613,8 @@ func (in *TestMaps) DeepCopyInto(out *TestMaps) { if val == nil { (*out)[key] = nil } else { - in, out := &val, &outVal + inVal := (*in)[key] + in, out := &inVal, &outVal *out = make([]string, len(*in)) copy(*out, *in) } @@ -1606,7 +1629,8 @@ func (in *TestMaps) DeepCopyInto(out *TestMaps) { if val == nil { (*out)[key] = nil } else { - in, out := &val, &outVal + inVal := (*in)[key] + in, out := &inVal, &outVal *out = new([]string) if **in != nil { in, out := *in, *out @@ -1632,7 +1656,8 @@ func (in *TestMaps) DeepCopyInto(out *TestMaps) { if val == nil { (*out)[key] = nil } else { - in, out := &val, &outVal + inVal := (*in)[key] + in, out := &inVal, &outVal *out = new(Ttest) (*in).DeepCopyInto(*out) } @@ -1962,7 +1987,8 @@ func (in *Ttest) DeepCopyInto(out *Ttest) { if val == nil { (*out)[key] = nil } else { - in, out := &val, &outVal + inVal := (*in)[key] + in, out := &inVal, &outVal *out = make(Slice, len(*in)) copy(*out, *in) } diff --git a/pkg/deepcopy/traverse.go b/pkg/deepcopy/traverse.go index 3a751757d..863408873 100644 --- a/pkg/deepcopy/traverse.go +++ b/pkg/deepcopy/traverse.go @@ -374,7 +374,8 @@ func (c *copyMethodMaker) genMapDeepCopy(actualName *namingInfo, mapType *types. c.IfElse("val == nil", func() { c.Line("(*out)[key] = nil") }, func() { - c.Line("in, out := &val, &outVal") + c.Line("inVal := (*in)[key]") + c.Line("in, out := &inVal, &outVal") c.genDeepCopyIntoBlock(&namingInfo{typeInfo: mapType.Elem()}, mapType.Elem()) }) c.Line("(*out)[key] = outVal") @@ -735,11 +736,14 @@ func hasAnyDeepCopyMethod(pkg *loader.Package, typeInfo types.Type) bool { // eventualUnderlyingType gets the "final" type in a sequence of named aliases. // It's effectively a shortcut for calling Underlying in a loop. func eventualUnderlyingType(typeInfo types.Type) types.Type { - last := typeInfo - for underlying := typeInfo.Underlying(); underlying != last; last, underlying = underlying, underlying.Underlying() { - // get the actual underlying type + for { + underlying := typeInfo.Underlying() + if underlying == typeInfo { + break + } + typeInfo = underlying } - return last + return typeInfo } // fineToShallowCopy checks if a shallow-copying a type is equivalent to deepcopy-ing it. diff --git a/pkg/deepcopy/zz_generated.markerhelp.go b/pkg/deepcopy/zz_generated.markerhelp.go index 913bc1fb7..081c06551 100644 --- a/pkg/deepcopy/zz_generated.markerhelp.go +++ b/pkg/deepcopy/zz_generated.markerhelp.go @@ -1,5 +1,4 @@ //go:build !ignore_autogenerated -// +build !ignore_autogenerated /* Copyright2019 The Kubernetes Authors. @@ -29,8 +28,8 @@ func (Generator) Help() *markers.DefinitionHelp { return &markers.DefinitionHelp{ Category: "", DetailedHelp: markers.DetailedHelp{ - Summary: "generates code containing DeepCopy, DeepCopyInto, and DeepCopyObject method implementations.", - Details: "", + Summary: "generates code containing DeepCopy, DeepCopyInto, and", + Details: "DeepCopyObject method implementations.", }, FieldHelp: map[string]markers.DetailedHelp{ "HeaderFile": { diff --git a/pkg/genall/genall.go b/pkg/genall/genall.go index 63afbac07..b553db14c 100644 --- a/pkg/genall/genall.go +++ b/pkg/genall/genall.go @@ -20,7 +20,6 @@ import ( "encoding/json" "fmt" "io" - "io/ioutil" "os" "golang.org/x/tools/go/packages" @@ -133,16 +132,28 @@ func WithTransform(transform func(obj map[string]interface{}) error) *WriteYAMLO } } +// TransformRemoveCreationTimestamp ensures we do not write the metadata.creationTimestamp field. +func TransformRemoveCreationTimestamp(obj map[string]interface{}) error { + metadata := obj["metadata"].(map[interface{}]interface{}) + delete(metadata, "creationTimestamp") + return nil +} + // WriteYAML writes the given objects out, serialized as YAML, using the // context's OutputRule. Objects are written as separate documents, separated // from each other by `---` (as per the YAML spec). -func (g GenerationContext) WriteYAML(itemPath string, objs []interface{}, options ...*WriteYAMLOptions) error { +func (g GenerationContext) WriteYAML(itemPath, headerText string, objs []interface{}, options ...*WriteYAMLOptions) error { out, err := g.Open(nil, itemPath) if err != nil { return err } defer out.Close() + _, err = out.Write([]byte(headerText)) + if err != nil { + return err + } + for _, obj := range objs { yamlContent, err := yamlMarshal(obj, options...) if err != nil { @@ -202,7 +213,7 @@ func (g GenerationContext) ReadFile(path string) ([]byte, error) { return nil, err } defer file.Close() - return ioutil.ReadAll(file) + return io.ReadAll(file) } // ForRoots produces a Runtime to run the given generators against the diff --git a/pkg/genall/options.go b/pkg/genall/options.go index 836b1617e..97d7d67a6 100644 --- a/pkg/genall/options.go +++ b/pkg/genall/options.go @@ -74,7 +74,6 @@ func RegistryFromOptions(optionsRegistry *markers.Registry, options []string) (* // further modified. Not default generators are used if none are specified -- you can check // the output and rerun for that. func FromOptions(optionsRegistry *markers.Registry, options []string) (*Runtime, error) { - protoRt, err := protoFromOptions(optionsRegistry, options) if err != nil { return nil, err @@ -136,6 +135,9 @@ func protoFromOptions(optionsRegistry *markers.Registry, options []string) (prot switch val := val.(type) { case Generator: gens = append(gens, &val) + if _, alreadyExists := gensByName[defn.Name]; alreadyExists { + return protoRuntime{}, fmt.Errorf("multiple instances of '%s' generator specified", defn.Name) + } gensByName[defn.Name] = &val case OutputRule: _, genName := splitOutputRuleOption(defn.Name) diff --git a/pkg/genall/output.go b/pkg/genall/output.go index 5dc3fe19c..3eb43b0c2 100644 --- a/pkg/genall/output.go +++ b/pkg/genall/output.go @@ -19,7 +19,6 @@ package genall import ( "fmt" "io" - "io/ioutil" "os" "path/filepath" @@ -92,7 +91,7 @@ var OutputToNothing = outputToNothing{} type outputToNothing struct{} func (o outputToNothing) Open(_ *loader.Package, _ string) (io.WriteCloser, error) { - return nopCloser{ioutil.Discard}, nil + return nopCloser{io.Discard}, nil } // +controllertools:marker:generateHelp:category="" @@ -122,7 +121,7 @@ var OutputToStdout = outputToStdout{} // Generally useful for single-artifact outputs. type outputToStdout struct{} -func (o outputToStdout) Open(_ *loader.Package, itemPath string) (io.WriteCloser, error) { +func (o outputToStdout) Open(_ *loader.Package, _ string) (io.WriteCloser, error) { return nopCloser{os.Stdout}, nil } diff --git a/pkg/genall/zz_generated.markerhelp.go b/pkg/genall/zz_generated.markerhelp.go index 6428f0ce2..998061b9b 100644 --- a/pkg/genall/zz_generated.markerhelp.go +++ b/pkg/genall/zz_generated.markerhelp.go @@ -1,5 +1,4 @@ //go:build !ignore_autogenerated -// +build !ignore_autogenerated /* Copyright2019 The Kubernetes Authors. @@ -29,7 +28,7 @@ func (InputPaths) Help() *markers.DefinitionHelp { return &markers.DefinitionHelp{ Category: "", DetailedHelp: markers.DetailedHelp{ - Summary: "represents paths and go-style path patterns to use as package roots. ", + Summary: "represents paths and go-style path patterns to use as package roots.", Details: "Multiple paths can be specified using \"{path1, path2, path3}\".", }, FieldHelp: map[string]markers.DetailedHelp{}, @@ -40,8 +39,8 @@ func (OutputArtifacts) Help() *markers.DefinitionHelp { return &markers.DefinitionHelp{ Category: "", DetailedHelp: markers.DetailedHelp{ - Summary: "outputs artifacts to different locations, depending on whether they're package-associated or not. ", - Details: "Non-package associated artifacts are output to the Config directory, while package-associated ones are output to their package's source files' directory, unless an alternate path is specified in Code.", + Summary: "outputs artifacts to different locations, depending on", + Details: "whether they're package-associated or not.\n\n\nNon-package associated artifacts\nare output to the Config directory, while package-associated ones are output\nto their package's source files' directory, unless an alternate path is\nspecified in Code.", }, FieldHelp: map[string]markers.DetailedHelp{ "Config": { @@ -60,8 +59,8 @@ func (OutputToDirectory) Help() *markers.DefinitionHelp { return &markers.DefinitionHelp{ Category: "", DetailedHelp: markers.DetailedHelp{ - Summary: "outputs each artifact to the given directory, regardless of if it's package-associated or not.", - Details: "", + Summary: "outputs each artifact to the given directory, regardless", + Details: "of if it's package-associated or not.", }, FieldHelp: map[string]markers.DetailedHelp{}, } @@ -82,7 +81,7 @@ func (outputToStdout) Help() *markers.DefinitionHelp { return &markers.DefinitionHelp{ Category: "", DetailedHelp: markers.DetailedHelp{ - Summary: "outputs everything to standard-out, with no separation. ", + Summary: "outputs everything to standard-out, with no separation.", Details: "Generally useful for single-artifact outputs.", }, FieldHelp: map[string]markers.DetailedHelp{}, diff --git a/pkg/loader/loader.go b/pkg/loader/loader.go index 2efa94c7d..2c5cf4c97 100644 --- a/pkg/loader/loader.go +++ b/pkg/loader/loader.go @@ -23,7 +23,6 @@ import ( "go/scanner" "go/token" "go/types" - "io/ioutil" "os" "path/filepath" "regexp" @@ -111,7 +110,7 @@ func (p *Package) NeedSyntax() { for i, filename := range p.CompiledGoFiles { go func(i int, filename string) { defer wg.Done() - src, err := ioutil.ReadFile(filename) + src, err := os.ReadFile(filename) if err != nil { p.AddError(err) return @@ -371,7 +370,7 @@ func LoadRootsWithConfig(cfg *packages.Config, roots ...string) ([]*Package, err cfg: cfg, packages: make(map[*packages.Package]*Package), } - l.cfg.Mode |= packages.LoadImports | packages.NeedTypesSizes + l.cfg.Mode |= packages.NeedName | packages.NeedFiles | packages.NeedCompiledGoFiles | packages.NeedImports | packages.NeedTypesSizes if l.cfg.Fset == nil { l.cfg.Fset = token.NewFileSet() } @@ -394,7 +393,7 @@ func LoadRootsWithConfig(cfg *packages.Config, roots ...string) ([]*Package, err // and try and prevent packages from showing up twice when nested module // support is enabled. there is not harm that comes from this per se, but // it makes testing easier when a known number of modules can be asserted - uniquePkgIDs := sets.String{} + uniquePkgIDs := sets.Set[string]{} // loadPackages returns the Go packages for the provided roots // @@ -490,7 +489,6 @@ func LoadRootsWithConfig(cfg *packages.Config, roots ...string) ([]*Package, err p string, d os.DirEntry, e error) error { - if e != nil { return e } @@ -519,7 +517,6 @@ func LoadRootsWithConfig(cfg *packages.Config, roots ...string) ([]*Package, err // get the absolute path of the root if !filepath.IsAbs(r) { - // if the initial value of cfg.Dir was non-empty then use it when // building the absolute path to this root. otherwise use the // filepath.Abs function to get the absolute path of the root based @@ -549,7 +546,6 @@ func LoadRootsWithConfig(cfg *packages.Config, roots ...string) ([]*Package, err if err := filepath.WalkDir( d, addNestedGoModulesToRoots); err != nil { - return nil, err } } @@ -605,9 +601,9 @@ func LoadRootsWithConfig(cfg *packages.Config, roots ...string) ([]*Package, err // references with those from the rootPkgs list. This ensures the // kubebuilder marker generation is handled correctly. For more info, // please see issue 680. -func visitImports(rootPkgs []*Package, pkg *Package, seen sets.String) { +func visitImports(rootPkgs []*Package, pkg *Package, seen sets.Set[string]) { if seen == nil { - seen = sets.String{} + seen = sets.Set[string]{} } for importedPkgID, importedPkg := range pkg.Imports() { for i := range rootPkgs { diff --git a/pkg/loader/refs.go b/pkg/loader/refs.go index 37c3295f1..f58a29f72 100644 --- a/pkg/loader/refs.go +++ b/pkg/loader/refs.go @@ -18,7 +18,6 @@ package loader import ( "fmt" - "go/ast" "strconv" "sync" @@ -164,7 +163,7 @@ func allReferencedPackages(pkg *Package, filterNodes NodeFilter) []*Package { refsByFile[file] = refs } - EachType(pkg, func(file *ast.File, decl *ast.GenDecl, spec *ast.TypeSpec) { + EachType(pkg, func(file *ast.File, _ *ast.GenDecl, spec *ast.TypeSpec) { refs := refsByFile[file] refs.collectReferences(spec.Type, filterNodes) }) diff --git a/pkg/markers/collect.go b/pkg/markers/collect.go index b2f821991..23f52e3d2 100644 --- a/pkg/markers/collect.go +++ b/pkg/markers/collect.go @@ -31,7 +31,7 @@ import ( type Collector struct { *Registry - byPackage map[string]map[ast.Node]MarkerValues + byPackage map[*loader.Package]map[ast.Node]MarkerValues mu sync.Mutex } @@ -53,7 +53,7 @@ func (c *Collector) init() { c.Registry = &Registry{} } if c.byPackage == nil { - c.byPackage = make(map[string]map[ast.Node]MarkerValues) + c.byPackage = make(map[*loader.Package]map[ast.Node]MarkerValues) } } @@ -75,7 +75,7 @@ func (c *Collector) init() { func (c *Collector) MarkersInPackage(pkg *loader.Package) (map[ast.Node]MarkerValues, error) { c.mu.Lock() c.init() - if markers, exist := c.byPackage[pkg.ID]; exist { + if markers, exist := c.byPackage[pkg]; exist { c.mu.Unlock() return markers, nil } @@ -91,8 +91,7 @@ func (c *Collector) MarkersInPackage(pkg *loader.Package) (map[ast.Node]MarkerVa c.mu.Lock() defer c.mu.Unlock() - c.byPackage[pkg.ID] = markers - + c.byPackage[pkg] = markers return markers, nil } @@ -389,7 +388,6 @@ func (v markerSubVisitor) Visit(node ast.Node) ast.Visitor { v.commentInd = lastCommentInd + 1 return resVisitor - } // associatedCommentsFor returns the doc comment group (if relevant and present) and end-of-line comment diff --git a/pkg/markers/collect_test.go b/pkg/markers/collect_test.go index eaa7bbea8..8ac0ce26b 100644 --- a/pkg/markers/collect_test.go +++ b/pkg/markers/collect_test.go @@ -106,7 +106,7 @@ var _ = Describe("Collecting", func() { }) It("should have docs without markers", func() { - Expect(docsByType).To(HaveKeyWithValue("Foo", "normal godoc normal godoc")) + Expect(docsByType).To(HaveKeyWithValue("Foo", "normal godoc\nnormal godoc")) }) It("should associate markers in the closest non-godoc block", func() { @@ -133,7 +133,22 @@ var _ = Describe("Collecting", func() { It("should have doc without extraneous spaces, even over multiple lines", func() { Expect(docsByType).To(HaveKeyWithValue("HasDocsWithSpaces2", - "This type of doc has spaces preserved in go-ast, but we'd like to trim them, especially when formatted like this.")) + "This type of doc has spaces preserved in go-ast, but we'd like to trim them,\nespecially when formatted like this.")) + }) + }) + Context("types with //-style comments and yaml embeeded", func() { + It("should keep spaces and multiline", func() { + Expect(docsByType).To(HaveKeyWithValue("HasNonAsteriskDocWithYamlEmbeeded", + `This is a description +this is an example as yaml: +~~~yaml +--- +foo: + bar: + dar: + - value1 + - value2 +~~~`)) }) }) diff --git a/pkg/markers/markers_suite_test.go b/pkg/markers/markers_suite_test.go index ad8491cb1..e977094c5 100644 --- a/pkg/markers/markers_suite_test.go +++ b/pkg/markers/markers_suite_test.go @@ -99,6 +99,19 @@ var _ = BeforeSuite(func() { type HasDocsWithSpaces2 struct { } + // This is a description + // this is an example as yaml: + // ~~~yaml + // --- + // foo: + // bar: + // dar: + // - value1 + // - value2 + // ~~~ + type HasNonAsteriskDocWithYamlEmbeeded struct { + } + type Baz interface { // +testing:pkglvl="not here in interface" } diff --git a/pkg/markers/parse.go b/pkg/markers/parse.go index 3e1d75a83..01e8950fb 100644 --- a/pkg/markers/parse.go +++ b/pkg/markers/parse.go @@ -268,7 +268,11 @@ func guessType(scanner *sc.Scanner, raw string, allowSlice bool) *Argument { subScanner := parserScanner(subRaw, scanner.Error) var tok rune - for tok = subScanner.Scan(); tok != ',' && tok != sc.EOF && tok != ';'; tok = subScanner.Scan() { + for { + tok = subScanner.Scan() + if tok == ',' || tok == sc.EOF || tok == ';' { + break + } // wait till we get something interesting } @@ -306,6 +310,7 @@ func guessType(scanner *sc.Scanner, raw string, allowSlice bool) *Argument { // We'll cross that bridge when we get there. // look ahead till we can figure out if this is a map or a slice + hint = peekNoSpace(subScanner) firstElemType := guessType(subScanner, subRaw, false) if firstElemType.Type == StringType { // might be a map or slice, parse the string and check for colon @@ -313,8 +318,9 @@ func guessType(scanner *sc.Scanner, raw string, allowSlice bool) *Argument { var keyVal string // just ignore this (&Argument{Type: StringType}).parseString(subScanner, raw, reflect.Indirect(reflect.ValueOf(&keyVal))) - if subScanner.Scan() == ':' { + if token := subScanner.Scan(); token == ':' || hint == '}' { // it's got a string followed by a colon -- it's a map + // or an empty map in case of {} return &Argument{ Type: MapType, ItemType: &Argument{Type: AnyType}, @@ -369,6 +375,14 @@ func guessType(scanner *sc.Scanner, raw string, allowSlice bool) *Argument { // parseString parses either of the two accepted string forms (quoted, or bare tokens). func (a *Argument) parseString(scanner *sc.Scanner, raw string, out reflect.Value) { + // we need to temporarily disable the scanner's int/float parsing, since we want to + // prevent number parsing errors. + oldMode := scanner.Mode + scanner.Mode = oldMode &^ sc.ScanInts &^ sc.ScanFloats + defer func() { + scanner.Mode = oldMode + }() + // strings are a bit weird -- the "easy" case is quoted strings (tokenized as strings), // the "hard" case (present for backwards compat) is a bare sequence of tokens that aren't // a comma. @@ -495,7 +509,12 @@ func (a *Argument) parse(scanner *sc.Scanner, raw string, out reflect.Value, inS // raw consumes everything else castAndSet(out, reflect.ValueOf(raw[scanner.Pos().Offset:])) // consume everything else - for tok := scanner.Scan(); tok != sc.EOF; tok = scanner.Scan() { + var tok rune + for { + tok = scanner.Scan() + if tok == sc.EOF { + break + } } case NumberType: nextChar := scanner.Peek() @@ -801,13 +820,23 @@ func parserScanner(raw string, err func(*sc.Scanner, string)) *sc.Scanner { return scanner } +type markerParser interface { + ParseMarker(name string, anonymousName string, restFields string) error +} + // Parse uses the type information in this Definition to parse the given // raw marker in the form `+a:b:c=arg,d=arg` into an output object of the // type specified in the definition. func (d *Definition) Parse(rawMarker string) (interface{}, error) { name, anonName, fields := splitMarker(rawMarker) - out := reflect.Indirect(reflect.New(d.Output)) + outPointer := reflect.New(d.Output) + out := reflect.Indirect(outPointer) + + if parser, ok := outPointer.Interface().(markerParser); ok { + err := parser.ParseMarker(name, anonName, fields) + return out.Interface(), err + } // if we're a not a struct or have no arguments, treat the full `a:b:c` as the name, // otherwise, treat `c` as a field name, and `a:b` as the marker name. diff --git a/pkg/markers/parse_test.go b/pkg/markers/parse_test.go index 632a10d57..012da56f9 100644 --- a/pkg/markers/parse_test.go +++ b/pkg/markers/parse_test.go @@ -171,6 +171,9 @@ var _ = Describe("Parsing", func() { Context("of individual arguments", func() { It("should support bare strings", argParseTestCase{arg: Argument{Type: StringType}, raw: `some string here!`, output: "some string here!"}.Run) + It("should support bare strings containing number-ish values 1", argParseTestCase{arg: Argument{Type: StringType}, raw: `aa 0Baaa aaa`, output: "aa 0Baaa aaa"}.Run) + It("should support bare strings containing number-ish values 2", argParseTestCase{arg: Argument{Type: StringType}, raw: `/tmp/tmp-CHECKCRD-0B7LDeoZta`, output: "/tmp/tmp-CHECKCRD-0B7LDeoZta"}.Run) + It("should support bare strings containing number-ish values 3", argParseTestCase{arg: Argument{Type: StringType}, raw: `.0B7LDeoZt`, output: ".0B7LDeoZt"}.Run) It("should support double-quoted strings", argParseTestCase{arg: Argument{Type: StringType}, raw: `"some; string, \nhere"`, output: "some; string, \nhere"}.Run) It("should support raw strings", argParseTestCase{arg: Argument{Type: StringType}, raw: "`some; string, \\nhere`", output: `some; string, \nhere`}.Run) It("should support integers", argParseTestCase{arg: Argument{Type: IntType}, raw: "42", output: 42}.Run) @@ -187,6 +190,7 @@ var _ = Describe("Parsing", func() { It("should support delimitted slices of delimitted slices", argParseTestCase{arg: sliceOSlice, raw: "{{1,1},{2,3},{5,8}}", output: sliceOSliceOut}.Run) It("should support maps", argParseTestCase{arg: Argument{Type: MapType, ItemType: &Argument{Type: StringType}}, raw: "{formal: hello, `informal`: `hi!`}", output: map[string]string{"formal": "hello", "informal": "hi!"}}.Run) + It("should work with empty maps (which are equal to empty lists in the output)", argParseTestCase{arg: Argument{Type: MapType, ItemType: &Argument{Type: StringType}}, raw: "{}", output: map[string]string{}}.Run) Context("with any value", func() { anyArg := Argument{Type: AnyType} diff --git a/pkg/markers/zip.go b/pkg/markers/zip.go index b352ededc..9e4d1b70a 100644 --- a/pkg/markers/zip.go +++ b/pkg/markers/zip.go @@ -58,32 +58,65 @@ func extractDoc(node ast.Node, decl *ast.GenDecl) string { } outGroup.List = append(outGroup.List, comment) } + isAsteriskComment := false + for _, l := range outGroup.List { + if strings.HasPrefix(l.Text, "/*") { + isAsteriskComment = true + break + } + } // split lines, and re-join together as a single // paragraph, respecting double-newlines as // paragraph markers. - outLines := strings.Split(outGroup.Text(), "\n") - if outLines[len(outLines)-1] == "" { + lines := strings.Split(outGroup.Text(), "\n") + if lines[len(lines)-1] == "" { // chop off the extraneous last part - outLines = outLines[:len(outLines)-1] + lines = lines[:len(lines)-1] } - for i, line := range outLines { - // Trim any extranous whitespace, - // for handling /*…*/-style comments, - // which have whitespace preserved in go/ast: - line = strings.TrimSpace(line) + var outLines []string + var insideCodeBlock bool + for i, line := range lines { + if isAsteriskComment { + // Trim any extranous whitespace, + // for handling /*…*/-style comments, + // which have whitespace preserved in go/ast: + line = strings.TrimSpace(line) + } // Respect that double-newline means // actual newline: if line == "" { - outLines[i] = "\n" + lines[i] = "\n" } else { - outLines[i] = line + lines[i] = line } - } - return strings.Join(outLines, " ") + // Recognize markdown code blocks (``` or ~~~) + // https://spec.commonmark.org/0.27/#fenced-code-blocks + if strings.HasPrefix(line, "```") || strings.HasPrefix(line, "~~~") { + insideCodeBlock = !insideCodeBlock + } + + if !insideCodeBlock { + // If we are not inside markdown code block, follow the Kubernetes formatting conventions: + // - Lines after --- are comments and should be ignored. + // - Lines starting with TODO are comments and should be ignored. + // See function fmtRawDoc() in https://github.com/kubernetes/apimachinery/blob/master/pkg/runtime/swagger_doc_generator.go + + if strings.HasPrefix(line, "TODO") { + continue + } + + if strings.HasPrefix(line, "---") { + break + } + } + + outLines = append(outLines, line) + } + return strings.Join(outLines, "\n") } // PackageMarkers collects all the package-level marker values for the given package. diff --git a/pkg/rbac/parser.go b/pkg/rbac/parser.go index c2a24f471..51b4c043f 100644 --- a/pkg/rbac/parser.go +++ b/pkg/rbac/parser.go @@ -93,6 +93,18 @@ func (r *Rule) key() ruleKey { } } +func (r *Rule) keyWithGroupResourceNamesURLsVerbs() string { + key := r.key() + verbs := strings.Join(r.Verbs, "&") + return fmt.Sprintf("%s + %s + %s + %s", key.Groups, key.ResourceNames, key.URLs, verbs) +} + +func (r *Rule) keyWithResourcesResourceNamesURLsVerbs() string { + key := r.key() + verbs := strings.Join(r.Verbs, "&") + return fmt.Sprintf("%s + %s + %s + %s", key.Resources, key.ResourceNames, key.URLs, verbs) +} + // addVerbs adds new verbs into a Rule. // The duplicates in `r.Verbs` will be removed, and then `r.Verbs` will be sorted. func (r *Rule) addVerbs(verbs []string) { @@ -149,6 +161,12 @@ func (r *Rule) ToRule() rbacv1.PolicyRule { type Generator struct { // RoleName sets the name of the generated ClusterRole. RoleName string + + // HeaderFile specifies the header text (e.g. license) to prepend to generated files. + HeaderFile string `marker:",optional"` + + // Year specifies the year to substitute for " YEAR" in the header file. + Year string `marker:",optional"` } func (Generator) RegisterMarkers(into *markers.Registry) error { @@ -162,22 +180,28 @@ func (Generator) RegisterMarkers(into *markers.Registry) error { // GenerateRoles generate a slice of objs representing either a ClusterRole or a Role object // The order of the objs in the returned slice is stable and determined by their namespaces. func GenerateRoles(ctx *genall.GenerationContext, roleName string) ([]interface{}, error) { - rulesByNS := make(map[string][]*Rule) + rulesByNSResource := make(map[string][]*Rule) for _, root := range ctx.Roots { markerSet, err := markers.PackageMarkers(ctx.Collector, root) if err != nil { root.AddError(err) } - // group RBAC markers by namespace + // group RBAC markers by namespace and separate by resource for _, markerValue := range markerSet[RuleDefinition.Name] { rule := markerValue.(Rule) - namespace := rule.Namespace - if _, ok := rulesByNS[namespace]; !ok { - rules := make([]*Rule, 0) - rulesByNS[namespace] = rules + for _, resource := range rule.Resources { + r := Rule{ + Groups: rule.Groups, + Resources: []string{resource}, + ResourceNames: rule.ResourceNames, + URLs: rule.URLs, + Namespace: rule.Namespace, + Verbs: rule.Verbs, + } + namespace := r.Namespace + rulesByNSResource[namespace] = append(rulesByNSResource[namespace], &r) } - rulesByNS[namespace] = append(rulesByNS[namespace], &rule) } } @@ -194,6 +218,45 @@ func GenerateRoles(ctx *genall.GenerationContext, roleName string) ([]interface{ ruleMap[key].addVerbs(rule.Verbs) } + // deduplicate resources + // 1. create map based on key without resources + ruleMapWithoutResources := make(map[string][]*Rule) + for _, rule := range ruleMap { + // get key without Resources + key := rule.keyWithGroupResourceNamesURLsVerbs() + ruleMapWithoutResources[key] = append(ruleMapWithoutResources[key], rule) + } + // 2. merge to ruleMap + ruleMap = make(map[ruleKey]*Rule) + for _, rules := range ruleMapWithoutResources { + rule := rules[0] + for _, mergeRule := range rules[1:] { + rule.Resources = append(rule.Resources, mergeRule.Resources...) + } + + key := rule.key() + ruleMap[key] = rule + } + + // deduplicate groups + // 1. create map based on key without group + ruleMapWithoutGroup := make(map[string][]*Rule) + for _, rule := range ruleMap { + // get key without Group + key := rule.keyWithResourcesResourceNamesURLsVerbs() + ruleMapWithoutGroup[key] = append(ruleMapWithoutGroup[key], rule) + } + // 2. merge to ruleMap + ruleMap = make(map[ruleKey]*Rule) + for _, rules := range ruleMapWithoutGroup { + rule := rules[0] + for _, mergeRule := range rules[1:] { + rule.Groups = append(rule.Groups, mergeRule.Groups...) + } + key := rule.key() + ruleMap[key] = rule + } + // sort the Rules in rules according to their ruleKeys keys := make([]ruleKey, 0, len(ruleMap)) for key := range ruleMap { @@ -204,14 +267,13 @@ func GenerateRoles(ctx *genall.GenerationContext, roleName string) ([]interface{ var policyRules []rbacv1.PolicyRule for _, key := range keys { policyRules = append(policyRules, ruleMap[key].ToRule()) - } return policyRules } // collect all the namespaces and sort them var namespaces []string - for ns := range rulesByNS { + for ns := range rulesByNSResource { namespaces = append(namespaces, ns) } sort.Strings(namespaces) @@ -219,7 +281,7 @@ func GenerateRoles(ctx *genall.GenerationContext, roleName string) ([]interface{ // process the items in rulesByNS by the order specified in `namespaces` to make sure that the Role order is stable var objs []interface{} for _, ns := range namespaces { - rules := rulesByNS[ns] + rules := rulesByNSResource[ns] policyRules := NormalizeRules(rules) if len(policyRules) == 0 { continue @@ -263,5 +325,15 @@ func (g Generator) Generate(ctx *genall.GenerationContext) error { return nil } - return ctx.WriteYAML("role.yaml", objs) + var headerText string + if g.HeaderFile != "" { + headerBytes, err := ctx.ReadFile(g.HeaderFile) + if err != nil { + return err + } + headerText = string(headerBytes) + } + headerText = strings.ReplaceAll(headerText, " YEAR", " "+g.Year) + + return ctx.WriteYAML("role.yaml", headerText, objs, genall.WithTransform(genall.TransformRemoveCreationTimestamp)) } diff --git a/pkg/rbac/parser_integration_test.go b/pkg/rbac/parser_integration_test.go index a56c1ec6a..74f8a7b56 100644 --- a/pkg/rbac/parser_integration_test.go +++ b/pkg/rbac/parser_integration_test.go @@ -3,7 +3,6 @@ package rbac_test import ( "bytes" "fmt" - "io/ioutil" "os" "github.com/google/go-cmp/cmp" @@ -49,11 +48,11 @@ var _ = Describe("ClusterRole generated by the RBAC Generator", func() { Expect(err).NotTo(HaveOccurred()) By("loading the desired YAML") - expectedFile, err := ioutil.ReadFile("role.yaml") + expectedFile, err := os.ReadFile("role.yaml") Expect(err).NotTo(HaveOccurred()) By("parsing the desired YAML") - for i, expectedRoleBytes := range bytes.Split(expectedFile, []byte("\n---\n"))[1:] { + for i, expectedRoleBytes := range bytes.Split(expectedFile, []byte("\n---\n")) { By(fmt.Sprintf("comparing the generated Role and expected Role (Pair %d)", i)) obj := objs[i] switch obj := obj.(type) { diff --git a/pkg/rbac/testdata/controller.go b/pkg/rbac/testdata/controller.go index 27800d729..82125e015 100644 --- a/pkg/rbac/testdata/controller.go +++ b/pkg/rbac/testdata/controller.go @@ -11,3 +11,20 @@ package controller // +kubebuilder:rbac:groups=batch,resources=jobs/status,verbs=watch;watch // +kubebuilder:rbac:groups=art,resources=jobs,verbs=get,namespace=park // +kubebuilder:rbac:groups=batch.io,resources=cronjobs,resourceNames=foo;bar;baz,verbs=get;watch +// +kubebuilder:rbac:groups=deduplicate-verbs,resources=some,verbs=get;list +// +kubebuilder:rbac:groups=deduplicate-verbs,resources=some,verbs=get +// +kubebuilder:rbac:groups=deduplicate-verbs,resources=some,verbs=list +// +kubebuilder:rbac:groups=deduplicate-resources,resources=one,verbs=create +// +kubebuilder:rbac:groups=deduplicate-resources,resources=two,verbs=create +// +kubebuilder:rbac:groups=deduplicate-resources,resources=three,verbs=create +// +kubebuilder:rbac:groups=deduplicate-groups1,resources=foo,verbs=patch +// +kubebuilder:rbac:groups=deduplicate-groups2,resources=foo,verbs=patch +// +kubebuilder:rbac:groups=deduplicate-groups3,resources=foo,verbs=patch +// +kubebuilder:rbac:groups=deduplicate-all,resources=foo;bar,verbs=get;list +// +kubebuilder:rbac:groups=deduplicate-all,resources=foo,verbs=get +// +kubebuilder:rbac:groups=deduplicate-all,resources=bar,verbs=list +// +kubebuilder:rbac:groups=deduplicate-all-group,resources=foo;bar,verbs=get;list +// +kubebuilder:rbac:groups=not-deduplicate-resources,resources=some,verbs=get +// +kubebuilder:rbac:groups=not-deduplicate-resources,resources=another,verbs=list +// +kubebuilder:rbac:groups=not-deduplicate-groups1,resources=some,verbs=get +// +kubebuilder:rbac:groups=not-deduplicate-groups2,resources=some,verbs=list diff --git a/pkg/rbac/testdata/role.yaml b/pkg/rbac/testdata/role.yaml index 892f09d65..33dfc8052 100644 --- a/pkg/rbac/testdata/role.yaml +++ b/pkg/rbac/testdata/role.yaml @@ -1,9 +1,7 @@ - --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: - creationTimestamp: null name: manager-role rules: - apiGroups: @@ -53,12 +51,61 @@ rules: - get - patch - update - +- apiGroups: + - deduplicate-all + - deduplicate-all-group + resources: + - bar + - foo + verbs: + - get + - list +- apiGroups: + - deduplicate-groups1 + - deduplicate-groups2 + - deduplicate-groups3 + resources: + - foo + verbs: + - patch +- apiGroups: + - deduplicate-resources + resources: + - one + - three + - two + verbs: + - create +- apiGroups: + - deduplicate-verbs + resources: + - some + verbs: + - get + - list +- apiGroups: + - not-deduplicate-groups1 + - not-deduplicate-resources + resources: + - some + verbs: + - get +- apiGroups: + - not-deduplicate-groups2 + resources: + - some + verbs: + - list +- apiGroups: + - not-deduplicate-resources + resources: + - another + verbs: + - list --- apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: - creationTimestamp: null name: manager-role namespace: park rules: @@ -68,22 +115,15 @@ rules: - jobs verbs: - get - --- apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: - creationTimestamp: null name: manager-role namespace: zoo rules: - apiGroups: - art - resources: - - jobs - verbs: - - get -- apiGroups: - wave resources: - jobs diff --git a/pkg/rbac/zz_generated.markerhelp.go b/pkg/rbac/zz_generated.markerhelp.go index 0e2083a23..20c707b1d 100644 --- a/pkg/rbac/zz_generated.markerhelp.go +++ b/pkg/rbac/zz_generated.markerhelp.go @@ -1,5 +1,4 @@ //go:build !ignore_autogenerated -// +build !ignore_autogenerated /* Copyright2019 The Kubernetes Authors. @@ -37,6 +36,14 @@ func (Generator) Help() *markers.DefinitionHelp { Summary: "sets the name of the generated ClusterRole.", Details: "", }, + "HeaderFile": { + Summary: "specifies the header text (e.g. license) to prepend to generated files.", + Details: "", + }, + "Year": { + Summary: "specifies the year to substitute for \" YEAR\" in the header file.", + Details: "", + }, }, } } @@ -58,8 +65,8 @@ func (Rule) Help() *markers.DefinitionHelp { Details: "", }, "ResourceNames": { - Summary: "specifies the names of the API resources that this rule encompasses. ", - Details: "Create requests cannot be restricted by resourcename, as the object's name is not known at authorization time.", + Summary: "specifies the names of the API resources that this rule encompasses.", + Details: "Create requests cannot be restricted by resourcename, as the object's name\nis not known at authorization time.", }, "Verbs": { Summary: "specifies the (lowercase) kubernetes API verbs that this rule encompasses.", @@ -70,8 +77,8 @@ func (Rule) Help() *markers.DefinitionHelp { Details: "", }, "Namespace": { - Summary: "specifies the scope of the Rule. If not set, the Rule belongs to the generated ClusterRole. If set, the Rule belongs to a Role, whose namespace is specified by this field.", - Details: "", + Summary: "specifies the scope of the Rule.", + Details: "If not set, the Rule belongs to the generated ClusterRole.\nIf set, the Rule belongs to a Role, whose namespace is specified by this field.", }, }, } diff --git a/pkg/schemapatcher/gen.go b/pkg/schemapatcher/gen.go index 688803b85..e2eea29c5 100644 --- a/pkg/schemapatcher/gen.go +++ b/pkg/schemapatcher/gen.go @@ -18,7 +18,7 @@ package schemapatcher import ( "fmt" - "io/ioutil" + "os" "path/filepath" "gopkg.in/yaml.v3" @@ -92,7 +92,7 @@ func (g Generator) Generate(ctx *genall.GenerationContext) (result error) { Collector: ctx.Collector, Checker: ctx.Checker, // Indicates the parser on whether to register the ObjectMeta type or not - GenerateEmbeddedObjectMeta: g.GenerateEmbeddedObjectMeta != nil && *g.GenerateEmbeddedObjectMeta == true, + GenerateEmbeddedObjectMeta: g.GenerateEmbeddedObjectMeta != nil && *g.GenerateEmbeddedObjectMeta, } crdgen.AddKnownTypes(parser) @@ -335,7 +335,7 @@ func (e *partialCRD) setVersionedSchemata(newSchemata map[string]apiext.JSONSche // minimally invasive. Returned CRDs are mapped by group-kind. func crdsFromDirectory(ctx *genall.GenerationContext, dir string) (map[schema.GroupKind]*partialCRDSet, error) { res := map[schema.GroupKind]*partialCRDSet{} - dirEntries, err := ioutil.ReadDir(dir) + dirEntries, err := os.ReadDir(dir) if err != nil { return nil, err } diff --git a/pkg/schemapatcher/gen_integration_test.go b/pkg/schemapatcher/gen_integration_test.go index d1c8485d6..c14439774 100644 --- a/pkg/schemapatcher/gen_integration_test.go +++ b/pkg/schemapatcher/gen_integration_test.go @@ -17,7 +17,6 @@ limitations under the License. package schemapatcher_test import ( - "io/ioutil" "os" "path/filepath" @@ -44,7 +43,7 @@ var _ = Describe("CRD Patching From Parsing to Editing", func() { rt, err := genall.Generators{&crdSchemaGen}.ForRoots("./...") Expect(err).NotTo(HaveOccurred()) - outputDir, err := ioutil.TempDir("", "controller-tools-test") + outputDir, err := os.MkdirTemp("", "controller-tools-test") Expect(err).NotTo(HaveOccurred()) defer os.RemoveAll(outputDir) rt.OutputRules.Default = genall.OutputToDirectory(outputDir) @@ -70,7 +69,7 @@ var _ = Describe("CRD Patching From Parsing to Editing", func() { rt, err := genall.Generators{&crdSchemaGen}.ForRoots("./...") Expect(err).NotTo(HaveOccurred()) - outputDir, err := ioutil.TempDir("", "controller-tools-test") + outputDir, err := os.MkdirTemp("", "controller-tools-test") Expect(err).NotTo(HaveOccurred()) defer os.RemoveAll(outputDir) rt.OutputRules.Default = genall.OutputToDirectory(outputDir) @@ -80,19 +79,19 @@ var _ = Describe("CRD Patching From Parsing to Editing", func() { Expect(rt.Run()).To(BeFalse(), "unexpectedly had errors") By("loading the output files") - expectedFiles, err := ioutil.ReadDir("expected") + expectedFiles, err := os.ReadDir("expected") Expect(err).NotTo(HaveOccurred()) for _, expectedFile := range expectedFiles { By("reading the expected and actual files for " + expectedFile.Name()) - actualContents, err := ioutil.ReadFile(filepath.Join(outputDir, expectedFile.Name())) + actualContents, err := os.ReadFile(filepath.Join(outputDir, expectedFile.Name())) Expect(err).NotTo(HaveOccurred()) - expectedContents, err := ioutil.ReadFile(filepath.Join("expected", expectedFile.Name())) + expectedContents, err := os.ReadFile(filepath.Join("expected", expectedFile.Name())) Expect(err).NotTo(HaveOccurred()) By("checking that the expected and actual files for " + expectedFile.Name() + " are identical") - Expect(actualContents).To(Equal(expectedContents), "contents not as expected, check pkg/schemapatcher/testdata/README.md for more details.\n\nDiff:\n\n%s", cmp.Diff(string(actualContents), string(expectedContents))) + Expect(actualContents).To(MatchYAML(expectedContents), "contents not as expected, check pkg/schemapatcher/testdata/README.md for more details.\n\nDiff:\n\n%s", cmp.Diff(string(actualContents), string(expectedContents))) } }) }) diff --git a/pkg/schemapatcher/testdata/expected/kubebuilder-example-crd.v1.yaml b/pkg/schemapatcher/testdata/expected/kubebuilder-example-crd.v1.yaml index 5aedaff9d..8f4b46a42 100644 --- a/pkg/schemapatcher/testdata/expected/kubebuilder-example-crd.v1.yaml +++ b/pkg/schemapatcher/testdata/expected/kubebuilder-example-crd.v1.yaml @@ -20,10 +20,19 @@ spec: - 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' + 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' + 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 diff --git a/pkg/schemapatcher/testdata/expected/kubebuilder-unchanged-crd.yaml b/pkg/schemapatcher/testdata/expected/kubebuilder-unchanged-crd.yaml index 265591675..3db57e7b6 100644 --- a/pkg/schemapatcher/testdata/expected/kubebuilder-unchanged-crd.yaml +++ b/pkg/schemapatcher/testdata/expected/kubebuilder-unchanged-crd.yaml @@ -20,10 +20,19 @@ spec: - 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' + 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' + 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 diff --git a/pkg/schemapatcher/zz_generated.markerhelp.go b/pkg/schemapatcher/zz_generated.markerhelp.go index db9745d76..db4cdb074 100644 --- a/pkg/schemapatcher/zz_generated.markerhelp.go +++ b/pkg/schemapatcher/zz_generated.markerhelp.go @@ -1,5 +1,4 @@ //go:build !ignore_autogenerated -// +build !ignore_autogenerated /* Copyright2019 The Kubernetes Authors. @@ -29,8 +28,8 @@ func (Generator) Help() *markers.DefinitionHelp { return &markers.DefinitionHelp{ Category: "", DetailedHelp: markers.DetailedHelp{ - Summary: "patches existing CRDs with new schemata. ", - Details: "It will generate output for each \"CRD Version\" (API version of the CRD type itself) , e.g. apiextensions/v1) available.", + Summary: "patches existing CRDs with new schemata.", + Details: "It will generate output for each \"CRD Version\" (API version of the CRD type\nitself) , e.g. apiextensions/v1) available.", }, FieldHelp: map[string]markers.DetailedHelp{ "ManifestsPath": { @@ -38,8 +37,8 @@ func (Generator) Help() *markers.DefinitionHelp { Details: "", }, "MaxDescLen": { - Summary: "specifies the maximum description length for fields in CRD's OpenAPI schema. ", - Details: "0 indicates drop the description for all fields completely. n indicates limit the description to at most n characters and truncate the description to closest sentence boundary if it exceeds n characters.", + Summary: "specifies the maximum description length for fields in CRD's OpenAPI schema.", + Details: "0 indicates drop the description for all fields completely.\nn indicates limit the description to at most n characters and truncate the description to\nclosest sentence boundary if it exceeds n characters.", }, "GenerateEmbeddedObjectMeta": { Summary: "specifies if any embedded ObjectMeta in the CRD should be generated", diff --git a/pkg/typescaffold/resource.go b/pkg/typescaffold/resource.go index e4c2388ac..7024a7c8a 100644 --- a/pkg/typescaffold/resource.go +++ b/pkg/typescaffold/resource.go @@ -46,7 +46,7 @@ func (r *Resource) Validate() error { } if r.Kind != flect.Pascalize(r.Kind) { - return fmt.Errorf("Kind must be camelcase (expected %s was %s)", flect.Pascalize(r.Kind), r.Kind) + return fmt.Errorf("kind must be CamelCase (expected %s was %s)", flect.Pascalize(r.Kind), r.Kind) } return nil diff --git a/pkg/typescaffold/scaffold.go b/pkg/typescaffold/scaffold.go index 361452fe0..f3640b94a 100644 --- a/pkg/typescaffold/scaffold.go +++ b/pkg/typescaffold/scaffold.go @@ -92,11 +92,8 @@ type ScaffoldOptions struct { // Validate validates the options, returning an error if anything is invalid. func (o *ScaffoldOptions) Validate() error { - if err := o.Resource.Validate(); err != nil { - return err - } - - return nil + err := o.Resource.Validate() + return err } // Scaffold prints the Kubernetes object scaffolding to the given output. diff --git a/pkg/version/version.go b/pkg/version/version.go index 09c8efcf4..f2709df4a 100644 --- a/pkg/version/version.go +++ b/pkg/version/version.go @@ -13,6 +13,8 @@ WITHOUT WARRANTIES 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 provides the version of the main module. package version import ( diff --git a/pkg/webhook/parser.go b/pkg/webhook/parser.go index a76dcdcbb..5652b4c45 100644 --- a/pkg/webhook/parser.go +++ b/pkg/webhook/parser.go @@ -19,11 +19,12 @@ limitations under the License. // // The markers take the form: // -// +kubebuilder:webhook:webhookVersions=<[]string>,failurePolicy=,matchPolicy=,groups=<[]string>,resources=<[]string>,verbs=<[]string>,versions=<[]string>,name=,path=,mutating=,sideEffects=,admissionReviewVersions=<[]string>,reinvocationPolicy= +// +kubebuilder:webhook:webhookVersions=<[]string>,failurePolicy=,matchPolicy=,groups=<[]string>,resources=<[]string>,verbs=<[]string>,versions=<[]string>,name=,path=,mutating=,sideEffects=,timeoutSeconds=,admissionReviewVersions=<[]string>,reinvocationPolicy= package webhook import ( "fmt" + "sort" "strings" admissionregv1 "k8s.io/api/admissionregistration/v1" @@ -80,6 +81,11 @@ type Config struct { // If the value is "NoneOnDryRun", then the webhook is responsible for inspecting the "dryRun" property of the // AdmissionReview sent in the request, and avoiding side effects if that value is "true." SideEffects string `marker:",optional"` + // TimeoutSeconds allows configuring how long the API server should wait for a webhook to respond before treating the call as a failure. + // If the timeout expires before the webhook responds, the webhook call will be ignored or the API call will be rejected based on the failure policy. + // The timeout value must be between 1 and 30 seconds. + // The timeout for an admission webhook defaults to 10 seconds. + TimeoutSeconds int `marker:",optional"` // Groups specifies the API groups that this webhook receives requests for. Groups []string @@ -102,7 +108,7 @@ type Config struct { // are substituted for hyphens. For example, a validating webhook path for type // batch.tutorial.kubebuilder.io/v1,Kind=CronJob would be // /validate-batch-tutorial-kubebuilder-io-v1-cronjob - Path string + Path string `marker:"path,optional"` // WebhookVersions specifies the target API versions of the {Mutating,Validating}WebhookConfiguration objects // itself to generate. The only supported value is v1. Defaults to v1. @@ -119,6 +125,14 @@ type Config struct { // an object, and mutating webhooks can specify a reinvocationPolicy to control // whether they are reinvoked as well. ReinvocationPolicy string `marker:"reinvocationPolicy,optional"` + + // URL allows mutating webhooks configuration to specify an external URL when generating + // the manifests, instead of using the internal service communication. Should be in format of + // https://address:port/path + // When this option is specified, the serviceConfig.Service is removed from webhook the manifest. + // The URL configuration should be between quotes. + // `url` cannot be specified when `path` is specified. + URL string `marker:"url,optional"` } // verbToAPIVariant converts a marker's verb to the proper value for the API. @@ -151,13 +165,19 @@ func (c Config) ToMutatingWebhook() (admissionregv1.MutatingWebhook, error) { return admissionregv1.MutatingWebhook{}, err } + clientConfig, err := c.clientConfig() + if err != nil { + return admissionregv1.MutatingWebhook{}, err + } + return admissionregv1.MutatingWebhook{ Name: c.Name, Rules: c.rules(), FailurePolicy: c.failurePolicy(), MatchPolicy: matchPolicy, - ClientConfig: c.clientConfig(), + ClientConfig: clientConfig, SideEffects: c.sideEffects(), + TimeoutSeconds: c.timeoutSeconds(), AdmissionReviewVersions: c.AdmissionReviewVersions, ReinvocationPolicy: c.reinvocationPolicy(), }, nil @@ -174,13 +194,19 @@ func (c Config) ToValidatingWebhook() (admissionregv1.ValidatingWebhook, error) return admissionregv1.ValidatingWebhook{}, err } + clientConfig, err := c.clientConfig() + if err != nil { + return admissionregv1.ValidatingWebhook{}, err + } + return admissionregv1.ValidatingWebhook{ Name: c.Name, Rules: c.rules(), FailurePolicy: c.failurePolicy(), MatchPolicy: matchPolicy, - ClientConfig: c.clientConfig(), + ClientConfig: clientConfig, SideEffects: c.sideEffects(), + TimeoutSeconds: c.timeoutSeconds(), AdmissionReviewVersions: c.AdmissionReviewVersions, }, nil } @@ -243,15 +269,26 @@ func (c Config) matchPolicy() (*admissionregv1.MatchPolicyType, error) { } // clientConfig returns the client config for a webhook. -func (c Config) clientConfig() admissionregv1.WebhookClientConfig { +func (c Config) clientConfig() (admissionregv1.WebhookClientConfig, error) { + if (c.Path != "" && c.URL != "") || (c.Path == "" && c.URL == "") { + return admissionregv1.WebhookClientConfig{}, fmt.Errorf("`url` or `path` markers are required and mutually exclusive") + } + path := c.Path - return admissionregv1.WebhookClientConfig{ - Service: &admissionregv1.ServiceReference{ - Name: "webhook-service", - Namespace: "system", - Path: &path, - }, + if path != "" { + return admissionregv1.WebhookClientConfig{ + Service: &admissionregv1.ServiceReference{ + Name: "webhook-service", + Namespace: "system", + Path: &path, + }, + }, nil } + + url := c.URL + return admissionregv1.WebhookClientConfig{ + URL: &url, + }, nil } // sideEffects returns the sideEffects config for a webhook. @@ -272,6 +309,15 @@ func (c Config) sideEffects() *admissionregv1.SideEffectClass { return &sideEffects } +// timeoutSeconds returns the timeoutSeconds config for a webhook. +func (c Config) timeoutSeconds() *int32 { + if c.TimeoutSeconds != 0 { + timeoutSeconds := int32(c.TimeoutSeconds) + return &timeoutSeconds + } + return nil +} + // reinvocationPolicy returns the reinvocationPolicy config for a mutating webhook. func (c Config) reinvocationPolicy() *admissionregv1.ReinvocationPolicyType { var reinvocationPolicy admissionregv1.ReinvocationPolicyType @@ -304,7 +350,13 @@ func (c Config) webhookVersions() ([]string, error) { // +controllertools:marker:generateHelp // Generator generates (partial) {Mutating,Validating}WebhookConfiguration objects. -type Generator struct{} +type Generator struct { + // HeaderFile specifies the header text (e.g. license) to prepend to generated files. + HeaderFile string `marker:",optional"` + + // Year specifies the year to substitute for " YEAR" in the header file. + Year string `marker:",optional"` +} func (Generator) RegisterMarkers(into *markers.Registry) error { if err := into.Register(ConfigDefinition); err != nil { @@ -314,7 +366,7 @@ func (Generator) RegisterMarkers(into *markers.Registry) error { return nil } -func (Generator) Generate(ctx *genall.GenerationContext) error { +func (g Generator) Generate(ctx *genall.GenerationContext) error { supportedWebhookVersions := supportedWebhookVersions() mutatingCfgs := make(map[string][]admissionregv1.MutatingWebhook, len(supportedWebhookVersions)) validatingCfgs := make(map[string][]admissionregv1.ValidatingWebhook, len(supportedWebhookVersions)) @@ -324,7 +376,12 @@ func (Generator) Generate(ctx *genall.GenerationContext) error { root.AddError(err) } - for _, cfg := range markerSet[ConfigDefinition.Name] { + cfgs := markerSet[ConfigDefinition.Name] + sort.SliceStable(cfgs, func(i, j int) bool { + return cfgs[i].(Config).Name < cfgs[j].(Config).Name + }) + + for _, cfg := range cfgs { cfg := cfg.(Config) webhookVersions, err := cfg.webhookVersions() if err != nil { @@ -369,6 +426,11 @@ func (Generator) Generate(ctx *genall.GenerationContext) error { if err := checkSideEffectsForV1(objRaw.Webhooks[i].SideEffects); err != nil { return err } + // TimeoutSeconds must be nil or between 1 and 30 seconds, otherwise, + // return an error + if err := checkTimeoutSeconds(objRaw.Webhooks[i].TimeoutSeconds); err != nil { + return err + } // AdmissionReviewVersions is required in admissionregistration/v1, if this is not set, // return an error if len(objRaw.Webhooks[i].AdmissionReviewVersions) == 0 { @@ -395,6 +457,11 @@ func (Generator) Generate(ctx *genall.GenerationContext) error { if err := checkSideEffectsForV1(objRaw.Webhooks[i].SideEffects); err != nil { return err } + // TimeoutSeconds must be nil or between 1 and 30 seconds, otherwise, + // return an error + if err := checkTimeoutSeconds(objRaw.Webhooks[i].TimeoutSeconds); err != nil { + return err + } // AdmissionReviewVersions is required in admissionregistration/v1, if this is not set, // return an error if len(objRaw.Webhooks[i].AdmissionReviewVersions) == 0 { @@ -405,14 +472,24 @@ func (Generator) Generate(ctx *genall.GenerationContext) error { } } + var headerText string + if g.HeaderFile != "" { + headerBytes, err := ctx.ReadFile(g.HeaderFile) + if err != nil { + return err + } + headerText = string(headerBytes) + } + headerText = strings.ReplaceAll(headerText, " YEAR", " "+g.Year) + for k, v := range versionedWebhooks { var fileName string if k == defaultWebhookVersion { - fileName = fmt.Sprintf("manifests.yaml") + fileName = "manifests.yaml" } else { fileName = fmt.Sprintf("manifests.%s.yaml", k) } - if err := ctx.WriteYAML(fileName, v); err != nil { + if err := ctx.WriteYAML(fileName, headerText, v, genall.WithTransform(genall.TransformRemoveCreationTimestamp)); err != nil { return err } } @@ -429,3 +506,10 @@ func checkSideEffectsForV1(sideEffects *admissionregv1.SideEffectClass) error { } return nil } + +func checkTimeoutSeconds(timeoutSeconds *int32) error { + if timeoutSeconds != nil && (*timeoutSeconds < 1 || *timeoutSeconds > 30) { + return fmt.Errorf("TimeoutSeconds must be between 1 and 30 seconds") + } + return nil +} diff --git a/pkg/webhook/parser_integration_test.go b/pkg/webhook/parser_integration_test.go index f2f6c438c..f020cfc2e 100644 --- a/pkg/webhook/parser_integration_test.go +++ b/pkg/webhook/parser_integration_test.go @@ -18,7 +18,6 @@ package webhook_test import ( "bytes" - "io/ioutil" "os" "path" @@ -59,7 +58,7 @@ var _ = Describe("Webhook Generation From Parsing to CustomResourceDefinition", Expect(reg.Register(webhook.ConfigDefinition)).To(Succeed()) By("requesting that the manifest be generated") - outputDir, err := ioutil.TempDir("", "webhook-integration-test") + outputDir, err := os.MkdirTemp("", "webhook-integration-test") Expect(err).NotTo(HaveOccurred()) defer os.RemoveAll(outputDir) genCtx := &genall.GenerationContext{ @@ -88,7 +87,7 @@ var _ = Describe("Webhook Generation From Parsing to CustomResourceDefinition", Expect(reg.Register(webhook.ConfigDefinition)).To(Succeed()) By("requesting that the manifest be generated") - outputDir, err := ioutil.TempDir("", "webhook-integration-test") + outputDir, err := os.MkdirTemp("", "webhook-integration-test") Expect(err).NotTo(HaveOccurred()) defer os.RemoveAll(outputDir) genCtx := &genall.GenerationContext{ @@ -119,7 +118,7 @@ var _ = Describe("Webhook Generation From Parsing to CustomResourceDefinition", Expect(reg.Register(webhook.ConfigDefinition)).To(Succeed()) By("requesting that the manifest be generated") - outputDir, err := ioutil.TempDir("", "webhook-integration-test") + outputDir, err := os.MkdirTemp("", "webhook-integration-test") Expect(err).NotTo(HaveOccurred()) defer os.RemoveAll(outputDir) genCtx := &genall.GenerationContext{ @@ -131,6 +130,35 @@ var _ = Describe("Webhook Generation From Parsing to CustomResourceDefinition", Expect(err).To(MatchError("SideEffects should not be set to `Some` or `Unknown` for v1 {Mutating,Validating}WebhookConfiguration")) }) + It("should fail with invalid timeout seconds", func() { + By("switching into testdata to appease go modules") + cwd, err := os.Getwd() + Expect(err).NotTo(HaveOccurred()) + Expect(os.Chdir("./testdata/invalid-timeoutSeconds")).To(Succeed()) // go modules are directory-sensitive + defer func() { Expect(os.Chdir(cwd)).To(Succeed()) }() + + By("loading the roots") + pkgs, err := loader.LoadRoots(".") + Expect(err).NotTo(HaveOccurred()) + Expect(pkgs).To(HaveLen(1)) + + By("setting up the parser") + reg := &markers.Registry{} + Expect(reg.Register(webhook.ConfigDefinition)).To(Succeed()) + + By("requesting that the manifest be generated") + outputDir, err := os.MkdirTemp("", "webhook-integration-test") + Expect(err).NotTo(HaveOccurred()) + defer os.RemoveAll(outputDir) + genCtx := &genall.GenerationContext{ + Collector: &markers.Collector{Registry: reg}, + Roots: pkgs, + OutputRule: genall.OutputToDirectory(outputDir), + } + err = webhook.Generator{}.Generate(genCtx) + Expect(err).To(MatchError("TimeoutSeconds must be between 1 and 30 seconds")) + }) + It("should properly generate the webhook definition", func() { By("switching into testdata to appease go modules") cwd, err := os.Getwd() @@ -148,7 +176,101 @@ var _ = Describe("Webhook Generation From Parsing to CustomResourceDefinition", Expect(reg.Register(webhook.ConfigDefinition)).To(Succeed()) By("requesting that the manifest be generated") - outputDir, err := ioutil.TempDir("", "webhook-integration-test") + outputDir, err := os.MkdirTemp("", "webhook-integration-test") + Expect(err).NotTo(HaveOccurred()) + defer os.RemoveAll(outputDir) + genCtx := &genall.GenerationContext{ + Collector: &markers.Collector{Registry: reg}, + Roots: pkgs, + OutputRule: genall.OutputToDirectory(outputDir), + } + Expect(webhook.Generator{}.Generate(genCtx)).To(Succeed()) + for _, r := range genCtx.Roots { + Expect(r.Errors).To(HaveLen(0)) + } + + By("loading the generated v1 YAML") + actualFile, err := os.ReadFile(path.Join(outputDir, "manifests.yaml")) + Expect(err).NotTo(HaveOccurred()) + actualMutating, actualValidating := unmarshalBothV1(actualFile) + + By("loading the desired v1 YAML") + expectedFile, err := os.ReadFile("manifests.yaml") + Expect(err).NotTo(HaveOccurred()) + expectedMutating, expectedValidating := unmarshalBothV1(expectedFile) + + By("comparing the two") + assertSame(actualMutating, expectedMutating) + assertSame(actualValidating, expectedValidating) + }) + + It("should generate the ordered webhook definitions", func() { + By("switching into testdata to appease go modules") + cwd, err := os.Getwd() + Expect(err).NotTo(HaveOccurred()) + Expect(os.Chdir("./testdata/valid-ordered")).To(Succeed()) // go modules are directory-sensitive + defer func() { Expect(os.Chdir(cwd)).To(Succeed()) }() + + By("loading the roots") + pkgs, err := loader.LoadRoots(".") + Expect(err).NotTo(HaveOccurred()) + Expect(pkgs).To(HaveLen(1)) + + By("setting up the parser") + reg := &markers.Registry{} + Expect(reg.Register(webhook.ConfigDefinition)).To(Succeed()) + + By("requesting that the manifest be generated") + outputDir, err := os.MkdirTemp("", "webhook-integration-test") + Expect(err).NotTo(HaveOccurred()) + defer os.RemoveAll(outputDir) + + for i := 0; i < 10; i++ { + genCtx := &genall.GenerationContext{ + Collector: &markers.Collector{Registry: reg}, + Roots: pkgs, + OutputRule: genall.OutputToDirectory(outputDir), + } + Expect(webhook.Generator{}.Generate(genCtx)).To(Succeed()) + for _, r := range genCtx.Roots { + Expect(r.Errors).To(HaveLen(0)) + } + + By("loading the generated v1 YAML") + actualFile, err := os.ReadFile(path.Join(outputDir, "manifests.yaml")) + Expect(err).NotTo(HaveOccurred()) + actualManifest := &admissionregv1.ValidatingWebhookConfiguration{} + Expect(yaml.UnmarshalStrict(actualFile, actualManifest)).To(Succeed()) + + By("loading the desired v1 YAML") + expectedFile, err := os.ReadFile("manifests.yaml") + Expect(err).NotTo(HaveOccurred()) + expectedManifest := &admissionregv1.ValidatingWebhookConfiguration{} + Expect(yaml.UnmarshalStrict(expectedFile, expectedManifest)).To(Succeed()) + + By("comparing the manifest") + assertSame(actualManifest, expectedManifest) + } + }) + + It("should properly generate the webhook definition with url instead of service", func() { + By("switching into testdata to appease go modules") + cwd, err := os.Getwd() + Expect(err).NotTo(HaveOccurred()) + Expect(os.Chdir("./testdata/valid-url")).To(Succeed()) // go modules are directory-sensitive + defer func() { Expect(os.Chdir(cwd)).To(Succeed()) }() + + By("loading the roots") + pkgs, err := loader.LoadRoots(".") + Expect(err).NotTo(HaveOccurred()) + Expect(pkgs).To(HaveLen(1)) + + By("setting up the parser") + reg := &markers.Registry{} + Expect(reg.Register(webhook.ConfigDefinition)).To(Succeed()) + + By("requesting that the manifest be generated") + outputDir, err := os.MkdirTemp("", "webhook-integration-test") Expect(err).NotTo(HaveOccurred()) defer os.RemoveAll(outputDir) genCtx := &genall.GenerationContext{ @@ -162,12 +284,12 @@ var _ = Describe("Webhook Generation From Parsing to CustomResourceDefinition", } By("loading the generated v1 YAML") - actualFile, err := ioutil.ReadFile(path.Join(outputDir, "manifests.yaml")) + actualFile, err := os.ReadFile(path.Join(outputDir, "manifests.yaml")) Expect(err).NotTo(HaveOccurred()) actualMutating, actualValidating := unmarshalBothV1(actualFile) By("loading the desired v1 YAML") - expectedFile, err := ioutil.ReadFile("manifests.yaml") + expectedFile, err := os.ReadFile("manifests.yaml") Expect(err).NotTo(HaveOccurred()) expectedMutating, expectedValidating := unmarshalBothV1(expectedFile) @@ -175,6 +297,35 @@ var _ = Describe("Webhook Generation From Parsing to CustomResourceDefinition", assertSame(actualMutating, expectedMutating) assertSame(actualValidating, expectedValidating) }) + + It("should fail to generate when both path and url are set", func() { + By("switching into testdata to appease go modules") + cwd, err := os.Getwd() + Expect(err).NotTo(HaveOccurred()) + Expect(os.Chdir("./testdata/invalid-path-and-url")).To(Succeed()) // go modules are directory-sensitive + defer func() { Expect(os.Chdir(cwd)).To(Succeed()) }() + + By("loading the roots") + pkgs, err := loader.LoadRoots(".") + Expect(err).NotTo(HaveOccurred()) + Expect(pkgs).To(HaveLen(1)) + + By("setting up the parser") + reg := &markers.Registry{} + Expect(reg.Register(webhook.ConfigDefinition)).To(Succeed()) + + By("requesting that the manifest be generated") + outputDir, err := os.MkdirTemp("", "webhook-integration-test") + Expect(err).NotTo(HaveOccurred()) + defer os.RemoveAll(outputDir) + genCtx := &genall.GenerationContext{ + Collector: &markers.Collector{Registry: reg}, + Roots: pkgs, + OutputRule: genall.OutputToDirectory(outputDir), + } + err = webhook.Generator{}.Generate(genCtx) + Expect(err).To(HaveOccurred()) + }) }) func unmarshalBothV1(in []byte) (mutating admissionregv1.MutatingWebhookConfiguration, validating admissionregv1.ValidatingWebhookConfiguration) { diff --git a/pkg/webhook/testdata/invalid-admissionReviewVersionsRequired/manifests.yaml b/pkg/webhook/testdata/invalid-admissionReviewVersionsRequired/manifests.yaml index 059794d6d..829d286ba 100644 --- a/pkg/webhook/testdata/invalid-admissionReviewVersionsRequired/manifests.yaml +++ b/pkg/webhook/testdata/invalid-admissionReviewVersionsRequired/manifests.yaml @@ -2,7 +2,6 @@ apiVersion: admissionregistration.k8s.io/v1 kind: MutatingWebhookConfiguration metadata: - creationTimestamp: null name: mutating-webhook-configuration webhooks: - admissionReviewVersions: @@ -27,11 +26,11 @@ webhooks: resources: - cronjobs sideEffects: None + timeoutSeconds: 10 --- apiVersion: admissionregistration.k8s.io/v1 kind: ValidatingWebhookConfiguration metadata: - creationTimestamp: null name: validating-webhook-configuration webhooks: - admissionReviewVersions: @@ -56,6 +55,7 @@ webhooks: resources: - cronjobs sideEffects: None + timeoutSeconds: 10 - admissionReviewVersions: - v1 - v1beta1 @@ -78,3 +78,4 @@ webhooks: resources: - cronjobs sideEffects: NoneOnDryRun + timeoutSeconds: 10 diff --git a/pkg/webhook/testdata/invalid-admissionReviewVersionsRequired/webhook.go b/pkg/webhook/testdata/invalid-admissionReviewVersionsRequired/webhook.go index 4275ad3ed..5f8896840 100644 --- a/pkg/webhook/testdata/invalid-admissionReviewVersionsRequired/webhook.go +++ b/pkg/webhook/testdata/invalid-admissionReviewVersionsRequired/webhook.go @@ -27,9 +27,9 @@ func (c *CronJob) SetupWebhookWithManager(mgr ctrl.Manager) error { Complete() } -// +kubebuilder:webhook:webhookVersions=v1,verbs=create;update,path=/validate-testdata-kubebuilder-io-v1-cronjob,mutating=false,failurePolicy=fail,matchPolicy=Equivalent,groups=testdata.kubebuiler.io,resources=cronjobs,versions=v1,name=validation.cronjob.testdata.kubebuilder.io,sideEffects=None -// +kubebuilder:webhook:verbs=create;update,path=/validate-testdata-kubebuilder-io-v1-cronjob,mutating=false,failurePolicy=fail,matchPolicy=Equivalent,groups=testdata.kubebuiler.io,resources=cronjobs,versions=v1,name=validation.cronjob.testdata.kubebuilder.io,sideEffects=NoneOnDryRun,admissionReviewVersions=v1;v1beta1 -// +kubebuilder:webhook:webhookVersions=v1,verbs=create;update,path=/mutate-testdata-kubebuilder-io-v1-cronjob,mutating=true,failurePolicy=fail,matchPolicy=Equivalent,groups=testdata.kubebuiler.io,resources=cronjobs,versions=v1,name=default.cronjob.testdata.kubebuilder.io,sideEffects=None,admissionReviewVersions=v1;v1beta1 +// +kubebuilder:webhook:webhookVersions=v1,verbs=create;update,path=/validate-testdata-kubebuilder-io-v1-cronjob,mutating=false,failurePolicy=fail,matchPolicy=Equivalent,groups=testdata.kubebuiler.io,resources=cronjobs,versions=v1,name=validation.cronjob.testdata.kubebuilder.io,sideEffects=None,timeoutSeconds=10 +// +kubebuilder:webhook:verbs=create;update,path=/validate-testdata-kubebuilder-io-v1-cronjob,mutating=false,failurePolicy=fail,matchPolicy=Equivalent,groups=testdata.kubebuiler.io,resources=cronjobs,versions=v1,name=validation.cronjob.testdata.kubebuilder.io,sideEffects=NoneOnDryRun,timeoutSeconds=10,admissionReviewVersions=v1;v1beta1 +// +kubebuilder:webhook:webhookVersions=v1,verbs=create;update,path=/mutate-testdata-kubebuilder-io-v1-cronjob,mutating=true,failurePolicy=fail,matchPolicy=Equivalent,groups=testdata.kubebuiler.io,resources=cronjobs,versions=v1,name=default.cronjob.testdata.kubebuilder.io,sideEffects=None,timeoutSeconds=10,admissionReviewVersions=v1;v1beta1 var _ webhook.Defaulter = &CronJob{} var _ webhook.Validator = &CronJob{} diff --git a/pkg/webhook/testdata/invalid-path-and-url/cronjob_types.go b/pkg/webhook/testdata/invalid-path-and-url/cronjob_types.go new file mode 100644 index 000000000..4a95bf52a --- /dev/null +++ b/pkg/webhook/testdata/invalid-path-and-url/cronjob_types.go @@ -0,0 +1,71 @@ +/* + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT 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:generate ../../../../.run-controller-gen.sh webhook paths=. output:dir=. + +// +groupName=testdata.kubebuilder.io +// +versionName=v1 +package cronjob + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// 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. + +// CronJobSpec defines the desired state of CronJob +type CronJobSpec struct { + // The schedule in Cron format, see https://en.wikipedia.org/wiki/Cron. + Schedule string `json:"schedule"` +} + +// CronJobStatus defines the observed state of CronJob +type CronJobStatus struct { + // INSERT ADDITIONAL STATUS FIELD - define observed state of cluster + // Important: Run "make" to regenerate code after modifying this file + + // Information when was the last time the job was successfully scheduled. + // +optional + LastScheduleTime *metav1.Time `json:"lastScheduleTime,omitempty"` +} + +// +kubebuilder:object:root=true +// +kubebuilder:subresource:status +// +kubebuilder:resource:singular=mycronjob + +// CronJob is the Schema for the cronjobs API +type CronJob struct { + /* + */ + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec CronJobSpec `json:"spec,omitempty"` + Status CronJobStatus `json:"status,omitempty"` +} + +// +kubebuilder:object:root=true + +// CronJobList contains a list of CronJob +type CronJobList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []CronJob `json:"items"` +} + +func init() { + SchemeBuilder.Register(&CronJob{}, &CronJobList{}) +} diff --git a/pkg/webhook/testdata/invalid-path-and-url/webhook.go b/pkg/webhook/testdata/invalid-path-and-url/webhook.go new file mode 100644 index 000000000..61f562e71 --- /dev/null +++ b/pkg/webhook/testdata/invalid-path-and-url/webhook.go @@ -0,0 +1,48 @@ +/* + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package cronjob + +import ( + "k8s.io/apimachinery/pkg/runtime" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/webhook" +) + +func (c *CronJob) SetupWebhookWithManager(mgr ctrl.Manager) error { + return ctrl.NewWebhookManagedBy(mgr). + For(c). + Complete() +} + +// +kubebuilder:webhook:url="https://anothersomewebhook:9443/validate-testdata-kubebuilder-io-v1-cronjob",path="/somepath",verbs=create;update,mutating=false,failurePolicy=fail,matchPolicy=Equivalent,groups=testdata.kubebuiler.io,resources=cronjobs,versions=v1,name=validation.cronjob.testdata.kubebuilder.io,sideEffects=NoneOnDryRun,timeoutSeconds=10,admissionReviewVersions=v1;v1beta1 + +var _ webhook.Defaulter = &CronJob{} +var _ webhook.Validator = &CronJob{} + +func (c *CronJob) Default() { +} + +func (c *CronJob) ValidateCreate() error { + return nil +} + +func (c *CronJob) ValidateUpdate(_ runtime.Object) error { + return nil +} + +func (c *CronJob) ValidateDelete() error { + return nil +} diff --git a/pkg/webhook/testdata/invalid-sideEffects/manifests.yaml b/pkg/webhook/testdata/invalid-sideEffects/manifests.yaml index 059794d6d..829d286ba 100644 --- a/pkg/webhook/testdata/invalid-sideEffects/manifests.yaml +++ b/pkg/webhook/testdata/invalid-sideEffects/manifests.yaml @@ -2,7 +2,6 @@ apiVersion: admissionregistration.k8s.io/v1 kind: MutatingWebhookConfiguration metadata: - creationTimestamp: null name: mutating-webhook-configuration webhooks: - admissionReviewVersions: @@ -27,11 +26,11 @@ webhooks: resources: - cronjobs sideEffects: None + timeoutSeconds: 10 --- apiVersion: admissionregistration.k8s.io/v1 kind: ValidatingWebhookConfiguration metadata: - creationTimestamp: null name: validating-webhook-configuration webhooks: - admissionReviewVersions: @@ -56,6 +55,7 @@ webhooks: resources: - cronjobs sideEffects: None + timeoutSeconds: 10 - admissionReviewVersions: - v1 - v1beta1 @@ -78,3 +78,4 @@ webhooks: resources: - cronjobs sideEffects: NoneOnDryRun + timeoutSeconds: 10 diff --git a/pkg/webhook/testdata/invalid-sideEffects/webhook.go b/pkg/webhook/testdata/invalid-sideEffects/webhook.go index 70c05446a..87584690b 100644 --- a/pkg/webhook/testdata/invalid-sideEffects/webhook.go +++ b/pkg/webhook/testdata/invalid-sideEffects/webhook.go @@ -27,9 +27,9 @@ func (c *CronJob) SetupWebhookWithManager(mgr ctrl.Manager) error { Complete() } -// +kubebuilder:webhook:webhookVersions=v1,verbs=create;update,path=/validate-testdata-kubebuilder-io-v1-cronjob,mutating=false,failurePolicy=fail,matchPolicy=Equivalent,groups=testdata.kubebuiler.io,resources=cronjobs,versions=v1,name=validation.cronjob.testdata.kubebuilder.io,sideEffects=Some,admissionReviewVersions=v1;v1beta1 -// +kubebuilder:webhook:verbs=create;update,path=/validate-testdata-kubebuilder-io-v1-cronjob,mutating=false,failurePolicy=fail,matchPolicy=Equivalent,groups=testdata.kubebuiler.io,resources=cronjobs,versions=v1,name=validation.cronjob.testdata.kubebuilder.io,sideEffects=NoneOnDryRun,admissionReviewVersions=v1;v1beta1 -// +kubebuilder:webhook:webhookVersions=v1,verbs=create;update,path=/mutate-testdata-kubebuilder-io-v1-cronjob,mutating=true,failurePolicy=fail,matchPolicy=Equivalent,groups=testdata.kubebuiler.io,resources=cronjobs,versions=v1,name=default.cronjob.testdata.kubebuilder.io,sideEffects=None,admissionReviewVersions=v1;v1beta1 +// +kubebuilder:webhook:webhookVersions=v1,verbs=create;update,path=/validate-testdata-kubebuilder-io-v1-cronjob,mutating=false,failurePolicy=fail,matchPolicy=Equivalent,groups=testdata.kubebuiler.io,resources=cronjobs,versions=v1,name=validation.cronjob.testdata.kubebuilder.io,sideEffects=Some,timeoutSeconds=10,admissionReviewVersions=v1;v1beta1 +// +kubebuilder:webhook:verbs=create;update,path=/validate-testdata-kubebuilder-io-v1-cronjob,mutating=false,failurePolicy=fail,matchPolicy=Equivalent,groups=testdata.kubebuiler.io,resources=cronjobs,versions=v1,name=validation.cronjob.testdata.kubebuilder.io,sideEffects=NoneOnDryRun,timeoutSeconds=10,admissionReviewVersions=v1;v1beta1 +// +kubebuilder:webhook:webhookVersions=v1,verbs=create;update,path=/mutate-testdata-kubebuilder-io-v1-cronjob,mutating=true,failurePolicy=fail,matchPolicy=Equivalent,groups=testdata.kubebuiler.io,resources=cronjobs,versions=v1,name=default.cronjob.testdata.kubebuilder.io,sideEffects=None,timeoutSeconds=10,admissionReviewVersions=v1;v1beta1 var _ webhook.Defaulter = &CronJob{} var _ webhook.Validator = &CronJob{} diff --git a/pkg/webhook/testdata/invalid-timeoutSeconds/cronjob_types.go b/pkg/webhook/testdata/invalid-timeoutSeconds/cronjob_types.go new file mode 100644 index 000000000..4a95bf52a --- /dev/null +++ b/pkg/webhook/testdata/invalid-timeoutSeconds/cronjob_types.go @@ -0,0 +1,71 @@ +/* + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT 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:generate ../../../../.run-controller-gen.sh webhook paths=. output:dir=. + +// +groupName=testdata.kubebuilder.io +// +versionName=v1 +package cronjob + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// 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. + +// CronJobSpec defines the desired state of CronJob +type CronJobSpec struct { + // The schedule in Cron format, see https://en.wikipedia.org/wiki/Cron. + Schedule string `json:"schedule"` +} + +// CronJobStatus defines the observed state of CronJob +type CronJobStatus struct { + // INSERT ADDITIONAL STATUS FIELD - define observed state of cluster + // Important: Run "make" to regenerate code after modifying this file + + // Information when was the last time the job was successfully scheduled. + // +optional + LastScheduleTime *metav1.Time `json:"lastScheduleTime,omitempty"` +} + +// +kubebuilder:object:root=true +// +kubebuilder:subresource:status +// +kubebuilder:resource:singular=mycronjob + +// CronJob is the Schema for the cronjobs API +type CronJob struct { + /* + */ + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec CronJobSpec `json:"spec,omitempty"` + Status CronJobStatus `json:"status,omitempty"` +} + +// +kubebuilder:object:root=true + +// CronJobList contains a list of CronJob +type CronJobList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []CronJob `json:"items"` +} + +func init() { + SchemeBuilder.Register(&CronJob{}, &CronJobList{}) +} diff --git a/pkg/webhook/testdata/invalid-timeoutSeconds/manifests.yaml b/pkg/webhook/testdata/invalid-timeoutSeconds/manifests.yaml new file mode 100644 index 000000000..d65e06264 --- /dev/null +++ b/pkg/webhook/testdata/invalid-timeoutSeconds/manifests.yaml @@ -0,0 +1,83 @@ +--- +apiVersion: admissionregistration.k8s.io/v1 +kind: MutatingWebhookConfiguration +metadata: + creationTimestamp: null + name: mutating-webhook-configuration +webhooks: +- admissionReviewVersions: + - v1 + - v1beta1 + clientConfig: + service: + name: webhook-service + namespace: system + path: /mutate-testdata-kubebuilder-io-v1-cronjob + failurePolicy: Fail + matchPolicy: Equivalent + name: default.cronjob.testdata.kubebuilder.io + rules: + - apiGroups: + - testdata.kubebuiler.io + apiVersions: + - v1 + operations: + - CREATE + - UPDATE + resources: + - cronjobs + sideEffects: None + timeoutSeconds: 40 +--- +apiVersion: admissionregistration.k8s.io/v1 +kind: ValidatingWebhookConfiguration +metadata: + creationTimestamp: null + name: validating-webhook-configuration +webhooks: +- admissionReviewVersions: + - v1 + - v1beta1 + clientConfig: + service: + name: webhook-service + namespace: system + path: /validate-testdata-kubebuilder-io-v1-cronjob + failurePolicy: Fail + matchPolicy: Equivalent + name: validation.cronjob.testdata.kubebuilder.io + rules: + - apiGroups: + - testdata.kubebuiler.io + apiVersions: + - v1 + operations: + - CREATE + - UPDATE + resources: + - cronjobs + sideEffects: None + timeoutSeconds: 10 +- admissionReviewVersions: + - v1 + - v1beta1 + clientConfig: + service: + name: webhook-service + namespace: system + path: /validate-testdata-kubebuilder-io-v1-cronjob + failurePolicy: Fail + matchPolicy: Equivalent + name: validation.cronjob.testdata.kubebuilder.io + rules: + - apiGroups: + - testdata.kubebuiler.io + apiVersions: + - v1 + operations: + - CREATE + - UPDATE + resources: + - cronjobs + sideEffects: None + timeoutSeconds: -1 diff --git a/pkg/webhook/testdata/invalid-timeoutSeconds/webhook.go b/pkg/webhook/testdata/invalid-timeoutSeconds/webhook.go new file mode 100644 index 000000000..80e8e6c27 --- /dev/null +++ b/pkg/webhook/testdata/invalid-timeoutSeconds/webhook.go @@ -0,0 +1,50 @@ +/* + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package cronjob + +import ( + "k8s.io/apimachinery/pkg/runtime" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/webhook" +) + +func (c *CronJob) SetupWebhookWithManager(mgr ctrl.Manager) error { + return ctrl.NewWebhookManagedBy(mgr). + For(c). + Complete() +} + +// +kubebuilder:webhook:webhookVersions=v1,verbs=create;update,path=/validate-testdata-kubebuilder-io-v1-cronjob,mutating=false,failurePolicy=fail,matchPolicy=Equivalent,groups=testdata.kubebuiler.io,resources=cronjobs,versions=v1,name=validation.cronjob.testdata.kubebuilder.io,sideEffects=None,timeoutSeconds=40,admissionReviewVersions=v1;v1beta1 +// +kubebuilder:webhook:verbs=create;update,path=/validate-testdata-kubebuilder-io-v1-cronjob,mutating=false,failurePolicy=fail,matchPolicy=Equivalent,groups=testdata.kubebuiler.io,resources=cronjobs,versions=v1,name=validation.cronjob.testdata.kubebuilder.io,sideEffects=None,timeoutSeconds=10,admissionReviewVersions=v1;v1beta1 +// +kubebuilder:webhook:webhookVersions=v1,verbs=create;update,path=/mutate-testdata-kubebuilder-io-v1-cronjob,mutating=true,failurePolicy=fail,matchPolicy=Equivalent,groups=testdata.kubebuiler.io,resources=cronjobs,versions=v1,name=default.cronjob.testdata.kubebuilder.io,sideEffects=None,timeoutSeconds=-1,admissionReviewVersions=v1;v1beta1 + +var _ webhook.Defaulter = &CronJob{} +var _ webhook.Validator = &CronJob{} + +func (c *CronJob) Default() { +} + +func (c *CronJob) ValidateCreate() error { + return nil +} + +func (c *CronJob) ValidateUpdate(_ runtime.Object) error { + return nil +} + +func (c *CronJob) ValidateDelete() error { + return nil +} diff --git a/pkg/webhook/testdata/invalid-v1beta1NotSupported/manifests.yaml b/pkg/webhook/testdata/invalid-v1beta1NotSupported/manifests.yaml index 059794d6d..829d286ba 100644 --- a/pkg/webhook/testdata/invalid-v1beta1NotSupported/manifests.yaml +++ b/pkg/webhook/testdata/invalid-v1beta1NotSupported/manifests.yaml @@ -2,7 +2,6 @@ apiVersion: admissionregistration.k8s.io/v1 kind: MutatingWebhookConfiguration metadata: - creationTimestamp: null name: mutating-webhook-configuration webhooks: - admissionReviewVersions: @@ -27,11 +26,11 @@ webhooks: resources: - cronjobs sideEffects: None + timeoutSeconds: 10 --- apiVersion: admissionregistration.k8s.io/v1 kind: ValidatingWebhookConfiguration metadata: - creationTimestamp: null name: validating-webhook-configuration webhooks: - admissionReviewVersions: @@ -56,6 +55,7 @@ webhooks: resources: - cronjobs sideEffects: None + timeoutSeconds: 10 - admissionReviewVersions: - v1 - v1beta1 @@ -78,3 +78,4 @@ webhooks: resources: - cronjobs sideEffects: NoneOnDryRun + timeoutSeconds: 10 diff --git a/pkg/webhook/testdata/invalid-v1beta1NotSupported/webhook.go b/pkg/webhook/testdata/invalid-v1beta1NotSupported/webhook.go index f717d4ed3..81dc82d9a 100644 --- a/pkg/webhook/testdata/invalid-v1beta1NotSupported/webhook.go +++ b/pkg/webhook/testdata/invalid-v1beta1NotSupported/webhook.go @@ -27,9 +27,9 @@ func (c *CronJob) SetupWebhookWithManager(mgr ctrl.Manager) error { Complete() } -// +kubebuilder:webhook:webhookVersions=v1beta1,verbs=create;update,path=/validate-testdata-kubebuilder-io-v1-cronjob,mutating=false,failurePolicy=fail,matchPolicy=Equivalent,groups=testdata.kubebuiler.io,resources=cronjobs,versions=v1,name=validation.cronjob.testdata.kubebuilder.io,sideEffects=None,admissionReviewVersions=v1;v1beta1 -// +kubebuilder:webhook:verbs=create;update,path=/validate-testdata-kubebuilder-io-v1-cronjob,mutating=false,failurePolicy=fail,matchPolicy=Equivalent,groups=testdata.kubebuiler.io,resources=cronjobs,versions=v1,name=validation.cronjob.testdata.kubebuilder.io,sideEffects=NoneOnDryRun,admissionReviewVersions=v1;v1beta1 -// +kubebuilder:webhook:webhookVersions=v1,verbs=create;update,path=/mutate-testdata-kubebuilder-io-v1-cronjob,mutating=true,failurePolicy=fail,matchPolicy=Equivalent,groups=testdata.kubebuiler.io,resources=cronjobs,versions=v1,name=default.cronjob.testdata.kubebuilder.io,sideEffects=None,admissionReviewVersions=v1;v1beta1 +// +kubebuilder:webhook:webhookVersions=v1beta1,verbs=create;update,path=/validate-testdata-kubebuilder-io-v1-cronjob,mutating=false,failurePolicy=fail,matchPolicy=Equivalent,groups=testdata.kubebuiler.io,resources=cronjobs,versions=v1,name=validation.cronjob.testdata.kubebuilder.io,sideEffects=None,timeoutSeconds=10,admissionReviewVersions=v1;v1beta1 +// +kubebuilder:webhook:verbs=create;update,path=/validate-testdata-kubebuilder-io-v1-cronjob,mutating=false,failurePolicy=fail,matchPolicy=Equivalent,groups=testdata.kubebuiler.io,resources=cronjobs,versions=v1,name=validation.cronjob.testdata.kubebuilder.io,sideEffects=NoneOnDryRun,timeoutSeconds=10,admissionReviewVersions=v1;v1beta1 +// +kubebuilder:webhook:webhookVersions=v1,verbs=create;update,path=/mutate-testdata-kubebuilder-io-v1-cronjob,mutating=true,failurePolicy=fail,matchPolicy=Equivalent,groups=testdata.kubebuiler.io,resources=cronjobs,versions=v1,name=default.cronjob.testdata.kubebuilder.io,sideEffects=None,timeoutSeconds=10,admissionReviewVersions=v1;v1beta1 var _ webhook.Defaulter = &CronJob{} var _ webhook.Validator = &CronJob{} diff --git a/pkg/webhook/testdata/manifests.yaml b/pkg/webhook/testdata/manifests.yaml index ab4fdc85f..e9d0ec43a 100644 --- a/pkg/webhook/testdata/manifests.yaml +++ b/pkg/webhook/testdata/manifests.yaml @@ -2,7 +2,6 @@ apiVersion: admissionregistration.k8s.io/v1 kind: MutatingWebhookConfiguration metadata: - creationTimestamp: null name: mutating-webhook-configuration webhooks: - admissionReviewVersions: @@ -28,11 +27,11 @@ webhooks: resources: - cronjobs sideEffects: None + timeoutSeconds: 10 --- apiVersion: admissionregistration.k8s.io/v1 kind: ValidatingWebhookConfiguration metadata: - creationTimestamp: null name: validating-webhook-configuration webhooks: - admissionReviewVersions: @@ -57,6 +56,7 @@ webhooks: resources: - cronjobs sideEffects: None + timeoutSeconds: 10 - admissionReviewVersions: - v1 - v1beta1 @@ -79,3 +79,4 @@ webhooks: resources: - cronjobs sideEffects: NoneOnDryRun + timeoutSeconds: 10 diff --git a/pkg/webhook/testdata/valid-ordered/cronjob_types.go b/pkg/webhook/testdata/valid-ordered/cronjob_types.go new file mode 100644 index 000000000..9144b496f --- /dev/null +++ b/pkg/webhook/testdata/valid-ordered/cronjob_types.go @@ -0,0 +1,71 @@ +/* + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT 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:generate ../../../.run-controller-gen.sh webhook paths=. output:dir=. + +// +groupName=testdata.kubebuilder.io +// +versionName=v1 +package cronjob + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// 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. + +// CronJobSpec defines the desired state of CronJob +type CronJobSpec struct { + // The schedule in Cron format, see https://en.wikipedia.org/wiki/Cron. + Schedule string `json:"schedule"` +} + +// CronJobStatus defines the observed state of CronJob +type CronJobStatus struct { + // INSERT ADDITIONAL STATUS FIELD - define observed state of cluster + // Important: Run "make" to regenerate code after modifying this file + + // Information when was the last time the job was successfully scheduled. + // +optional + LastScheduleTime *metav1.Time `json:"lastScheduleTime,omitempty"` +} + +// +kubebuilder:object:root=true +// +kubebuilder:subresource:status +// +kubebuilder:resource:singular=mycronjob + +// CronJob is the Schema for the cronjobs API +type CronJob struct { + /* + */ + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec CronJobSpec `json:"spec,omitempty"` + Status CronJobStatus `json:"status,omitempty"` +} + +// +kubebuilder:object:root=true + +// CronJobList contains a list of CronJob +type CronJobList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []CronJob `json:"items"` +} + +func init() { + SchemeBuilder.Register(&CronJob{}, &CronJobList{}) +} diff --git a/pkg/webhook/testdata/valid-ordered/manifests.yaml b/pkg/webhook/testdata/valid-ordered/manifests.yaml new file mode 100644 index 000000000..a83b088a3 --- /dev/null +++ b/pkg/webhook/testdata/valid-ordered/manifests.yaml @@ -0,0 +1,72 @@ +--- +apiVersion: admissionregistration.k8s.io/v1 +kind: ValidatingWebhookConfiguration +metadata: + name: validating-webhook-configuration +webhooks: +- admissionReviewVersions: + - v1 + - v1beta1 + clientConfig: + service: + name: webhook-service + namespace: system + path: /validate-testdata-kubebuilder-io-v1-cronjob + failurePolicy: Fail + matchPolicy: Equivalent + name: cronjob.testdata.kubebuilder.io + rules: + - apiGroups: + - testdata.kubebuiler.io + apiVersions: + - v1 + operations: + - CREATE + - UPDATE + resources: + - cronjobs + sideEffects: None +- admissionReviewVersions: + - v1 + - v1beta1 + clientConfig: + service: + name: webhook-service + namespace: system + path: /validate-testdata-kubebuilder-io-v1-cronjoblist + failurePolicy: Fail + matchPolicy: Equivalent + name: cronjoblist.testdata.kubebuilder.io + rules: + - apiGroups: + - testdata.kubebuiler.io + apiVersions: + - v1 + operations: + - CREATE + - UPDATE + resources: + - cronjoblist + sideEffects: None +- admissionReviewVersions: + - v1 + - v1beta1 + clientConfig: + service: + name: webhook-service + namespace: system + path: /validate-testdata-kubebuilder-io-v1-deployments + failurePolicy: Fail + matchPolicy: Equivalent + name: deployment.testdata.kubebuilder.io + rules: + - apiGroups: + - testdata.kubebuiler.io + apiVersions: + - v1 + operations: + - CREATE + - UPDATE + resources: + - deployments + sideEffects: None diff --git a/pkg/webhook/testdata/valid-ordered/webhook.go b/pkg/webhook/testdata/valid-ordered/webhook.go new file mode 100644 index 000000000..c23b7a378 --- /dev/null +++ b/pkg/webhook/testdata/valid-ordered/webhook.go @@ -0,0 +1,84 @@ +/* + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package cronjob + +import ( + "context" + + "k8s.io/apimachinery/pkg/runtime" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +func (c *CronJob) SetupWebhookWithManager(mgr ctrl.Manager) error { + return ctrl.NewWebhookManagedBy(mgr). + For(c). + Complete() +} + +// +kubebuilder:webhook:webhookVersions=v1,verbs=create;update,path=/validate-testdata-kubebuilder-io-v1-cronjob,mutating=false,failurePolicy=fail,matchPolicy=Equivalent,groups=testdata.kubebuiler.io,resources=cronjobs,versions=v1,name=cronjob.testdata.kubebuilder.io,sideEffects=None,admissionReviewVersions=v1;v1beta1,reinvocationPolicy=Never + +type cronJobValidator struct { + client client.Client +} + +func (v cronJobValidator) ValidateCreate(ctx context.Context, obj runtime.Object) error { + return nil +} + +func (v cronJobValidator) ValidateUpdate(ctx context.Context, oldObj, newObj runtime.Object) error { + return nil +} + +func (v cronJobValidator) ValidateDelete(ctx context.Context, obj runtime.Object) error { + return nil +} + +// +kubebuilder:webhook:webhookVersions=v1,verbs=create;update,path=/validate-testdata-kubebuilder-io-v1-cronjoblist,mutating=false,failurePolicy=fail,matchPolicy=Equivalent,groups=testdata.kubebuiler.io,resources=cronjoblist,versions=v1,name=cronjoblist.testdata.kubebuilder.io,sideEffects=None,admissionReviewVersions=v1;v1beta1,reinvocationPolicy=Never + +type cronjobListValidator struct { + client client.Client +} + +func (v cronJobListValidator) ValidateCreate(ctx context.Context, obj runtime.Object) error { + return nil +} + +func (v cronJobListValidator) ValidateUpdate(ctx context.Context, oldObj, newObj runtime.Object) error { + return nil +} + +func (v cronJobListValidator) ValidateDelete(ctx context.Context, obj runtime.Object) error { + return nil +} + +// +kubebuilder:webhook:webhookVersions=v1,verbs=create;update,path=/validate-testdata-kubebuilder-io-v1-deployments,mutating=false,failurePolicy=fail,matchPolicy=Equivalent,groups=testdata.kubebuiler.io,resources=deployments,versions=v1,name=deployment.testdata.kubebuilder.io,sideEffects=None,admissionReviewVersions=v1;v1beta1,reinvocationPolicy=Never + +type deploymentValidator struct { + client client.Client +} + +func (v deploymentValidator) ValidateCreate(ctx context.Context, obj runtime.Object) error { + return nil +} + +func (v deploymentValidator) ValidateUpdate(ctx context.Context, oldObj, newObj runtime.Object) error { + return nil +} + +func (v deploymentValidator) ValidateDelete(ctx context.Context, obj runtime.Object) error { + return nil +} diff --git a/pkg/webhook/testdata/valid-url/cronjob_types.go b/pkg/webhook/testdata/valid-url/cronjob_types.go new file mode 100644 index 000000000..4a95bf52a --- /dev/null +++ b/pkg/webhook/testdata/valid-url/cronjob_types.go @@ -0,0 +1,71 @@ +/* + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT 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:generate ../../../../.run-controller-gen.sh webhook paths=. output:dir=. + +// +groupName=testdata.kubebuilder.io +// +versionName=v1 +package cronjob + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// 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. + +// CronJobSpec defines the desired state of CronJob +type CronJobSpec struct { + // The schedule in Cron format, see https://en.wikipedia.org/wiki/Cron. + Schedule string `json:"schedule"` +} + +// CronJobStatus defines the observed state of CronJob +type CronJobStatus struct { + // INSERT ADDITIONAL STATUS FIELD - define observed state of cluster + // Important: Run "make" to regenerate code after modifying this file + + // Information when was the last time the job was successfully scheduled. + // +optional + LastScheduleTime *metav1.Time `json:"lastScheduleTime,omitempty"` +} + +// +kubebuilder:object:root=true +// +kubebuilder:subresource:status +// +kubebuilder:resource:singular=mycronjob + +// CronJob is the Schema for the cronjobs API +type CronJob struct { + /* + */ + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec CronJobSpec `json:"spec,omitempty"` + Status CronJobStatus `json:"status,omitempty"` +} + +// +kubebuilder:object:root=true + +// CronJobList contains a list of CronJob +type CronJobList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []CronJob `json:"items"` +} + +func init() { + SchemeBuilder.Register(&CronJob{}, &CronJobList{}) +} diff --git a/pkg/webhook/testdata/valid-url/manifests.yaml b/pkg/webhook/testdata/valid-url/manifests.yaml new file mode 100644 index 000000000..0f1edc5d3 --- /dev/null +++ b/pkg/webhook/testdata/valid-url/manifests.yaml @@ -0,0 +1,76 @@ +--- +apiVersion: admissionregistration.k8s.io/v1 +kind: MutatingWebhookConfiguration +metadata: + name: mutating-webhook-configuration +webhooks: +- admissionReviewVersions: + - v1 + - v1beta1 + clientConfig: + service: + name: webhook-service + namespace: system + path: /mutate-testdata-kubebuilder-io-v1-cronjob + failurePolicy: Fail + matchPolicy: Equivalent + name: default.cronjob.testdata.kubebuilder.io + rules: + - apiGroups: + - testdata.kubebuiler.io + apiVersions: + - v1 + operations: + - CREATE + - UPDATE + resources: + - cronjobs + sideEffects: None + timeoutSeconds: 10 + reinvocationPolicy: IfNeeded +--- +apiVersion: admissionregistration.k8s.io/v1 +kind: ValidatingWebhookConfiguration +metadata: + name: validating-webhook-configuration +webhooks: +- admissionReviewVersions: + - v1 + - v1beta1 + clientConfig: + url: https://somewebhook:9443/validate-testdata-kubebuilder-io-v1-cronjob + failurePolicy: Fail + matchPolicy: Equivalent + name: validation.cronjob.testdata.kubebuilder.io + rules: + - apiGroups: + - testdata.kubebuiler.io + apiVersions: + - v1 + operations: + - CREATE + - UPDATE + resources: + - cronjobs + sideEffects: None + timeoutSeconds: 10 +- admissionReviewVersions: + - v1 + - v1beta1 + clientConfig: + url: https://anothersomewebhook:9443/validate-testdata-kubebuilder-io-v1-cronjob + failurePolicy: Fail + matchPolicy: Equivalent + name: validation.cronjob.testdata.kubebuilder.io + rules: + - apiGroups: + - testdata.kubebuiler.io + apiVersions: + - v1 + operations: + - CREATE + - UPDATE + resources: + - cronjobs + sideEffects: NoneOnDryRun + timeoutSeconds: 10 diff --git a/pkg/webhook/testdata/valid-url/webhook.go b/pkg/webhook/testdata/valid-url/webhook.go new file mode 100644 index 000000000..4ceefe691 --- /dev/null +++ b/pkg/webhook/testdata/valid-url/webhook.go @@ -0,0 +1,50 @@ +/* + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package cronjob + +import ( + "k8s.io/apimachinery/pkg/runtime" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/webhook" +) + +func (c *CronJob) SetupWebhookWithManager(mgr ctrl.Manager) error { + return ctrl.NewWebhookManagedBy(mgr). + For(c). + Complete() +} + +// +kubebuilder:webhook:webhookVersions=v1,verbs=create;update,mutating=false,failurePolicy=fail,matchPolicy=Equivalent,groups=testdata.kubebuiler.io,resources=cronjobs,versions=v1,name=validation.cronjob.testdata.kubebuilder.io,sideEffects=None,timeoutSeconds=10,admissionReviewVersions=v1;v1beta1,url="https://somewebhook:9443/validate-testdata-kubebuilder-io-v1-cronjob" +// +kubebuilder:webhook:url="https://anothersomewebhook:9443/validate-testdata-kubebuilder-io-v1-cronjob",verbs=create;update,mutating=false,failurePolicy=fail,matchPolicy=Equivalent,groups=testdata.kubebuiler.io,resources=cronjobs,versions=v1,name=validation.cronjob.testdata.kubebuilder.io,sideEffects=NoneOnDryRun,timeoutSeconds=10,admissionReviewVersions=v1;v1beta1 +// +kubebuilder:webhook:webhookVersions=v1,verbs=create;update,path=/mutate-testdata-kubebuilder-io-v1-cronjob,mutating=true,failurePolicy=fail,matchPolicy=Equivalent,groups=testdata.kubebuiler.io,resources=cronjobs,versions=v1,name=default.cronjob.testdata.kubebuilder.io,sideEffects=None,timeoutSeconds=10,admissionReviewVersions=v1;v1beta1,reinvocationPolicy=IfNeeded + +var _ webhook.Defaulter = &CronJob{} +var _ webhook.Validator = &CronJob{} + +func (c *CronJob) Default() { +} + +func (c *CronJob) ValidateCreate() error { + return nil +} + +func (c *CronJob) ValidateUpdate(_ runtime.Object) error { + return nil +} + +func (c *CronJob) ValidateDelete() error { + return nil +} diff --git a/pkg/webhook/testdata/valid/manifests.yaml b/pkg/webhook/testdata/valid/manifests.yaml index ce3836ddd..9a2011559 100644 --- a/pkg/webhook/testdata/valid/manifests.yaml +++ b/pkg/webhook/testdata/valid/manifests.yaml @@ -2,7 +2,6 @@ apiVersion: admissionregistration.k8s.io/v1 kind: MutatingWebhookConfiguration metadata: - creationTimestamp: null name: mutating-webhook-configuration webhooks: - admissionReviewVersions: @@ -27,12 +26,12 @@ webhooks: resources: - cronjobs sideEffects: None + timeoutSeconds: 10 reinvocationPolicy: IfNeeded --- apiVersion: admissionregistration.k8s.io/v1 kind: ValidatingWebhookConfiguration metadata: - creationTimestamp: null name: validating-webhook-configuration webhooks: - admissionReviewVersions: @@ -57,6 +56,7 @@ webhooks: resources: - cronjobs sideEffects: None + timeoutSeconds: 10 - admissionReviewVersions: - v1 - v1beta1 @@ -79,3 +79,4 @@ webhooks: resources: - cronjobs sideEffects: NoneOnDryRun + timeoutSeconds: 10 diff --git a/pkg/webhook/testdata/valid/webhook.go b/pkg/webhook/testdata/valid/webhook.go index 2ea3c31d2..9e8685278 100644 --- a/pkg/webhook/testdata/valid/webhook.go +++ b/pkg/webhook/testdata/valid/webhook.go @@ -27,9 +27,9 @@ func (c *CronJob) SetupWebhookWithManager(mgr ctrl.Manager) error { Complete() } -// +kubebuilder:webhook:webhookVersions=v1,verbs=create;update,path=/validate-testdata-kubebuilder-io-v1-cronjob,mutating=false,failurePolicy=fail,matchPolicy=Equivalent,groups=testdata.kubebuiler.io,resources=cronjobs,versions=v1,name=validation.cronjob.testdata.kubebuilder.io,sideEffects=None,admissionReviewVersions=v1;v1beta1 -// +kubebuilder:webhook:verbs=create;update,path=/validate-testdata-kubebuilder-io-v1-cronjob,mutating=false,failurePolicy=fail,matchPolicy=Equivalent,groups=testdata.kubebuiler.io,resources=cronjobs,versions=v1,name=validation.cronjob.testdata.kubebuilder.io,sideEffects=NoneOnDryRun,admissionReviewVersions=v1;v1beta1 -// +kubebuilder:webhook:webhookVersions=v1,verbs=create;update,path=/mutate-testdata-kubebuilder-io-v1-cronjob,mutating=true,failurePolicy=fail,matchPolicy=Equivalent,groups=testdata.kubebuiler.io,resources=cronjobs,versions=v1,name=default.cronjob.testdata.kubebuilder.io,sideEffects=None,admissionReviewVersions=v1;v1beta1,reinvocationPolicy=IfNeeded +// +kubebuilder:webhook:webhookVersions=v1,verbs=create;update,path=/validate-testdata-kubebuilder-io-v1-cronjob,mutating=false,failurePolicy=fail,matchPolicy=Equivalent,groups=testdata.kubebuiler.io,resources=cronjobs,versions=v1,name=validation.cronjob.testdata.kubebuilder.io,sideEffects=None,timeoutSeconds=10,admissionReviewVersions=v1;v1beta1 +// +kubebuilder:webhook:verbs=create;update,path=/validate-testdata-kubebuilder-io-v1-cronjob,mutating=false,failurePolicy=fail,matchPolicy=Equivalent,groups=testdata.kubebuiler.io,resources=cronjobs,versions=v1,name=validation.cronjob.testdata.kubebuilder.io,sideEffects=NoneOnDryRun,timeoutSeconds=10,admissionReviewVersions=v1;v1beta1 +// +kubebuilder:webhook:webhookVersions=v1,verbs=create;update,path=/mutate-testdata-kubebuilder-io-v1-cronjob,mutating=true,failurePolicy=fail,matchPolicy=Equivalent,groups=testdata.kubebuiler.io,resources=cronjobs,versions=v1,name=default.cronjob.testdata.kubebuilder.io,sideEffects=None,timeoutSeconds=10,admissionReviewVersions=v1;v1beta1,reinvocationPolicy=IfNeeded var _ webhook.Defaulter = &CronJob{} var _ webhook.Validator = &CronJob{} diff --git a/pkg/webhook/testdata/webhook.go b/pkg/webhook/testdata/webhook.go index 41a69d706..7b94d264e 100644 --- a/pkg/webhook/testdata/webhook.go +++ b/pkg/webhook/testdata/webhook.go @@ -27,9 +27,9 @@ func (c *CronJob) SetupWebhookWithManager(mgr ctrl.Manager) error { Complete() } -// +kubebuilder:webhook:webhookVersions=v1,verbs=create;update,path=/validate-testdata-kubebuilder-io-v1-cronjob,mutating=false,failurePolicy=fail,matchPolicy=Equivalent,groups=testdata.kubebuiler.io,resources=cronjobs,versions=v1,name=validation.cronjob.testdata.kubebuilder.io,sideEffects=None,admissionReviewVersions=v1;v1beta1 -// +kubebuilder:webhook:verbs=create;update,path=/validate-testdata-kubebuilder-io-v1-cronjob,mutating=false,failurePolicy=fail,matchPolicy=Equivalent,groups=testdata.kubebuiler.io,resources=cronjobs,versions=v1,name=validation.cronjob.testdata.kubebuilder.io,sideEffects=NoneOnDryRun,admissionReviewVersions=v1;v1beta1 -// +kubebuilder:webhook:webhookVersions=v1,verbs=create;update,path=/mutate-testdata-kubebuilder-io-v1-cronjob,mutating=true,failurePolicy=fail,matchPolicy=Equivalent,groups=testdata.kubebuiler.io,resources=cronjobs,versions=v1,name=default.cronjob.testdata.kubebuilder.io,sideEffects=None,admissionReviewVersions=v1;v1beta1,reinvocationPolicy=Never +// +kubebuilder:webhook:webhookVersions=v1,verbs=create;update,path=/validate-testdata-kubebuilder-io-v1-cronjob,mutating=false,failurePolicy=fail,matchPolicy=Equivalent,groups=testdata.kubebuiler.io,resources=cronjobs,versions=v1,name=validation.cronjob.testdata.kubebuilder.io,sideEffects=None,timeoutSeconds=10,admissionReviewVersions=v1;v1beta1 +// +kubebuilder:webhook:verbs=create;update,path=/validate-testdata-kubebuilder-io-v1-cronjob,mutating=false,failurePolicy=fail,matchPolicy=Equivalent,groups=testdata.kubebuiler.io,resources=cronjobs,versions=v1,name=validation.cronjob.testdata.kubebuilder.io,sideEffects=NoneOnDryRun,timeoutSeconds=10,admissionReviewVersions=v1;v1beta1 +// +kubebuilder:webhook:webhookVersions=v1,verbs=create;update,path=/mutate-testdata-kubebuilder-io-v1-cronjob,mutating=true,failurePolicy=fail,matchPolicy=Equivalent,groups=testdata.kubebuiler.io,resources=cronjobs,versions=v1,name=default.cronjob.testdata.kubebuilder.io,sideEffects=None,timeoutSeconds=10,admissionReviewVersions=v1;v1beta1,reinvocationPolicy=Never var _ webhook.Defaulter = &CronJob{} var _ webhook.Validator = &CronJob{} diff --git a/pkg/webhook/zz_generated.markerhelp.go b/pkg/webhook/zz_generated.markerhelp.go index 411c58e17..d40bcc81f 100644 --- a/pkg/webhook/zz_generated.markerhelp.go +++ b/pkg/webhook/zz_generated.markerhelp.go @@ -1,5 +1,4 @@ //go:build !ignore_autogenerated -// +build !ignore_autogenerated /* Copyright2019 The Kubernetes Authors. @@ -29,25 +28,29 @@ func (Config) Help() *markers.DefinitionHelp { return &markers.DefinitionHelp{ Category: "Webhook", DetailedHelp: markers.DetailedHelp{ - Summary: "specifies how a webhook should be served. ", - Details: "It specifies only the details that are intrinsic to the application serving it (e.g. the resources it can handle, or the path it serves on).", + Summary: "specifies how a webhook should be served.", + Details: "It specifies only the details that are intrinsic to the application serving\nit (e.g. the resources it can handle, or the path it serves on).", }, FieldHelp: map[string]markers.DetailedHelp{ "Mutating": { - Summary: "marks this as a mutating webhook (it's validating only if false) ", - Details: "Mutating webhooks are allowed to change the object in their response, and are called *before* all validating webhooks. Mutating webhooks may choose to reject an object, similarly to a validating webhook.", + Summary: "marks this as a mutating webhook (it's validating only if false)", + Details: "Mutating webhooks are allowed to change the object in their response,\nand are called *before* all validating webhooks. Mutating webhooks may\nchoose to reject an object, similarly to a validating webhook.", }, "FailurePolicy": { - Summary: "specifies what should happen if the API server cannot reach the webhook. ", - Details: "It may be either \"ignore\" (to skip the webhook and continue on) or \"fail\" (to reject the object in question).", + Summary: "specifies what should happen if the API server cannot reach the webhook.", + Details: "It may be either \"ignore\" (to skip the webhook and continue on) or \"fail\" (to reject\nthe object in question).", }, "MatchPolicy": { - Summary: "defines how the \"rules\" list is used to match incoming requests. Allowed values are \"Exact\" (match only if it exactly matches the specified rule) or \"Equivalent\" (match a request if it modifies a resource listed in rules, even via another API group or version).", - Details: "", + Summary: "defines how the \"rules\" list is used to match incoming requests.", + Details: "Allowed values are \"Exact\" (match only if it exactly matches the specified rule)\nor \"Equivalent\" (match a request if it modifies a resource listed in rules, even via another API group or version).", }, "SideEffects": { - Summary: "specify whether calling the webhook will have side effects. This has an impact on dry runs and `kubectl diff`: if the sideEffect is \"Unknown\" (the default) or \"Some\", then the API server will not call the webhook on a dry-run request and fails instead. If the value is \"None\", then the webhook has no side effects and the API server will call it on dry-run. If the value is \"NoneOnDryRun\", then the webhook is responsible for inspecting the \"dryRun\" property of the AdmissionReview sent in the request, and avoiding side effects if that value is \"true.\"", - Details: "", + Summary: "specify whether calling the webhook will have side effects.", + Details: "This has an impact on dry runs and `kubectl diff`: if the sideEffect is \"Unknown\" (the default) or \"Some\", then\nthe API server will not call the webhook on a dry-run request and fails instead.\nIf the value is \"None\", then the webhook has no side effects and the API server will call it on dry-run.\nIf the value is \"NoneOnDryRun\", then the webhook is responsible for inspecting the \"dryRun\" property of the\nAdmissionReview sent in the request, and avoiding side effects if that value is \"true.\"", + }, + "TimeoutSeconds": { + Summary: "allows configuring how long the API server should wait for a webhook to respond before treating the call as a failure.", + Details: "If the timeout expires before the webhook responds, the webhook call will be ignored or the API call will be rejected based on the failure policy.\nThe timeout value must be between 1 and 30 seconds.\nThe timeout for an admission webhook defaults to 10 seconds.", }, "Groups": { Summary: "specifies the API groups that this webhook receives requests for.", @@ -58,8 +61,8 @@ func (Config) Help() *markers.DefinitionHelp { Details: "", }, "Verbs": { - Summary: "specifies the Kubernetes API verbs that this webhook receives requests for. ", - Details: "Only modification-like verbs may be specified. May be \"create\", \"update\", \"delete\", \"connect\", or \"*\" (for all).", + Summary: "specifies the Kubernetes API verbs that this webhook receives requests for.", + Details: "Only modification-like verbs may be specified.\nMay be \"create\", \"update\", \"delete\", \"connect\", or \"*\" (for all).", }, "Versions": { Summary: "specifies the API versions that this webhook receives requests for.", @@ -70,20 +73,24 @@ func (Config) Help() *markers.DefinitionHelp { Details: "", }, "Path": { - Summary: "specifies that path that the API server should connect to this webhook on. Must be prefixed with a '/validate-' or '/mutate-' depending on the type, and followed by $GROUP-$VERSION-$KIND where all values are lower-cased and the periods in the group are substituted for hyphens. For example, a validating webhook path for type batch.tutorial.kubebuilder.io/v1,Kind=CronJob would be /validate-batch-tutorial-kubebuilder-io-v1-cronjob", - Details: "", + Summary: "specifies that path that the API server should connect to this webhook on. Must be", + Details: "prefixed with a '/validate-' or '/mutate-' depending on the type, and followed by\n$GROUP-$VERSION-$KIND where all values are lower-cased and the periods in the group\nare substituted for hyphens. For example, a validating webhook path for type\nbatch.tutorial.kubebuilder.io/v1,Kind=CronJob would be\n/validate-batch-tutorial-kubebuilder-io-v1-cronjob", }, "WebhookVersions": { - Summary: "specifies the target API versions of the {Mutating,Validating}WebhookConfiguration objects itself to generate. The only supported value is v1. Defaults to v1.", - Details: "", + Summary: "specifies the target API versions of the {Mutating,Validating}WebhookConfiguration objects", + Details: "itself to generate. The only supported value is v1. Defaults to v1.", }, "AdmissionReviewVersions": { - Summary: "is an ordered list of preferred `AdmissionReview` versions the Webhook expects.", - Details: "", + Summary: "is an ordered list of preferred `AdmissionReview`", + Details: "versions the Webhook expects.", }, "ReinvocationPolicy": { - Summary: "allows mutating webhooks to request reinvocation after other mutations ", - Details: "To allow mutating admission plugins to observe changes made by other plugins, built-in mutating admission plugins are re-run if a mutating webhook modifies an object, and mutating webhooks can specify a reinvocationPolicy to control whether they are reinvoked as well.", + Summary: "allows mutating webhooks to request reinvocation after other mutations", + Details: "To allow mutating admission plugins to observe changes made by other plugins,\nbuilt-in mutating admission plugins are re-run if a mutating webhook modifies\nan object, and mutating webhooks can specify a reinvocationPolicy to control\nwhether they are reinvoked as well.", + }, + "URL": { + Summary: "allows mutating webhooks configuration to specify an external URL when generating", + Details: "the manifests, instead of using the internal service communication. Should be in format of\nhttps://address:port/path\nWhen this option is specified, the serviceConfig.Service is removed from webhook the manifest.\nThe URL configuration should be between quotes.\n`url` cannot be specified when `path` is specified.", }, }, } @@ -96,6 +103,15 @@ func (Generator) Help() *markers.DefinitionHelp { Summary: "generates (partial) {Mutating,Validating}WebhookConfiguration objects.", Details: "", }, - FieldHelp: map[string]markers.DetailedHelp{}, + FieldHelp: map[string]markers.DetailedHelp{ + "HeaderFile": { + Summary: "specifies the header text (e.g. license) to prepend to generated files.", + Details: "", + }, + "Year": { + Summary: "specifies the year to substitute for \" YEAR\" in the header file.", + Details: "", + }, + }, } } diff --git a/test.sh b/test.sh index f2b317187..df668fd5d 100755 --- a/test.sh +++ b/test.sh @@ -99,11 +99,6 @@ function setup_envs { header_text "using tools" -if ! which golangci-lint 2>&1 >/dev/null; then - curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin v1.49.0 - export PATH=$PATH:$(go env GOPATH)/bin -fi - # fetch the testing binaries - e.g. apiserver and etcd fetch_kb_tools @@ -116,24 +111,7 @@ pushd cmd/controller-gen > /dev/null popd > /dev/null header_text "running golangci-lint" - - -golangci-lint run --disable-all \ - --enable=misspell \ - --enable=revive \ - --enable=govet \ - --enable=unused \ - --enable=goimports \ - --enable=errcheck \ - --enable=unparam \ - --enable=ineffassign \ - --enable=nakedret \ - --enable=misspell \ - --enable=gocyclo \ - --enable=gosec \ - --enable=gofmt \ - --deadline=5m \ - ./pkg/... ./cmd/... +make lint # --enable=structcheck \ # doesn't understand embedded structs # --enable=goconst \ # complains about constants that shouldn't be constants