update dependencies (#6267)
Signed-off-by: hongming <coder.scala@gmail.com>
(cherry picked from commit cfebd96a1f)
This commit is contained in:
@@ -15,7 +15,7 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.27.1
|
||||
// protoc v3.12.4
|
||||
// protoc v3.21.12
|
||||
// source: konnectivity-client/proto/client/client.proto
|
||||
|
||||
package client
|
||||
|
||||
@@ -16,7 +16,7 @@ limitations under the License.
|
||||
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
|
||||
// versions:
|
||||
// - protoc-gen-go-grpc v1.2.0
|
||||
// - protoc v3.12.4
|
||||
// - protoc v3.21.12
|
||||
// source: konnectivity-client/proto/client/client.proto
|
||||
|
||||
package client
|
||||
|
||||
5
vendor/sigs.k8s.io/controller-runtime/.gitignore
generated
vendored
5
vendor/sigs.k8s.io/controller-runtime/.gitignore
generated
vendored
@@ -23,5 +23,8 @@
|
||||
# Tools binaries.
|
||||
hack/tools/bin
|
||||
|
||||
# Release artifacts
|
||||
tools/setup-envtest/out
|
||||
|
||||
junit-report.xml
|
||||
/artifacts
|
||||
/artifacts
|
||||
|
||||
16
vendor/sigs.k8s.io/controller-runtime/.golangci.yml
generated
vendored
16
vendor/sigs.k8s.io/controller-runtime/.golangci.yml
generated
vendored
@@ -41,6 +41,11 @@ linters:
|
||||
- whitespace
|
||||
|
||||
linters-settings:
|
||||
govet:
|
||||
enable-all: true
|
||||
disable:
|
||||
- fieldalignment
|
||||
- shadow
|
||||
importas:
|
||||
no-unaliased: true
|
||||
alias:
|
||||
@@ -58,10 +63,6 @@ linters-settings:
|
||||
# Controller Runtime
|
||||
- pkg: sigs.k8s.io/controller-runtime
|
||||
alias: ctrl
|
||||
staticcheck:
|
||||
go: "1.21"
|
||||
stylecheck:
|
||||
go: "1.21"
|
||||
revive:
|
||||
rules:
|
||||
# The following rules are recommended https://github.com/mgechev/revive#recommended-configuration
|
||||
@@ -105,6 +106,9 @@ issues:
|
||||
- Subprocess launch(ed with variable|ing should be audited)
|
||||
- (G204|G104|G307)
|
||||
- "ST1000: at least one file in a package should have a package comment"
|
||||
exclude-files:
|
||||
- "zz_generated.*\\.go$"
|
||||
- ".*conversion.*\\.go$"
|
||||
exclude-rules:
|
||||
- linters:
|
||||
- gosec
|
||||
@@ -163,8 +167,6 @@ issues:
|
||||
path: _test\.go
|
||||
|
||||
run:
|
||||
go: "1.22"
|
||||
timeout: 10m
|
||||
skip-files:
|
||||
- "zz_generated.*\\.go$"
|
||||
- ".*conversion.*\\.go$"
|
||||
allow-parallel-runners: true
|
||||
|
||||
14
vendor/sigs.k8s.io/controller-runtime/.gomodcheck.yaml
generated
vendored
Normal file
14
vendor/sigs.k8s.io/controller-runtime/.gomodcheck.yaml
generated
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
upstreamRefs:
|
||||
- k8s.io/api
|
||||
- k8s.io/apiextensions-apiserver
|
||||
- k8s.io/apimachinery
|
||||
- k8s.io/apiserver
|
||||
- k8s.io/client-go
|
||||
- k8s.io/component-base
|
||||
# k8s.io/klog/v2 -> conflicts with k/k deps
|
||||
# k8s.io/utils -> conflicts with k/k deps
|
||||
|
||||
excludedModules:
|
||||
# --- test dependencies:
|
||||
- github.com/onsi/ginkgo/v2
|
||||
- github.com/onsi/gomega
|
||||
4
vendor/sigs.k8s.io/controller-runtime/FAQ.md
generated
vendored
4
vendor/sigs.k8s.io/controller-runtime/FAQ.md
generated
vendored
@@ -4,13 +4,13 @@
|
||||
|
||||
**A**: Each controller should only reconcile one object type. Other
|
||||
affected objects should be mapped to a single type of root object, using
|
||||
the `EnqueueRequestForOwner` or `EnqueueRequestsFromMapFunc` event
|
||||
the `handler.EnqueueRequestForOwner` or `handler.EnqueueRequestsFromMapFunc` event
|
||||
handlers, and potentially indices. Then, your Reconcile method should
|
||||
attempt to reconcile *all* state for that given root objects.
|
||||
|
||||
### Q: How do I have different logic in my reconciler for different types of events (e.g. create, update, delete)?
|
||||
|
||||
**A**: You should not. Reconcile functions should be idempotent, and
|
||||
**A**: You should not. Reconcile functions should be idempotent, and
|
||||
should always reconcile state by reading all the state it needs, then
|
||||
writing updates. This allows your reconciler to correctly respond to
|
||||
generic events, adjust to skipped or coalesced events, and easily deal
|
||||
|
||||
122
vendor/sigs.k8s.io/controller-runtime/Makefile
generated
vendored
122
vendor/sigs.k8s.io/controller-runtime/Makefile
generated
vendored
@@ -24,6 +24,11 @@
|
||||
SHELL:=/usr/bin/env bash
|
||||
.DEFAULT_GOAL:=help
|
||||
|
||||
#
|
||||
# Go.
|
||||
#
|
||||
GO_VERSION ?= 1.22.5
|
||||
|
||||
# Use GOPROXY environment variable if set
|
||||
GOPROXY := $(shell go env GOPROXY)
|
||||
ifeq ($(GOPROXY),)
|
||||
@@ -34,14 +39,22 @@ export GOPROXY
|
||||
# Active module mode, as we use go modules to manage dependencies
|
||||
export GO111MODULE=on
|
||||
|
||||
# Hosts running SELinux need :z added to volume mounts
|
||||
SELINUX_ENABLED := $(shell cat /sys/fs/selinux/enforce 2> /dev/null || echo 0)
|
||||
|
||||
ifeq ($(SELINUX_ENABLED),1)
|
||||
DOCKER_VOL_OPTS?=:z
|
||||
endif
|
||||
|
||||
# Tools.
|
||||
TOOLS_DIR := hack/tools
|
||||
TOOLS_BIN_DIR := $(TOOLS_DIR)/bin
|
||||
TOOLS_BIN_DIR := $(abspath $(TOOLS_DIR)/bin)
|
||||
GOLANGCI_LINT := $(abspath $(TOOLS_BIN_DIR)/golangci-lint)
|
||||
GO_APIDIFF := $(TOOLS_BIN_DIR)/go-apidiff
|
||||
CONTROLLER_GEN := $(TOOLS_BIN_DIR)/controller-gen
|
||||
ENVTEST_DIR := $(abspath tools/setup-envtest)
|
||||
SCRATCH_ENV_DIR := $(abspath examples/scratch-env)
|
||||
GO_INSTALL := ./hack/go-install.sh
|
||||
|
||||
# The help will print out all targets with their descriptions organized bellow their categories. The categories are represented by `##@` and the target descriptions by `##`.
|
||||
# The awk commands is responsible to read the entire set of makefiles included in this invocation, looking for lines of the file as xyz: ## something, and then pretty-format the target and help. Then, if there's a line with ##@ something, that gets pretty-printed as a category.
|
||||
@@ -67,16 +80,36 @@ test-tools: ## tests the tools codebase (setup-envtest)
|
||||
## Binaries
|
||||
## --------------------------------------
|
||||
|
||||
$(GO_APIDIFF): $(TOOLS_DIR)/go.mod # Build go-apidiff from tools folder.
|
||||
cd $(TOOLS_DIR) && go build -tags=tools -o bin/go-apidiff github.com/joelanford/go-apidiff
|
||||
GO_APIDIFF_VER := v0.8.2
|
||||
GO_APIDIFF_BIN := go-apidiff
|
||||
GO_APIDIFF := $(abspath $(TOOLS_BIN_DIR)/$(GO_APIDIFF_BIN)-$(GO_APIDIFF_VER))
|
||||
GO_APIDIFF_PKG := github.com/joelanford/go-apidiff
|
||||
|
||||
$(CONTROLLER_GEN): $(TOOLS_DIR)/go.mod # Build controller-gen from tools folder.
|
||||
cd $(TOOLS_DIR) && go build -tags=tools -o bin/controller-gen sigs.k8s.io/controller-tools/cmd/controller-gen
|
||||
$(GO_APIDIFF): # Build go-apidiff from tools folder.
|
||||
GOBIN=$(TOOLS_BIN_DIR) $(GO_INSTALL) $(GO_APIDIFF_PKG) $(GO_APIDIFF_BIN) $(GO_APIDIFF_VER)
|
||||
|
||||
$(GOLANGCI_LINT): .github/workflows/golangci-lint.yml # Download golanci-lint using hack script into tools folder.
|
||||
hack/ensure-golangci-lint.sh \
|
||||
-b $(TOOLS_BIN_DIR) \
|
||||
$(shell cat .github/workflows/golangci-lint.yml | grep "version: v" | sed 's/.*version: //')
|
||||
CONTROLLER_GEN_VER := v0.14.0
|
||||
CONTROLLER_GEN_BIN := controller-gen
|
||||
CONTROLLER_GEN := $(abspath $(TOOLS_BIN_DIR)/$(CONTROLLER_GEN_BIN)-$(CONTROLLER_GEN_VER))
|
||||
CONTROLLER_GEN_PKG := sigs.k8s.io/controller-tools/cmd/controller-gen
|
||||
|
||||
$(CONTROLLER_GEN): # Build controller-gen from tools folder.
|
||||
GOBIN=$(TOOLS_BIN_DIR) $(GO_INSTALL) $(CONTROLLER_GEN_PKG) $(CONTROLLER_GEN_BIN) $(CONTROLLER_GEN_VER)
|
||||
|
||||
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)
|
||||
|
||||
GO_MOD_CHECK_DIR := $(abspath ./hack/tools/cmd/gomodcheck)
|
||||
GO_MOD_CHECK := $(abspath $(TOOLS_BIN_DIR)/gomodcheck)
|
||||
GO_MOD_CHECK_IGNORE := $(abspath .gomodcheck.yaml)
|
||||
.PHONY: $(GO_MOD_CHECK)
|
||||
$(GO_MOD_CHECK): # Build gomodcheck
|
||||
go build -C $(GO_MOD_CHECK_DIR) -o $(GO_MOD_CHECK)
|
||||
|
||||
## --------------------------------------
|
||||
## Linting
|
||||
@@ -102,9 +135,47 @@ modules: ## Runs go mod to ensure modules are up to date.
|
||||
cd $(ENVTEST_DIR); go mod tidy
|
||||
cd $(SCRATCH_ENV_DIR); go mod tidy
|
||||
|
||||
.PHONY: generate
|
||||
generate: $(CONTROLLER_GEN) ## Runs controller-gen for internal types for config file
|
||||
$(CONTROLLER_GEN) object paths="./pkg/config/v1alpha1/...;./examples/configfile/custom/v1alpha1/..."
|
||||
## --------------------------------------
|
||||
## Release
|
||||
## --------------------------------------
|
||||
|
||||
RELEASE_DIR := tools/setup-envtest/out
|
||||
|
||||
.PHONY: $(RELEASE_DIR)
|
||||
$(RELEASE_DIR):
|
||||
mkdir -p $(RELEASE_DIR)/
|
||||
|
||||
.PHONY: release
|
||||
release: clean-release $(RELEASE_DIR) ## Build release.
|
||||
@if ! [ -z "$$(git status --porcelain)" ]; then echo "Your local git repository contains uncommitted changes, use git clean before proceeding."; exit 1; fi
|
||||
|
||||
# Build binaries first.
|
||||
$(MAKE) release-binaries
|
||||
|
||||
.PHONY: release-binaries
|
||||
release-binaries: ## Build release binaries.
|
||||
RELEASE_BINARY=setup-envtest-linux-amd64 GOOS=linux GOARCH=amd64 $(MAKE) release-binary
|
||||
RELEASE_BINARY=setup-envtest-linux-arm64 GOOS=linux GOARCH=arm64 $(MAKE) release-binary
|
||||
RELEASE_BINARY=setup-envtest-linux-ppc64le GOOS=linux GOARCH=ppc64le $(MAKE) release-binary
|
||||
RELEASE_BINARY=setup-envtest-linux-s390x GOOS=linux GOARCH=s390x $(MAKE) release-binary
|
||||
RELEASE_BINARY=setup-envtest-darwin-amd64 GOOS=darwin GOARCH=amd64 $(MAKE) release-binary
|
||||
RELEASE_BINARY=setup-envtest-darwin-arm64 GOOS=darwin GOARCH=arm64 $(MAKE) release-binary
|
||||
RELEASE_BINARY=setup-envtest-windows-amd64.exe GOOS=windows GOARCH=amd64 $(MAKE) release-binary
|
||||
|
||||
.PHONY: release-binary
|
||||
release-binary: $(RELEASE_DIR)
|
||||
docker run \
|
||||
--rm \
|
||||
-e CGO_ENABLED=0 \
|
||||
-e GOOS=$(GOOS) \
|
||||
-e GOARCH=$(GOARCH) \
|
||||
-e GOCACHE=/tmp/ \
|
||||
--user $$(id -u):$$(id -g) \
|
||||
-v "$$(pwd):/workspace$(DOCKER_VOL_OPTS)" \
|
||||
-w /workspace/tools/setup-envtest \
|
||||
golang:$(GO_VERSION) \
|
||||
go build -a -trimpath -ldflags "-extldflags '-static'" \
|
||||
-o ./out/$(RELEASE_BINARY) ./
|
||||
|
||||
## --------------------------------------
|
||||
## Cleanup / Verification
|
||||
@@ -119,16 +190,29 @@ clean: ## Cleanup.
|
||||
clean-bin: ## Remove all generated binaries.
|
||||
rm -rf hack/tools/bin
|
||||
|
||||
.PHONY: clean-release
|
||||
clean-release: ## Remove the release folder
|
||||
rm -rf $(RELEASE_DIR)
|
||||
|
||||
.PHONY: verify-modules
|
||||
verify-modules: modules ## Verify go modules are up to date
|
||||
verify-modules: modules $(GO_MOD_CHECK) ## Verify go modules are up to date
|
||||
@if !(git diff --quiet HEAD -- go.sum go.mod $(TOOLS_DIR)/go.mod $(TOOLS_DIR)/go.sum $(ENVTEST_DIR)/go.mod $(ENVTEST_DIR)/go.sum $(SCRATCH_ENV_DIR)/go.sum); then \
|
||||
git diff; \
|
||||
echo "go module files are out of date, please run 'make modules'"; exit 1; \
|
||||
fi
|
||||
$(GO_MOD_CHECK) $(GO_MOD_CHECK_IGNORE)
|
||||
|
||||
.PHONY: verify-generate
|
||||
verify-generate: generate ## Verify generated files are up to date
|
||||
@if !(git diff --quiet HEAD); then \
|
||||
git diff; \
|
||||
echo "generated files are out of date, run make generate"; exit 1; \
|
||||
fi
|
||||
APIDIFF_OLD_COMMIT ?= $(shell git rev-parse origin/main)
|
||||
|
||||
.PHONY: apidiff
|
||||
verify-apidiff: $(GO_APIDIFF) ## Check for API differences
|
||||
$(GO_APIDIFF) $(APIDIFF_OLD_COMMIT) --print-compatible
|
||||
|
||||
## --------------------------------------
|
||||
## Helpers
|
||||
## --------------------------------------
|
||||
|
||||
##@ helpers:
|
||||
|
||||
go-version: ## Print the go version we use to compile our binaries and images
|
||||
@echo $(GO_VERSION)
|
||||
|
||||
3
vendor/sigs.k8s.io/controller-runtime/OWNERS
generated
vendored
3
vendor/sigs.k8s.io/controller-runtime/OWNERS
generated
vendored
@@ -6,5 +6,6 @@ approvers:
|
||||
- controller-runtime-approvers
|
||||
reviewers:
|
||||
- controller-runtime-admins
|
||||
- controller-runtime-reviewers
|
||||
- controller-runtime-maintainers
|
||||
- controller-runtime-approvers
|
||||
- controller-runtime-reviewers
|
||||
|
||||
6
vendor/sigs.k8s.io/controller-runtime/OWNERS_ALIASES
generated
vendored
6
vendor/sigs.k8s.io/controller-runtime/OWNERS_ALIASES
generated
vendored
@@ -25,12 +25,6 @@ aliases:
|
||||
- varshaprasad96
|
||||
- inteon
|
||||
|
||||
# folks to can approve things in the directly-ported
|
||||
# testing_frameworks portions of the codebase
|
||||
testing-integration-approvers:
|
||||
- apelisse
|
||||
- hoegaarden
|
||||
|
||||
# folks who may have context on ancient history,
|
||||
# but are no longer directly involved
|
||||
controller-runtime-emeritus-maintainers:
|
||||
|
||||
20
vendor/sigs.k8s.io/controller-runtime/README.md
generated
vendored
20
vendor/sigs.k8s.io/controller-runtime/README.md
generated
vendored
@@ -40,6 +40,25 @@ Contributors:
|
||||
* [Documentation Changes](/.github/PULL_REQUEST_TEMPLATE/docs.md)
|
||||
* [Test/Build/Other Changes](/.github/PULL_REQUEST_TEMPLATE/other.md)
|
||||
|
||||
## Compatibility
|
||||
|
||||
Every minor version of controller-runtime has been tested with a specific minor version of client-go. A controller-runtime minor version *may* be compatible with
|
||||
other client-go minor versions, but this is by chance and neither supported nor tested. In general, we create one minor version of controller-runtime
|
||||
for each minor version of client-go and other k8s.io/* dependencies.
|
||||
|
||||
The minimum Go version of controller-runtime is the highest minimum Go version of our Go dependencies. Usually, this will
|
||||
be identical to the minimum Go version of the corresponding k8s.io/* dependencies.
|
||||
|
||||
Compatible k8s.io/*, client-go and minimum Go versions can be looked up in our [go.mod](go.mod) file.
|
||||
|
||||
| | k8s.io/*, client-go | minimum Go version |
|
||||
|----------|:-------------------:|:------------------:|
|
||||
| CR v0.19 | v0.31 | 1.22 |
|
||||
| CR v0.18 | v0.30 | 1.22 |
|
||||
| CR v0.17 | v0.29 | 1.21 |
|
||||
| CR v0.16 | v0.28 | 1.20 |
|
||||
| CR v0.15 | v0.27 | 1.20 |
|
||||
|
||||
## FAQ
|
||||
|
||||
See [FAQ.md](FAQ.md)
|
||||
@@ -57,6 +76,7 @@ You can reach the maintainers of this project at:
|
||||
- Google Group: [kubebuilder@googlegroups.com](https://groups.google.com/forum/#!forum/kubebuilder)
|
||||
|
||||
## Contributing
|
||||
|
||||
Contributions are greatly appreciated. The maintainers actively manage the issues list, and try to highlight issues suitable for newcomers.
|
||||
The project follows the typical GitHub pull request model. See [CONTRIBUTING.md](CONTRIBUTING.md) for more details.
|
||||
Before starting any work, please either comment on an existing issue, or file a new one.
|
||||
|
||||
12
vendor/sigs.k8s.io/controller-runtime/alias.go
generated
vendored
12
vendor/sigs.k8s.io/controller-runtime/alias.go
generated
vendored
@@ -21,7 +21,6 @@ import (
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"sigs.k8s.io/controller-runtime/pkg/builder"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client/config"
|
||||
cfg "sigs.k8s.io/controller-runtime/pkg/config"
|
||||
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
|
||||
"sigs.k8s.io/controller-runtime/pkg/log"
|
||||
"sigs.k8s.io/controller-runtime/pkg/manager"
|
||||
@@ -96,13 +95,6 @@ var (
|
||||
// * $HOME/.kube/config if exists.
|
||||
GetConfig = config.GetConfig
|
||||
|
||||
// ConfigFile returns the cfg.File function for deferred config file loading,
|
||||
// this is passed into Options{}.From() to populate the Options fields for
|
||||
// the manager.
|
||||
//
|
||||
// Deprecated: This is deprecated in favor of using Options directly.
|
||||
ConfigFile = cfg.File
|
||||
|
||||
// NewControllerManagedBy returns a new controller builder that will be started by the provided Manager.
|
||||
NewControllerManagedBy = builder.ControllerManagedBy
|
||||
|
||||
@@ -130,8 +122,8 @@ var (
|
||||
// there is another OwnerReference with Controller flag set.
|
||||
SetControllerReference = controllerutil.SetControllerReference
|
||||
|
||||
// SetupSignalHandler registered for SIGTERM and SIGINT. A stop channel is returned
|
||||
// which is closed on one of these signals. If a second signal is caught, the program
|
||||
// SetupSignalHandler registers for SIGTERM and SIGINT. A context is returned
|
||||
// which is canceled on one of these signals. If a second signal is caught, the program
|
||||
// is terminated with exit code 1.
|
||||
SetupSignalHandler = signals.SetupSignalHandler
|
||||
|
||||
|
||||
181
vendor/sigs.k8s.io/controller-runtime/pkg/builder/controller.go
generated
vendored
181
vendor/sigs.k8s.io/controller-runtime/pkg/builder/controller.go
generated
vendored
@@ -19,6 +19,7 @@ package builder
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
"github.com/go-logr/logr"
|
||||
@@ -30,17 +31,12 @@ import (
|
||||
"sigs.k8s.io/controller-runtime/pkg/client/apiutil"
|
||||
"sigs.k8s.io/controller-runtime/pkg/controller"
|
||||
"sigs.k8s.io/controller-runtime/pkg/handler"
|
||||
internalsource "sigs.k8s.io/controller-runtime/pkg/internal/source"
|
||||
"sigs.k8s.io/controller-runtime/pkg/manager"
|
||||
"sigs.k8s.io/controller-runtime/pkg/predicate"
|
||||
"sigs.k8s.io/controller-runtime/pkg/reconcile"
|
||||
"sigs.k8s.io/controller-runtime/pkg/source"
|
||||
)
|
||||
|
||||
// Supporting mocking out functions for testing.
|
||||
var newController = controller.New
|
||||
var getGvk = apiutil.GVKForObject
|
||||
|
||||
// project represents other forms that we can use to
|
||||
// send/receive a given resource (metadata-only, unstructured, etc).
|
||||
type objectProjection int
|
||||
@@ -53,20 +49,32 @@ const (
|
||||
)
|
||||
|
||||
// Builder builds a Controller.
|
||||
type Builder struct {
|
||||
type Builder = TypedBuilder[reconcile.Request]
|
||||
|
||||
// TypedBuilder builds a Controller. The request is the request type
|
||||
// that is passed to the workqueue and then to the Reconciler.
|
||||
// The workqueue de-duplicates identical requests.
|
||||
type TypedBuilder[request comparable] struct {
|
||||
forInput ForInput
|
||||
ownsInput []OwnsInput
|
||||
watchesInput []WatchesInput
|
||||
rawSources []source.TypedSource[request]
|
||||
watchesInput []WatchesInput[request]
|
||||
mgr manager.Manager
|
||||
globalPredicates []predicate.Predicate
|
||||
ctrl controller.Controller
|
||||
ctrlOptions controller.Options
|
||||
ctrl controller.TypedController[request]
|
||||
ctrlOptions controller.TypedOptions[request]
|
||||
name string
|
||||
newController func(name string, mgr manager.Manager, options controller.TypedOptions[request]) (controller.TypedController[request], error)
|
||||
}
|
||||
|
||||
// ControllerManagedBy returns a new controller builder that will be started by the provided Manager.
|
||||
func ControllerManagedBy(m manager.Manager) *Builder {
|
||||
return &Builder{mgr: m}
|
||||
return TypedControllerManagedBy[reconcile.Request](m)
|
||||
}
|
||||
|
||||
// TypedControllerManagedBy returns a new typed controller builder that will be started by the provided Manager.
|
||||
func TypedControllerManagedBy[request comparable](m manager.Manager) *TypedBuilder[request] {
|
||||
return &TypedBuilder[request]{mgr: m}
|
||||
}
|
||||
|
||||
// ForInput represents the information set by the For method.
|
||||
@@ -79,9 +87,10 @@ type ForInput struct {
|
||||
|
||||
// For defines the type of Object being *reconciled*, and configures the ControllerManagedBy to respond to create / delete /
|
||||
// update events by *reconciling the object*.
|
||||
//
|
||||
// This is the equivalent of calling
|
||||
// Watches(&source.Kind{Type: apiType}, &handler.EnqueueRequestForObject{}).
|
||||
func (blder *Builder) For(object client.Object, opts ...ForOption) *Builder {
|
||||
// Watches(source.Kind(cache, &Type{}, &handler.EnqueueRequestForObject{})).
|
||||
func (blder *TypedBuilder[request]) For(object client.Object, opts ...ForOption) *TypedBuilder[request] {
|
||||
if blder.forInput.object != nil {
|
||||
blder.forInput.err = fmt.Errorf("For(...) should only be called once, could not assign multiple objects for reconciliation")
|
||||
return blder
|
||||
@@ -110,8 +119,8 @@ type OwnsInput struct {
|
||||
// Use Owns(object, builder.MatchEveryOwner) to reconcile all owners.
|
||||
//
|
||||
// By default, this is the equivalent of calling
|
||||
// Watches(object, handler.EnqueueRequestForOwner([...], ownerType, OnlyControllerOwner())).
|
||||
func (blder *Builder) Owns(object client.Object, opts ...OwnsOption) *Builder {
|
||||
// Watches(source.Kind(cache, &Type{}, handler.EnqueueRequestForOwner([...], &OwnerType{}, OnlyControllerOwner()))).
|
||||
func (blder *TypedBuilder[request]) Owns(object client.Object, opts ...OwnsOption) *TypedBuilder[request] {
|
||||
input := OwnsInput{object: object}
|
||||
for _, opt := range opts {
|
||||
opt.ApplyToOwns(&input)
|
||||
@@ -121,22 +130,48 @@ func (blder *Builder) Owns(object client.Object, opts ...OwnsOption) *Builder {
|
||||
return blder
|
||||
}
|
||||
|
||||
type untypedWatchesInput interface {
|
||||
setPredicates([]predicate.Predicate)
|
||||
setObjectProjection(objectProjection)
|
||||
}
|
||||
|
||||
// WatchesInput represents the information set by Watches method.
|
||||
type WatchesInput struct {
|
||||
src source.Source
|
||||
eventHandler handler.EventHandler
|
||||
type WatchesInput[request comparable] struct {
|
||||
obj client.Object
|
||||
handler handler.TypedEventHandler[client.Object, request]
|
||||
predicates []predicate.Predicate
|
||||
objectProjection objectProjection
|
||||
}
|
||||
|
||||
func (w *WatchesInput[request]) setPredicates(predicates []predicate.Predicate) {
|
||||
w.predicates = predicates
|
||||
}
|
||||
|
||||
func (w *WatchesInput[request]) setObjectProjection(objectProjection objectProjection) {
|
||||
w.objectProjection = objectProjection
|
||||
}
|
||||
|
||||
// Watches defines the type of Object to watch, and configures the ControllerManagedBy to respond to create / delete /
|
||||
// update events by *reconciling the object* with the given EventHandler.
|
||||
//
|
||||
// This is the equivalent of calling
|
||||
// WatchesRawSource(source.Kind(cache, object), eventHandler, opts...).
|
||||
func (blder *Builder) Watches(object client.Object, eventHandler handler.EventHandler, opts ...WatchesOption) *Builder {
|
||||
src := source.Kind(blder.mgr.GetCache(), object)
|
||||
return blder.WatchesRawSource(src, eventHandler, opts...)
|
||||
// WatchesRawSource(source.Kind(cache, object, eventHandler, predicates...)).
|
||||
func (blder *TypedBuilder[request]) Watches(
|
||||
object client.Object,
|
||||
eventHandler handler.TypedEventHandler[client.Object, request],
|
||||
opts ...WatchesOption,
|
||||
) *TypedBuilder[request] {
|
||||
input := WatchesInput[request]{
|
||||
obj: object,
|
||||
handler: eventHandler,
|
||||
}
|
||||
for _, opt := range opts {
|
||||
opt.ApplyToWatches(&input)
|
||||
}
|
||||
|
||||
blder.watchesInput = append(blder.watchesInput, input)
|
||||
|
||||
return blder
|
||||
}
|
||||
|
||||
// WatchesMetadata is the same as Watches, but forces the internal cache to only watch PartialObjectMetadata.
|
||||
@@ -166,43 +201,45 @@ func (blder *Builder) Watches(object client.Object, eventHandler handler.EventHa
|
||||
// In the first case, controller-runtime will create another cache for the
|
||||
// concrete type on top of the metadata cache; this increases memory
|
||||
// consumption and leads to race conditions as caches are not in sync.
|
||||
func (blder *Builder) WatchesMetadata(object client.Object, eventHandler handler.EventHandler, opts ...WatchesOption) *Builder {
|
||||
func (blder *TypedBuilder[request]) WatchesMetadata(
|
||||
object client.Object,
|
||||
eventHandler handler.TypedEventHandler[client.Object, request],
|
||||
opts ...WatchesOption,
|
||||
) *TypedBuilder[request] {
|
||||
opts = append(opts, OnlyMetadata)
|
||||
return blder.Watches(object, eventHandler, opts...)
|
||||
}
|
||||
|
||||
// WatchesRawSource exposes the lower-level ControllerManagedBy Watches functions through the builder.
|
||||
// Specified predicates are registered only for given source.
|
||||
//
|
||||
// STOP! Consider using For(...), Owns(...), Watches(...), WatchesMetadata(...) instead.
|
||||
// This method is only exposed for more advanced use cases, most users should use one of the higher level functions.
|
||||
func (blder *Builder) WatchesRawSource(src source.Source, eventHandler handler.EventHandler, opts ...WatchesOption) *Builder {
|
||||
input := WatchesInput{src: src, eventHandler: eventHandler}
|
||||
for _, opt := range opts {
|
||||
opt.ApplyToWatches(&input)
|
||||
}
|
||||
// WatchesRawSource does not respect predicates configured through WithEventFilter.
|
||||
//
|
||||
// WatchesRawSource makes it possible to use typed handlers and predicates with `source.Kind` as well as custom source implementations.
|
||||
func (blder *TypedBuilder[request]) WatchesRawSource(src source.TypedSource[request]) *TypedBuilder[request] {
|
||||
blder.rawSources = append(blder.rawSources, src)
|
||||
|
||||
blder.watchesInput = append(blder.watchesInput, input)
|
||||
return blder
|
||||
}
|
||||
|
||||
// WithEventFilter sets the event filters, to filter which create/update/delete/generic events eventually
|
||||
// trigger reconciliations. For example, filtering on whether the resource version has changed.
|
||||
// Given predicate is added for all watched objects.
|
||||
// Given predicate is added for all watched objects and thus must be able to deal with the type
|
||||
// of all watched objects.
|
||||
//
|
||||
// Defaults to the empty list.
|
||||
func (blder *Builder) WithEventFilter(p predicate.Predicate) *Builder {
|
||||
func (blder *TypedBuilder[request]) WithEventFilter(p predicate.Predicate) *TypedBuilder[request] {
|
||||
blder.globalPredicates = append(blder.globalPredicates, p)
|
||||
return blder
|
||||
}
|
||||
|
||||
// WithOptions overrides the controller options used in doController. Defaults to empty.
|
||||
func (blder *Builder) WithOptions(options controller.Options) *Builder {
|
||||
func (blder *TypedBuilder[request]) WithOptions(options controller.TypedOptions[request]) *TypedBuilder[request] {
|
||||
blder.ctrlOptions = options
|
||||
return blder
|
||||
}
|
||||
|
||||
// WithLogConstructor overrides the controller options's LogConstructor.
|
||||
func (blder *Builder) WithLogConstructor(logConstructor func(*reconcile.Request) logr.Logger) *Builder {
|
||||
func (blder *TypedBuilder[request]) WithLogConstructor(logConstructor func(*request) logr.Logger) *TypedBuilder[request] {
|
||||
blder.ctrlOptions.LogConstructor = logConstructor
|
||||
return blder
|
||||
}
|
||||
@@ -212,19 +249,21 @@ func (blder *Builder) WithLogConstructor(logConstructor func(*reconcile.Request)
|
||||
// (underscores and alphanumeric characters only).
|
||||
//
|
||||
// By default, controllers are named using the lowercase version of their kind.
|
||||
func (blder *Builder) Named(name string) *Builder {
|
||||
//
|
||||
// The name must be unique as it is used to identify the controller in metrics and logs.
|
||||
func (blder *TypedBuilder[request]) Named(name string) *TypedBuilder[request] {
|
||||
blder.name = name
|
||||
return blder
|
||||
}
|
||||
|
||||
// Complete builds the Application Controller.
|
||||
func (blder *Builder) Complete(r reconcile.Reconciler) error {
|
||||
func (blder *TypedBuilder[request]) Complete(r reconcile.TypedReconciler[request]) error {
|
||||
_, err := blder.Build(r)
|
||||
return err
|
||||
}
|
||||
|
||||
// Build builds the Application Controller and returns the Controller it created.
|
||||
func (blder *Builder) Build(r reconcile.Reconciler) (controller.Controller, error) {
|
||||
func (blder *TypedBuilder[request]) Build(r reconcile.TypedReconciler[request]) (controller.TypedController[request], error) {
|
||||
if r == nil {
|
||||
return nil, fmt.Errorf("must provide a non-nil Reconciler")
|
||||
}
|
||||
@@ -248,13 +287,13 @@ func (blder *Builder) Build(r reconcile.Reconciler) (controller.Controller, erro
|
||||
return blder.ctrl, nil
|
||||
}
|
||||
|
||||
func (blder *Builder) project(obj client.Object, proj objectProjection) (client.Object, error) {
|
||||
func (blder *TypedBuilder[request]) project(obj client.Object, proj objectProjection) (client.Object, error) {
|
||||
switch proj {
|
||||
case projectAsNormal:
|
||||
return obj, nil
|
||||
case projectAsMetadata:
|
||||
metaObj := &metav1.PartialObjectMetadata{}
|
||||
gvk, err := getGvk(obj, blder.mgr.GetScheme())
|
||||
gvk, err := apiutil.GVKForObject(obj, blder.mgr.GetScheme())
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to determine GVK of %T for a metadata-only watch: %w", obj, err)
|
||||
}
|
||||
@@ -265,18 +304,24 @@ func (blder *Builder) project(obj client.Object, proj objectProjection) (client.
|
||||
}
|
||||
}
|
||||
|
||||
func (blder *Builder) doWatch() error {
|
||||
func (blder *TypedBuilder[request]) doWatch() error {
|
||||
// Reconcile type
|
||||
if blder.forInput.object != nil {
|
||||
obj, err := blder.project(blder.forInput.object, blder.forInput.objectProjection)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
src := source.Kind(blder.mgr.GetCache(), obj)
|
||||
hdler := &handler.EnqueueRequestForObject{}
|
||||
|
||||
if reflect.TypeFor[request]() != reflect.TypeOf(reconcile.Request{}) {
|
||||
return fmt.Errorf("For() can only be used with reconcile.Request, got %T", *new(request))
|
||||
}
|
||||
|
||||
var hdler handler.TypedEventHandler[client.Object, request]
|
||||
reflect.ValueOf(&hdler).Elem().Set(reflect.ValueOf(&handler.EnqueueRequestForObject{}))
|
||||
allPredicates := append([]predicate.Predicate(nil), blder.globalPredicates...)
|
||||
allPredicates = append(allPredicates, blder.forInput.predicates...)
|
||||
if err := blder.ctrl.Watch(src, hdler, allPredicates...); err != nil {
|
||||
src := source.TypedKind(blder.mgr.GetCache(), obj, hdler, allPredicates...)
|
||||
if err := blder.ctrl.Watch(src); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@@ -290,46 +335,49 @@ func (blder *Builder) doWatch() error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
src := source.Kind(blder.mgr.GetCache(), obj)
|
||||
opts := []handler.OwnerOption{}
|
||||
if !own.matchEveryOwner {
|
||||
opts = append(opts, handler.OnlyControllerOwner())
|
||||
}
|
||||
hdler := handler.EnqueueRequestForOwner(
|
||||
|
||||
var hdler handler.TypedEventHandler[client.Object, request]
|
||||
reflect.ValueOf(&hdler).Elem().Set(reflect.ValueOf(handler.EnqueueRequestForOwner(
|
||||
blder.mgr.GetScheme(), blder.mgr.GetRESTMapper(),
|
||||
blder.forInput.object,
|
||||
opts...,
|
||||
)
|
||||
)))
|
||||
allPredicates := append([]predicate.Predicate(nil), blder.globalPredicates...)
|
||||
allPredicates = append(allPredicates, own.predicates...)
|
||||
if err := blder.ctrl.Watch(src, hdler, allPredicates...); err != nil {
|
||||
src := source.TypedKind(blder.mgr.GetCache(), obj, hdler, allPredicates...)
|
||||
if err := blder.ctrl.Watch(src); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Do the watch requests
|
||||
if len(blder.watchesInput) == 0 && blder.forInput.object == nil {
|
||||
return errors.New("there are no watches configured, controller will never get triggered. Use For(), Owns() or Watches() to set them up")
|
||||
if len(blder.watchesInput) == 0 && blder.forInput.object == nil && len(blder.rawSources) == 0 {
|
||||
return errors.New("there are no watches configured, controller will never get triggered. Use For(), Owns(), Watches() or WatchesRawSource() to set them up")
|
||||
}
|
||||
for _, w := range blder.watchesInput {
|
||||
// If the source of this watch is of type Kind, project it.
|
||||
if srcKind, ok := w.src.(*internalsource.Kind); ok {
|
||||
typeForSrc, err := blder.project(srcKind.Type, w.objectProjection)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
srcKind.Type = typeForSrc
|
||||
projected, err := blder.project(w.obj, w.objectProjection)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to project for %T: %w", w.obj, err)
|
||||
}
|
||||
allPredicates := append([]predicate.Predicate(nil), blder.globalPredicates...)
|
||||
allPredicates = append(allPredicates, w.predicates...)
|
||||
if err := blder.ctrl.Watch(w.src, w.eventHandler, allPredicates...); err != nil {
|
||||
if err := blder.ctrl.Watch(source.TypedKind(blder.mgr.GetCache(), projected, w.handler, allPredicates...)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
for _, src := range blder.rawSources {
|
||||
if err := blder.ctrl.Watch(src); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (blder *Builder) getControllerName(gvk schema.GroupVersionKind, hasGVK bool) (string, error) {
|
||||
func (blder *TypedBuilder[request]) getControllerName(gvk schema.GroupVersionKind, hasGVK bool) (string, error) {
|
||||
if blder.name != "" {
|
||||
return blder.name, nil
|
||||
}
|
||||
@@ -339,7 +387,7 @@ func (blder *Builder) getControllerName(gvk schema.GroupVersionKind, hasGVK bool
|
||||
return strings.ToLower(gvk.Kind), nil
|
||||
}
|
||||
|
||||
func (blder *Builder) doController(r reconcile.Reconciler) error {
|
||||
func (blder *TypedBuilder[request]) doController(r reconcile.TypedReconciler[request]) error {
|
||||
globalOpts := blder.mgr.GetControllerOptions()
|
||||
|
||||
ctrlOptions := blder.ctrlOptions
|
||||
@@ -356,7 +404,7 @@ func (blder *Builder) doController(r reconcile.Reconciler) error {
|
||||
hasGVK := blder.forInput.object != nil
|
||||
if hasGVK {
|
||||
var err error
|
||||
gvk, err = getGvk(blder.forInput.object, blder.mgr.GetScheme())
|
||||
gvk, err = apiutil.GVKForObject(blder.forInput.object, blder.mgr.GetScheme())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -393,9 +441,10 @@ func (blder *Builder) doController(r reconcile.Reconciler) error {
|
||||
)
|
||||
}
|
||||
|
||||
ctrlOptions.LogConstructor = func(req *reconcile.Request) logr.Logger {
|
||||
ctrlOptions.LogConstructor = func(in *request) logr.Logger {
|
||||
log := log
|
||||
if req != nil {
|
||||
|
||||
if req, ok := any(in).(*reconcile.Request); ok && req != nil {
|
||||
if hasGVK {
|
||||
log = log.WithValues(gvk.Kind, klog.KRef(req.Namespace, req.Name))
|
||||
}
|
||||
@@ -407,7 +456,11 @@ func (blder *Builder) doController(r reconcile.Reconciler) error {
|
||||
}
|
||||
}
|
||||
|
||||
if blder.newController == nil {
|
||||
blder.newController = controller.NewTyped[request]
|
||||
}
|
||||
|
||||
// Build the controller and return.
|
||||
blder.ctrl, err = newController(controllerName, blder.mgr, ctrlOptions)
|
||||
blder.ctrl, err = blder.newController(controllerName, blder.mgr, ctrlOptions)
|
||||
return err
|
||||
}
|
||||
|
||||
10
vendor/sigs.k8s.io/controller-runtime/pkg/builder/options.go
generated
vendored
10
vendor/sigs.k8s.io/controller-runtime/pkg/builder/options.go
generated
vendored
@@ -37,7 +37,7 @@ type OwnsOption interface {
|
||||
// WatchesOption is some configuration that modifies options for a watches request.
|
||||
type WatchesOption interface {
|
||||
// ApplyToWatches applies this configuration to the given watches options.
|
||||
ApplyToWatches(*WatchesInput)
|
||||
ApplyToWatches(untypedWatchesInput)
|
||||
}
|
||||
|
||||
// }}}
|
||||
@@ -67,8 +67,8 @@ func (w Predicates) ApplyToOwns(opts *OwnsInput) {
|
||||
}
|
||||
|
||||
// ApplyToWatches applies this configuration to the given WatchesInput options.
|
||||
func (w Predicates) ApplyToWatches(opts *WatchesInput) {
|
||||
opts.predicates = w.predicates
|
||||
func (w Predicates) ApplyToWatches(opts untypedWatchesInput) {
|
||||
opts.setPredicates(w.predicates)
|
||||
}
|
||||
|
||||
var _ ForOption = &Predicates{}
|
||||
@@ -95,8 +95,8 @@ func (p projectAs) ApplyToOwns(opts *OwnsInput) {
|
||||
}
|
||||
|
||||
// ApplyToWatches applies this configuration to the given WatchesInput options.
|
||||
func (p projectAs) ApplyToWatches(opts *WatchesInput) {
|
||||
opts.objectProjection = objectProjection(p)
|
||||
func (p projectAs) ApplyToWatches(opts untypedWatchesInput) {
|
||||
opts.setObjectProjection(objectProjection(p))
|
||||
}
|
||||
|
||||
var (
|
||||
|
||||
37
vendor/sigs.k8s.io/controller-runtime/pkg/builder/webhook.go
generated
vendored
37
vendor/sigs.k8s.io/controller-runtime/pkg/builder/webhook.go
generated
vendored
@@ -42,8 +42,9 @@ type WebhookBuilder struct {
|
||||
gvk schema.GroupVersionKind
|
||||
mgr manager.Manager
|
||||
config *rest.Config
|
||||
recoverPanic bool
|
||||
recoverPanic *bool
|
||||
logConstructor func(base logr.Logger, req *admission.Request) logr.Logger
|
||||
err error
|
||||
}
|
||||
|
||||
// WebhookManagedBy returns a new webhook builder.
|
||||
@@ -57,6 +58,9 @@ func WebhookManagedBy(m manager.Manager) *WebhookBuilder {
|
||||
// If the given object implements the admission.Defaulter interface, a MutatingWebhook will be wired for this type.
|
||||
// If the given object implements the admission.Validator interface, a ValidatingWebhook will be wired for this type.
|
||||
func (blder *WebhookBuilder) For(apiType runtime.Object) *WebhookBuilder {
|
||||
if blder.apiType != nil {
|
||||
blder.err = errors.New("For(...) should only be called once, could not assign multiple objects for webhook registration")
|
||||
}
|
||||
blder.apiType = apiType
|
||||
return blder
|
||||
}
|
||||
@@ -80,8 +84,9 @@ func (blder *WebhookBuilder) WithLogConstructor(logConstructor func(base logr.Lo
|
||||
}
|
||||
|
||||
// RecoverPanic indicates whether panics caused by the webhook should be recovered.
|
||||
func (blder *WebhookBuilder) RecoverPanic() *WebhookBuilder {
|
||||
blder.recoverPanic = true
|
||||
// Defaults to true.
|
||||
func (blder *WebhookBuilder) RecoverPanic(recoverPanic bool) *WebhookBuilder {
|
||||
blder.recoverPanic = &recoverPanic
|
||||
return blder
|
||||
}
|
||||
|
||||
@@ -142,7 +147,7 @@ func (blder *WebhookBuilder) registerWebhooks() error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
return blder.err
|
||||
}
|
||||
|
||||
// registerDefaultingWebhook registers a defaulting webhook if necessary.
|
||||
@@ -165,10 +170,18 @@ func (blder *WebhookBuilder) registerDefaultingWebhook() {
|
||||
|
||||
func (blder *WebhookBuilder) getDefaultingWebhook() *admission.Webhook {
|
||||
if defaulter := blder.customDefaulter; defaulter != nil {
|
||||
return admission.WithCustomDefaulter(blder.mgr.GetScheme(), blder.apiType, defaulter).WithRecoverPanic(blder.recoverPanic)
|
||||
w := admission.WithCustomDefaulter(blder.mgr.GetScheme(), blder.apiType, defaulter)
|
||||
if blder.recoverPanic != nil {
|
||||
w = w.WithRecoverPanic(*blder.recoverPanic)
|
||||
}
|
||||
return w
|
||||
}
|
||||
if defaulter, ok := blder.apiType.(admission.Defaulter); ok {
|
||||
return admission.DefaultingWebhookFor(blder.mgr.GetScheme(), defaulter).WithRecoverPanic(blder.recoverPanic)
|
||||
w := admission.DefaultingWebhookFor(blder.mgr.GetScheme(), defaulter)
|
||||
if blder.recoverPanic != nil {
|
||||
w = w.WithRecoverPanic(*blder.recoverPanic)
|
||||
}
|
||||
return w
|
||||
}
|
||||
log.Info(
|
||||
"skip registering a mutating webhook, object does not implement admission.Defaulter or WithDefaulter wasn't called",
|
||||
@@ -196,10 +209,18 @@ func (blder *WebhookBuilder) registerValidatingWebhook() {
|
||||
|
||||
func (blder *WebhookBuilder) getValidatingWebhook() *admission.Webhook {
|
||||
if validator := blder.customValidator; validator != nil {
|
||||
return admission.WithCustomValidator(blder.mgr.GetScheme(), blder.apiType, validator).WithRecoverPanic(blder.recoverPanic)
|
||||
w := admission.WithCustomValidator(blder.mgr.GetScheme(), blder.apiType, validator)
|
||||
if blder.recoverPanic != nil {
|
||||
w = w.WithRecoverPanic(*blder.recoverPanic)
|
||||
}
|
||||
return w
|
||||
}
|
||||
if validator, ok := blder.apiType.(admission.Validator); ok {
|
||||
return admission.ValidatingWebhookFor(blder.mgr.GetScheme(), validator).WithRecoverPanic(blder.recoverPanic)
|
||||
w := admission.ValidatingWebhookFor(blder.mgr.GetScheme(), validator)
|
||||
if blder.recoverPanic != nil {
|
||||
w = w.WithRecoverPanic(*blder.recoverPanic)
|
||||
}
|
||||
return w
|
||||
}
|
||||
log.Info(
|
||||
"skip registering a validating webhook, object does not implement admission.Validator or WithValidator wasn't called",
|
||||
|
||||
84
vendor/sigs.k8s.io/controller-runtime/pkg/cache/cache.go
generated
vendored
84
vendor/sigs.k8s.io/controller-runtime/pkg/cache/cache.go
generated
vendored
@@ -20,6 +20,7 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"sort"
|
||||
"time"
|
||||
|
||||
"golang.org/x/exp/maps"
|
||||
@@ -38,11 +39,9 @@ import (
|
||||
"sigs.k8s.io/controller-runtime/pkg/cache/internal"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client/apiutil"
|
||||
logf "sigs.k8s.io/controller-runtime/pkg/internal/log"
|
||||
)
|
||||
|
||||
var (
|
||||
log = logf.RuntimeLog.WithName("object-cache")
|
||||
defaultSyncPeriod = 10 * time.Hour
|
||||
)
|
||||
|
||||
@@ -118,8 +117,8 @@ type Informer interface {
|
||||
// This function is guaranteed to be idempotent and thread-safe.
|
||||
RemoveEventHandler(handle toolscache.ResourceEventHandlerRegistration) error
|
||||
|
||||
// AddIndexers adds indexers to this store. If this is called after there is already data
|
||||
// in the store, the results are undefined.
|
||||
// AddIndexers adds indexers to this store. It is valid to add indexers
|
||||
// after an informer was started.
|
||||
AddIndexers(indexers toolscache.Indexers) error
|
||||
|
||||
// HasSynced return true if the informers underlying store has synced.
|
||||
@@ -202,6 +201,9 @@ type Options struct {
|
||||
|
||||
// DefaultTransform will be used as transform for all object types
|
||||
// unless there is already one set in ByObject or DefaultNamespaces.
|
||||
//
|
||||
// A typical usecase for this is to use TransformStripManagedFields
|
||||
// to reduce the caches memory usage.
|
||||
DefaultTransform toolscache.TransformFunc
|
||||
|
||||
// DefaultWatchErrorHandler will be used to the WatchErrorHandler which is called
|
||||
@@ -221,7 +223,7 @@ type Options struct {
|
||||
DefaultUnsafeDisableDeepCopy *bool
|
||||
|
||||
// ByObject restricts the cache's ListWatch to the desired fields per GVK at the specified object.
|
||||
// object, this will fall through to Default* settings.
|
||||
// If unset, this will fall through to the Default* settings.
|
||||
ByObject map[client.Object]ByObject
|
||||
|
||||
// newInformer allows overriding of NewSharedIndexInformer for testing.
|
||||
@@ -345,6 +347,20 @@ func New(cfg *rest.Config, opts Options) (Cache, error) {
|
||||
return delegating, nil
|
||||
}
|
||||
|
||||
// TransformStripManagedFields strips the managed fields of an object before it is committed to the cache.
|
||||
// If you are not explicitly accessing managedFields from your code, setting this as `DefaultTransform`
|
||||
// on the cache can lead to a significant reduction in memory usage.
|
||||
func TransformStripManagedFields() toolscache.TransformFunc {
|
||||
return func(in any) (any, error) {
|
||||
// Nilcheck managed fields to avoid hitting https://github.com/kubernetes/kubernetes/issues/124337
|
||||
if obj, err := meta.Accessor(in); err == nil && obj.GetManagedFields() != nil {
|
||||
obj.SetManagedFields(nil)
|
||||
}
|
||||
|
||||
return in, nil
|
||||
}
|
||||
}
|
||||
|
||||
func optionDefaultsToConfig(opts *Options) Config {
|
||||
return Config{
|
||||
LabelSelector: opts.DefaultLabelSelector,
|
||||
@@ -418,14 +434,6 @@ func defaultOpts(config *rest.Config, opts Options) (Options, error) {
|
||||
}
|
||||
}
|
||||
|
||||
for namespace, cfg := range opts.DefaultNamespaces {
|
||||
cfg = defaultConfig(cfg, optionDefaultsToConfig(&opts))
|
||||
if namespace == metav1.NamespaceAll {
|
||||
cfg.FieldSelector = fields.AndSelectors(appendIfNotNil(namespaceAllSelector(maps.Keys(opts.DefaultNamespaces)), cfg.FieldSelector)...)
|
||||
}
|
||||
opts.DefaultNamespaces[namespace] = cfg
|
||||
}
|
||||
|
||||
for obj, byObject := range opts.ByObject {
|
||||
isNamespaced, err := apiutil.IsObjectNamespaced(obj, opts.Scheme, opts.Mapper)
|
||||
if err != nil {
|
||||
@@ -435,7 +443,12 @@ func defaultOpts(config *rest.Config, opts Options) (Options, error) {
|
||||
return opts, fmt.Errorf("type %T is not namespaced, but its ByObject.Namespaces setting is not nil", obj)
|
||||
}
|
||||
|
||||
// Default the namespace-level configs first, because they need to use the undefaulted type-level config.
|
||||
if isNamespaced && byObject.Namespaces == nil {
|
||||
byObject.Namespaces = maps.Clone(opts.DefaultNamespaces)
|
||||
}
|
||||
|
||||
// Default the namespace-level configs first, because they need to use the undefaulted type-level config
|
||||
// to be able to potentially fall through to settings from DefaultNamespaces.
|
||||
for namespace, config := range byObject.Namespaces {
|
||||
// 1. Default from the undefaulted type-level config
|
||||
config = defaultConfig(config, byObjectToConfig(byObject))
|
||||
@@ -461,19 +474,35 @@ func defaultOpts(config *rest.Config, opts Options) (Options, error) {
|
||||
byObject.Namespaces[namespace] = config
|
||||
}
|
||||
|
||||
defaultedConfig := defaultConfig(byObjectToConfig(byObject), optionDefaultsToConfig(&opts))
|
||||
byObject.Label = defaultedConfig.LabelSelector
|
||||
byObject.Field = defaultedConfig.FieldSelector
|
||||
byObject.Transform = defaultedConfig.Transform
|
||||
byObject.UnsafeDisableDeepCopy = defaultedConfig.UnsafeDisableDeepCopy
|
||||
|
||||
if isNamespaced && byObject.Namespaces == nil {
|
||||
byObject.Namespaces = opts.DefaultNamespaces
|
||||
// Only default ByObject iself if it isn't namespaced or has no namespaces configured, as only
|
||||
// then any of this will be honored.
|
||||
if !isNamespaced || len(byObject.Namespaces) == 0 {
|
||||
defaultedConfig := defaultConfig(byObjectToConfig(byObject), optionDefaultsToConfig(&opts))
|
||||
byObject.Label = defaultedConfig.LabelSelector
|
||||
byObject.Field = defaultedConfig.FieldSelector
|
||||
byObject.Transform = defaultedConfig.Transform
|
||||
byObject.UnsafeDisableDeepCopy = defaultedConfig.UnsafeDisableDeepCopy
|
||||
}
|
||||
|
||||
opts.ByObject[obj] = byObject
|
||||
}
|
||||
|
||||
// Default namespaces after byObject has been defaulted, otherwise a namespace without selectors
|
||||
// will get the `Default` selectors, then get copied to byObject and then not get defaulted from
|
||||
// byObject, as it already has selectors.
|
||||
for namespace, cfg := range opts.DefaultNamespaces {
|
||||
cfg = defaultConfig(cfg, optionDefaultsToConfig(&opts))
|
||||
if namespace == metav1.NamespaceAll {
|
||||
cfg.FieldSelector = fields.AndSelectors(
|
||||
appendIfNotNil(
|
||||
namespaceAllSelector(maps.Keys(opts.DefaultNamespaces)),
|
||||
cfg.FieldSelector,
|
||||
)...,
|
||||
)
|
||||
}
|
||||
opts.DefaultNamespaces[namespace] = cfg
|
||||
}
|
||||
|
||||
// Default the resync period to 10 hours if unset
|
||||
if opts.SyncPeriod == nil {
|
||||
opts.SyncPeriod = &defaultSyncPeriod
|
||||
@@ -498,20 +527,21 @@ func defaultConfig(toDefault, defaultFrom Config) Config {
|
||||
return toDefault
|
||||
}
|
||||
|
||||
func namespaceAllSelector(namespaces []string) fields.Selector {
|
||||
func namespaceAllSelector(namespaces []string) []fields.Selector {
|
||||
selectors := make([]fields.Selector, 0, len(namespaces)-1)
|
||||
sort.Strings(namespaces)
|
||||
for _, namespace := range namespaces {
|
||||
if namespace != metav1.NamespaceAll {
|
||||
selectors = append(selectors, fields.OneTermNotEqualSelector("metadata.namespace", namespace))
|
||||
}
|
||||
}
|
||||
|
||||
return fields.AndSelectors(selectors...)
|
||||
return selectors
|
||||
}
|
||||
|
||||
func appendIfNotNil[T comparable](a, b T) []T {
|
||||
func appendIfNotNil[T comparable](a []T, b T) []T {
|
||||
if b != *new(T) {
|
||||
return []T{a, b}
|
||||
return append(a, b)
|
||||
}
|
||||
return []T{a}
|
||||
return a
|
||||
}
|
||||
|
||||
2
vendor/sigs.k8s.io/controller-runtime/pkg/cache/internal/cache_reader.go
generated
vendored
2
vendor/sigs.k8s.io/controller-runtime/pkg/cache/internal/cache_reader.go
generated
vendored
@@ -36,7 +36,7 @@ import (
|
||||
// CacheReader is a client.Reader.
|
||||
var _ client.Reader = &CacheReader{}
|
||||
|
||||
// CacheReader wraps a cache.Index to implement the client.CacheReader interface for a single type.
|
||||
// CacheReader wraps a cache.Index to implement the client.Reader interface for a single type.
|
||||
type CacheReader struct {
|
||||
// indexer is the underlying indexer wrapped by this cache.
|
||||
indexer cache.Indexer
|
||||
|
||||
13
vendor/sigs.k8s.io/controller-runtime/pkg/cache/internal/informers.go
generated
vendored
13
vendor/sigs.k8s.io/controller-runtime/pkg/cache/internal/informers.go
generated
vendored
@@ -18,6 +18,7 @@ package internal
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"net/http"
|
||||
@@ -186,10 +187,14 @@ type Informers struct {
|
||||
// Start calls Run on each of the informers and sets started to true. Blocks on the context.
|
||||
// It doesn't return start because it can't return an error, and it's not a runnable directly.
|
||||
func (ip *Informers) Start(ctx context.Context) error {
|
||||
func() {
|
||||
if err := func() error {
|
||||
ip.mu.Lock()
|
||||
defer ip.mu.Unlock()
|
||||
|
||||
if ip.started {
|
||||
return errors.New("Informer already started") //nolint:stylecheck
|
||||
}
|
||||
|
||||
// Set the context so it can be passed to informers that are added later
|
||||
ip.ctx = ctx
|
||||
|
||||
@@ -207,7 +212,11 @@ func (ip *Informers) Start(ctx context.Context) error {
|
||||
// Set started to true so we immediately start any informers added later.
|
||||
ip.started = true
|
||||
close(ip.startWait)
|
||||
}()
|
||||
|
||||
return nil
|
||||
}(); err != nil {
|
||||
return err
|
||||
}
|
||||
<-ctx.Done() // Block until the context is done
|
||||
ip.mu.Lock()
|
||||
ip.stopped = true // Set stopped to true so we don't start any new informers
|
||||
|
||||
14
vendor/sigs.k8s.io/controller-runtime/pkg/cache/multi_namespace_cache.go
generated
vendored
14
vendor/sigs.k8s.io/controller-runtime/pkg/cache/multi_namespace_cache.go
generated
vendored
@@ -163,12 +163,13 @@ func (c *multiNamespaceCache) GetInformerForKind(ctx context.Context, gvk schema
|
||||
}
|
||||
|
||||
func (c *multiNamespaceCache) Start(ctx context.Context) error {
|
||||
errs := make(chan error)
|
||||
// start global cache
|
||||
if c.clusterCache != nil {
|
||||
go func() {
|
||||
err := c.clusterCache.Start(ctx)
|
||||
if err != nil {
|
||||
log.Error(err, "cluster scoped cache failed to start")
|
||||
errs <- fmt.Errorf("failed to start cluster-scoped cache: %w", err)
|
||||
}
|
||||
}()
|
||||
}
|
||||
@@ -177,13 +178,16 @@ func (c *multiNamespaceCache) Start(ctx context.Context) error {
|
||||
for ns, cache := range c.namespaceToCache {
|
||||
go func(ns string, cache Cache) {
|
||||
if err := cache.Start(ctx); err != nil {
|
||||
log.Error(err, "multi-namespace cache failed to start namespaced informer", "namespace", ns)
|
||||
errs <- fmt.Errorf("failed to start cache for namespace %s: %w", ns, err)
|
||||
}
|
||||
}(ns, cache)
|
||||
}
|
||||
|
||||
<-ctx.Done()
|
||||
return nil
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return nil
|
||||
case err := <-errs:
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
func (c *multiNamespaceCache) WaitForCacheSync(ctx context.Context) bool {
|
||||
|
||||
10
vendor/sigs.k8s.io/controller-runtime/pkg/certwatcher/certwatcher.go
generated
vendored
10
vendor/sigs.k8s.io/controller-runtime/pkg/certwatcher/certwatcher.go
generated
vendored
@@ -173,14 +173,14 @@ func (cw *CertWatcher) ReadCertificate() error {
|
||||
|
||||
func (cw *CertWatcher) handleEvent(event fsnotify.Event) {
|
||||
// Only care about events which may modify the contents of the file.
|
||||
if !(isWrite(event) || isRemove(event) || isCreate(event)) {
|
||||
if !(isWrite(event) || isRemove(event) || isCreate(event) || isChmod(event)) {
|
||||
return
|
||||
}
|
||||
|
||||
log.V(1).Info("certificate event", "event", event)
|
||||
|
||||
// If the file was removed, re-add the watch.
|
||||
if isRemove(event) {
|
||||
// If the file was removed or renamed, re-add the watch to the previous name
|
||||
if isRemove(event) || isChmod(event) {
|
||||
if err := cw.watcher.Add(event.Name); err != nil {
|
||||
log.Error(err, "error re-watching file")
|
||||
}
|
||||
@@ -202,3 +202,7 @@ func isCreate(event fsnotify.Event) bool {
|
||||
func isRemove(event fsnotify.Event) bool {
|
||||
return event.Op.Has(fsnotify.Remove)
|
||||
}
|
||||
|
||||
func isChmod(event fsnotify.Event) bool {
|
||||
return event.Op.Has(fsnotify.Chmod)
|
||||
}
|
||||
|
||||
5
vendor/sigs.k8s.io/controller-runtime/pkg/client/apiutil/apimachinery.go
generated
vendored
5
vendor/sigs.k8s.io/controller-runtime/pkg/client/apiutil/apimachinery.go
generated
vendored
@@ -72,7 +72,10 @@ func IsObjectNamespaced(obj runtime.Object, scheme *runtime.Scheme, restmapper m
|
||||
// IsGVKNamespaced returns true if the object having the provided
|
||||
// GVK is namespace scoped.
|
||||
func IsGVKNamespaced(gvk schema.GroupVersionKind, restmapper meta.RESTMapper) (bool, error) {
|
||||
restmapping, err := restmapper.RESTMapping(schema.GroupKind{Group: gvk.Group, Kind: gvk.Kind})
|
||||
// Fetch the RESTMapping using the complete GVK. If we exclude the Version, the Version set
|
||||
// will be populated using the cached Group if available. This can lead to failures updating
|
||||
// the cache with new Versions of CRDs registered at runtime.
|
||||
restmapping, err := restmapper.RESTMapping(schema.GroupKind{Group: gvk.Group, Kind: gvk.Kind}, gvk.Version)
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("failed to get restmapping: %w", err)
|
||||
}
|
||||
|
||||
41
vendor/sigs.k8s.io/controller-runtime/pkg/client/client.go
generated
vendored
41
vendor/sigs.k8s.io/controller-runtime/pkg/client/client.go
generated
vendored
@@ -50,28 +50,10 @@ type Options struct {
|
||||
// Cache, if provided, is used to read objects from the cache.
|
||||
Cache *CacheOptions
|
||||
|
||||
// WarningHandler is used to configure the warning handler responsible for
|
||||
// surfacing and handling warnings messages sent by the API server.
|
||||
WarningHandler WarningHandlerOptions
|
||||
|
||||
// DryRun instructs the client to only perform dry run requests.
|
||||
DryRun *bool
|
||||
}
|
||||
|
||||
// WarningHandlerOptions are options for configuring a
|
||||
// warning handler for the client which is responsible
|
||||
// for surfacing API Server warnings.
|
||||
type WarningHandlerOptions struct {
|
||||
// SuppressWarnings decides if the warnings from the
|
||||
// API server are suppressed or surfaced in the client.
|
||||
SuppressWarnings bool
|
||||
// AllowDuplicateLogs does not deduplicate the to-be
|
||||
// logged surfaced warnings messages. See
|
||||
// log.WarningHandlerOptions for considerations
|
||||
// regarding deduplication
|
||||
AllowDuplicateLogs bool
|
||||
}
|
||||
|
||||
// CacheOptions are options for creating a cache-backed client.
|
||||
type CacheOptions struct {
|
||||
// Reader is a cache-backed reader that will be used to read objects from the cache.
|
||||
@@ -91,6 +73,12 @@ type NewClientFunc func(config *rest.Config, options Options) (Client, error)
|
||||
|
||||
// New returns a new Client using the provided config and Options.
|
||||
//
|
||||
// By default, the client surfaces warnings returned by the server. To
|
||||
// suppress warnings, set config.WarningHandler = rest.NoWarnings{}. To
|
||||
// define custom behavior, implement the rest.WarningHandler interface.
|
||||
// See [sigs.k8s.io/controller-runtime/pkg/log.KubeAPIWarningLogger] for
|
||||
// an example.
|
||||
//
|
||||
// The client's read behavior is determined by Options.Cache.
|
||||
// If either Options.Cache or Options.Cache.Reader is nil,
|
||||
// the client reads directly from the API server.
|
||||
@@ -124,17 +112,12 @@ func newClient(config *rest.Config, options Options) (*client, error) {
|
||||
config.UserAgent = rest.DefaultKubernetesUserAgent()
|
||||
}
|
||||
|
||||
if !options.WarningHandler.SuppressWarnings {
|
||||
// surface warnings
|
||||
logger := log.Log.WithName("KubeAPIWarningLogger")
|
||||
// Set a WarningHandler, the default WarningHandler
|
||||
// is log.KubeAPIWarningLogger with deduplication enabled.
|
||||
// See log.KubeAPIWarningLoggerOptions for considerations
|
||||
// regarding deduplication.
|
||||
if config.WarningHandler == nil {
|
||||
// By default, we de-duplicate and surface warnings.
|
||||
config.WarningHandler = log.NewKubeAPIWarningLogger(
|
||||
logger,
|
||||
log.Log.WithName("KubeAPIWarningLogger"),
|
||||
log.KubeAPIWarningLoggerOptions{
|
||||
Deduplicate: !options.WarningHandler.AllowDuplicateLogs,
|
||||
Deduplicate: true,
|
||||
},
|
||||
)
|
||||
}
|
||||
@@ -523,8 +506,8 @@ func (co *SubResourceCreateOptions) ApplyOptions(opts []SubResourceCreateOption)
|
||||
return co
|
||||
}
|
||||
|
||||
// ApplyToSubresourceCreate applies the the configuration on the given create options.
|
||||
func (co *SubResourceCreateOptions) ApplyToSubresourceCreate(o *SubResourceCreateOptions) {
|
||||
// ApplyToSubResourceCreate applies the the configuration on the given create options.
|
||||
func (co *SubResourceCreateOptions) ApplyToSubResourceCreate(o *SubResourceCreateOptions) {
|
||||
co.CreateOptions.ApplyToCreate(&co.CreateOptions)
|
||||
}
|
||||
|
||||
|
||||
329
vendor/sigs.k8s.io/controller-runtime/pkg/client/fake/client.go
generated
vendored
329
vendor/sigs.k8s.io/controller-runtime/pkg/client/fake/client.go
generated
vendored
@@ -30,7 +30,9 @@ import (
|
||||
"time"
|
||||
|
||||
// Using v4 to match upstream
|
||||
jsonpatch "github.com/evanphx/json-patch"
|
||||
jsonpatch "gopkg.in/evanphx/json-patch.v4"
|
||||
appsv1 "k8s.io/api/apps/v1"
|
||||
autoscalingv1 "k8s.io/api/autoscaling/v1"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
policyv1 "k8s.io/api/policy/v1"
|
||||
policyv1beta1 "k8s.io/api/policy/v1beta1"
|
||||
@@ -50,6 +52,7 @@ import (
|
||||
"k8s.io/apimachinery/pkg/watch"
|
||||
"k8s.io/client-go/kubernetes/scheme"
|
||||
"k8s.io/client-go/testing"
|
||||
"k8s.io/utils/ptr"
|
||||
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client/apiutil"
|
||||
@@ -65,16 +68,21 @@ type versionedTracker struct {
|
||||
}
|
||||
|
||||
type fakeClient struct {
|
||||
tracker versionedTracker
|
||||
scheme *runtime.Scheme
|
||||
// trackerWriteLock must be acquired before writing to
|
||||
// the tracker or performing reads that affect a following
|
||||
// write.
|
||||
trackerWriteLock sync.Mutex
|
||||
tracker versionedTracker
|
||||
|
||||
schemeWriteLock sync.Mutex
|
||||
scheme *runtime.Scheme
|
||||
|
||||
restMapper meta.RESTMapper
|
||||
withStatusSubresource sets.Set[schema.GroupVersionKind]
|
||||
|
||||
// indexes maps each GroupVersionKind (GVK) to the indexes registered for that GVK.
|
||||
// The inner map maps from index name to IndexerFunc.
|
||||
indexes map[schema.GroupVersionKind]map[string]client.IndexerFunc
|
||||
|
||||
schemeWriteLock sync.Mutex
|
||||
}
|
||||
|
||||
var _ client.WithWatch = &fakeClient{}
|
||||
@@ -83,6 +91,8 @@ const (
|
||||
maxNameLength = 63
|
||||
randomLength = 5
|
||||
maxGeneratedNameLength = maxNameLength - randomLength
|
||||
|
||||
subResourceScale = "scale"
|
||||
)
|
||||
|
||||
// NewFakeClient creates a new fake client for testing.
|
||||
@@ -301,7 +311,7 @@ func (t versionedTracker) Add(obj runtime.Object) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t versionedTracker) Create(gvr schema.GroupVersionResource, obj runtime.Object, ns string) error {
|
||||
func (t versionedTracker) Create(gvr schema.GroupVersionResource, obj runtime.Object, ns string, opts ...metav1.CreateOptions) error {
|
||||
accessor, err := meta.Accessor(obj)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get accessor for object: %w", err)
|
||||
@@ -320,7 +330,7 @@ func (t versionedTracker) Create(gvr schema.GroupVersionResource, obj runtime.Ob
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := t.ObjectTracker.Create(gvr, obj, ns); err != nil {
|
||||
if err := t.ObjectTracker.Create(gvr, obj, ns, opts...); err != nil {
|
||||
accessor.SetResourceVersion("")
|
||||
return err
|
||||
}
|
||||
@@ -359,24 +369,59 @@ func convertFromUnstructuredIfNecessary(s *runtime.Scheme, o runtime.Object) (ru
|
||||
return typed, nil
|
||||
}
|
||||
|
||||
func (t versionedTracker) Update(gvr schema.GroupVersionResource, obj runtime.Object, ns string) error {
|
||||
func (t versionedTracker) Update(gvr schema.GroupVersionResource, obj runtime.Object, ns string, opts ...metav1.UpdateOptions) error {
|
||||
updateOpts, err := getSingleOrZeroOptions(opts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return t.update(gvr, obj, ns, false, false, updateOpts)
|
||||
}
|
||||
|
||||
func (t versionedTracker) update(gvr schema.GroupVersionResource, obj runtime.Object, ns string, isStatus, deleting bool, opts metav1.UpdateOptions) error {
|
||||
obj, err := t.updateObject(gvr, obj, ns, isStatus, deleting, opts.DryRun)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if obj == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return t.ObjectTracker.Update(gvr, obj, ns, opts)
|
||||
}
|
||||
|
||||
func (t versionedTracker) Patch(gvr schema.GroupVersionResource, obj runtime.Object, ns string, opts ...metav1.PatchOptions) error {
|
||||
patchOptions, err := getSingleOrZeroOptions(opts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
isStatus := false
|
||||
// We apply patches using a client-go reaction that ends up calling the trackers Update. As we can't change
|
||||
// We apply patches using a client-go reaction that ends up calling the trackers Patch. As we can't change
|
||||
// that reaction, we use the callstack to figure out if this originated from the status client.
|
||||
if bytes.Contains(debug.Stack(), []byte("sigs.k8s.io/controller-runtime/pkg/client/fake.(*fakeSubResourceClient).statusPatch")) {
|
||||
isStatus = true
|
||||
}
|
||||
return t.update(gvr, obj, ns, isStatus, false)
|
||||
|
||||
obj, err = t.updateObject(gvr, obj, ns, isStatus, false, patchOptions.DryRun)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if obj == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return t.ObjectTracker.Patch(gvr, obj, ns, patchOptions)
|
||||
}
|
||||
|
||||
func (t versionedTracker) update(gvr schema.GroupVersionResource, obj runtime.Object, ns string, isStatus bool, deleting bool) error {
|
||||
func (t versionedTracker) updateObject(gvr schema.GroupVersionResource, obj runtime.Object, ns string, isStatus, deleting bool, dryRun []string) (runtime.Object, error) {
|
||||
accessor, err := meta.Accessor(obj)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get accessor for object: %w", err)
|
||||
return nil, fmt.Errorf("failed to get accessor for object: %w", err)
|
||||
}
|
||||
|
||||
if accessor.GetName() == "" {
|
||||
return apierrors.NewInvalid(
|
||||
return nil, apierrors.NewInvalid(
|
||||
obj.GetObjectKind().GroupVersionKind().GroupKind(),
|
||||
accessor.GetName(),
|
||||
field.ErrorList{field.Required(field.NewPath("metadata.name"), "name is required")})
|
||||
@@ -384,7 +429,7 @@ func (t versionedTracker) update(gvr schema.GroupVersionResource, obj runtime.Ob
|
||||
|
||||
gvk, err := apiutil.GVKForObject(obj, t.scheme)
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
oldObject, err := t.ObjectTracker.Get(gvr, ns, accessor.GetName())
|
||||
@@ -392,65 +437,75 @@ func (t versionedTracker) update(gvr schema.GroupVersionResource, obj runtime.Ob
|
||||
// If the resource is not found and the resource allows create on update, issue a
|
||||
// create instead.
|
||||
if apierrors.IsNotFound(err) && allowsCreateOnUpdate(gvk) {
|
||||
return t.Create(gvr, obj, ns)
|
||||
return nil, t.Create(gvr, obj, ns)
|
||||
}
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if t.withStatusSubresource.Has(gvk) {
|
||||
if isStatus { // copy everything but status and metadata.ResourceVersion from original object
|
||||
if err := copyStatusFrom(obj, oldObject); err != nil {
|
||||
return fmt.Errorf("failed to copy non-status field for object with status subresouce: %w", err)
|
||||
return nil, fmt.Errorf("failed to copy non-status field for object with status subresouce: %w", err)
|
||||
}
|
||||
passedRV := accessor.GetResourceVersion()
|
||||
if err := copyFrom(oldObject, obj); err != nil {
|
||||
return fmt.Errorf("failed to restore non-status fields: %w", err)
|
||||
return nil, fmt.Errorf("failed to restore non-status fields: %w", err)
|
||||
}
|
||||
accessor.SetResourceVersion(passedRV)
|
||||
} else { // copy status from original object
|
||||
if err := copyStatusFrom(oldObject, obj); err != nil {
|
||||
return fmt.Errorf("failed to copy the status for object with status subresource: %w", err)
|
||||
return nil, fmt.Errorf("failed to copy the status for object with status subresource: %w", err)
|
||||
}
|
||||
}
|
||||
} else if isStatus {
|
||||
return apierrors.NewNotFound(gvr.GroupResource(), accessor.GetName())
|
||||
return nil, apierrors.NewNotFound(gvr.GroupResource(), accessor.GetName())
|
||||
}
|
||||
|
||||
oldAccessor, err := meta.Accessor(oldObject)
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// If the new object does not have the resource version set and it allows unconditional update,
|
||||
// default it to the resource version of the existing resource
|
||||
if accessor.GetResourceVersion() == "" && allowsUnconditionalUpdate(gvk) {
|
||||
accessor.SetResourceVersion(oldAccessor.GetResourceVersion())
|
||||
if accessor.GetResourceVersion() == "" {
|
||||
switch {
|
||||
case allowsUnconditionalUpdate(gvk):
|
||||
accessor.SetResourceVersion(oldAccessor.GetResourceVersion())
|
||||
// This is needed because if the patch explicitly sets the RV to null, the client-go reaction we use
|
||||
// to apply it and whose output we process here will have it unset. It is not clear why the Kubernetes
|
||||
// apiserver accepts such a patch, but it does so we just copy that behavior.
|
||||
// Kubernetes apiserver behavior can be checked like this:
|
||||
// `kubectl patch configmap foo --patch '{"metadata":{"annotations":{"foo":"bar"},"resourceVersion":null}}' -v=9`
|
||||
case bytes.
|
||||
Contains(debug.Stack(), []byte("sigs.k8s.io/controller-runtime/pkg/client/fake.(*fakeClient).Patch")):
|
||||
// We apply patches using a client-go reaction that ends up calling the trackers Update. As we can't change
|
||||
// that reaction, we use the callstack to figure out if this originated from the "fakeClient.Patch" func.
|
||||
accessor.SetResourceVersion(oldAccessor.GetResourceVersion())
|
||||
}
|
||||
}
|
||||
|
||||
if accessor.GetResourceVersion() != oldAccessor.GetResourceVersion() {
|
||||
return apierrors.NewConflict(gvr.GroupResource(), accessor.GetName(), errors.New("object was modified"))
|
||||
return nil, apierrors.NewConflict(gvr.GroupResource(), accessor.GetName(), errors.New("object was modified"))
|
||||
}
|
||||
if oldAccessor.GetResourceVersion() == "" {
|
||||
oldAccessor.SetResourceVersion("0")
|
||||
}
|
||||
intResourceVersion, err := strconv.ParseUint(oldAccessor.GetResourceVersion(), 10, 64)
|
||||
if err != nil {
|
||||
return fmt.Errorf("can not convert resourceVersion %q to int: %w", oldAccessor.GetResourceVersion(), err)
|
||||
return nil, fmt.Errorf("can not convert resourceVersion %q to int: %w", oldAccessor.GetResourceVersion(), err)
|
||||
}
|
||||
intResourceVersion++
|
||||
accessor.SetResourceVersion(strconv.FormatUint(intResourceVersion, 10))
|
||||
|
||||
if !deleting && !deletionTimestampEqual(accessor, oldAccessor) {
|
||||
return fmt.Errorf("error: Unable to edit %s: metadata.deletionTimestamp field is immutable", accessor.GetName())
|
||||
return nil, fmt.Errorf("error: Unable to edit %s: metadata.deletionTimestamp field is immutable", accessor.GetName())
|
||||
}
|
||||
|
||||
if !accessor.GetDeletionTimestamp().IsZero() && len(accessor.GetFinalizers()) == 0 {
|
||||
return t.ObjectTracker.Delete(gvr, accessor.GetNamespace(), accessor.GetName())
|
||||
return nil, t.ObjectTracker.Delete(gvr, accessor.GetNamespace(), accessor.GetName(), metav1.DeleteOptions{DryRun: dryRun})
|
||||
}
|
||||
obj, err = convertFromUnstructuredIfNecessary(t.scheme, obj)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return t.ObjectTracker.Update(gvr, obj, ns)
|
||||
return convertFromUnstructuredIfNecessary(t.scheme, obj)
|
||||
}
|
||||
|
||||
func (c *fakeClient) Get(ctx context.Context, key client.ObjectKey, obj client.Object, opts ...client.GetOption) error {
|
||||
@@ -463,7 +518,10 @@ func (c *fakeClient) Get(ctx context.Context, key client.ObjectKey, obj client.O
|
||||
return err
|
||||
}
|
||||
|
||||
if _, isUnstructured := obj.(runtime.Unstructured); isUnstructured {
|
||||
_, isUnstructured := obj.(runtime.Unstructured)
|
||||
_, isPartialObject := obj.(*metav1.PartialObjectMetadata)
|
||||
|
||||
if isUnstructured || isPartialObject {
|
||||
gvk, err := apiutil.GVKForObject(obj, c.scheme)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -684,6 +742,8 @@ func (c *fakeClient) Create(ctx context.Context, obj client.Object, opts ...clie
|
||||
accessor.SetDeletionTimestamp(nil)
|
||||
}
|
||||
|
||||
c.trackerWriteLock.Lock()
|
||||
defer c.trackerWriteLock.Unlock()
|
||||
return c.tracker.Create(gvr, obj, accessor.GetNamespace())
|
||||
}
|
||||
|
||||
@@ -705,6 +765,8 @@ func (c *fakeClient) Delete(ctx context.Context, obj client.Object, opts ...clie
|
||||
}
|
||||
}
|
||||
|
||||
c.trackerWriteLock.Lock()
|
||||
defer c.trackerWriteLock.Unlock()
|
||||
// Check the ResourceVersion if that Precondition was specified.
|
||||
if delOptions.Preconditions != nil && delOptions.Preconditions.ResourceVersion != nil {
|
||||
name := accessor.GetName()
|
||||
@@ -727,7 +789,7 @@ func (c *fakeClient) Delete(ctx context.Context, obj client.Object, opts ...clie
|
||||
}
|
||||
}
|
||||
|
||||
return c.deleteObject(gvr, accessor)
|
||||
return c.deleteObjectLocked(gvr, accessor)
|
||||
}
|
||||
|
||||
func (c *fakeClient) DeleteAllOf(ctx context.Context, obj client.Object, opts ...client.DeleteAllOfOption) error {
|
||||
@@ -745,6 +807,9 @@ func (c *fakeClient) DeleteAllOf(ctx context.Context, obj client.Object, opts ..
|
||||
}
|
||||
}
|
||||
|
||||
c.trackerWriteLock.Lock()
|
||||
defer c.trackerWriteLock.Unlock()
|
||||
|
||||
gvr, _ := meta.UnsafeGuessKindToResource(gvk)
|
||||
o, err := c.tracker.List(gvr, gvk, dcOptions.Namespace)
|
||||
if err != nil {
|
||||
@@ -764,7 +829,7 @@ func (c *fakeClient) DeleteAllOf(ctx context.Context, obj client.Object, opts ..
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = c.deleteObject(gvr, accessor)
|
||||
err = c.deleteObjectLocked(gvr, accessor)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -794,7 +859,10 @@ func (c *fakeClient) update(obj client.Object, isStatus bool, opts ...client.Upd
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return c.tracker.update(gvr, obj, accessor.GetNamespace(), isStatus, false)
|
||||
|
||||
c.trackerWriteLock.Lock()
|
||||
defer c.trackerWriteLock.Unlock()
|
||||
return c.tracker.update(gvr, obj, accessor.GetNamespace(), isStatus, false, *updateOptions.AsUpdateOptions())
|
||||
}
|
||||
|
||||
func (c *fakeClient) Patch(ctx context.Context, obj client.Object, patch client.Patch, opts ...client.PatchOption) error {
|
||||
@@ -829,6 +897,8 @@ func (c *fakeClient) patch(obj client.Object, patch client.Patch, opts ...client
|
||||
return err
|
||||
}
|
||||
|
||||
c.trackerWriteLock.Lock()
|
||||
defer c.trackerWriteLock.Unlock()
|
||||
oldObj, err := c.tracker.Get(gvr, accessor.GetNamespace(), accessor.GetName())
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -1037,7 +1107,7 @@ func (c *fakeClient) SubResource(subResource string) client.SubResourceClient {
|
||||
return &fakeSubResourceClient{client: c, subResource: subResource}
|
||||
}
|
||||
|
||||
func (c *fakeClient) deleteObject(gvr schema.GroupVersionResource, accessor metav1.Object) error {
|
||||
func (c *fakeClient) deleteObjectLocked(gvr schema.GroupVersionResource, accessor metav1.Object) error {
|
||||
old, err := c.tracker.Get(gvr, accessor.GetNamespace(), accessor.GetName())
|
||||
if err == nil {
|
||||
oldAccessor, err := meta.Accessor(old)
|
||||
@@ -1047,7 +1117,7 @@ func (c *fakeClient) deleteObject(gvr schema.GroupVersionResource, accessor meta
|
||||
oldAccessor.SetDeletionTimestamp(&now)
|
||||
// Call update directly with mutability parameter set to true to allow
|
||||
// changes to deletionTimestamp
|
||||
return c.tracker.update(gvr, old, accessor.GetNamespace(), false, true)
|
||||
return c.tracker.update(gvr, old, accessor.GetNamespace(), false, true, metav1.UpdateOptions{})
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1071,7 +1141,26 @@ type fakeSubResourceClient struct {
|
||||
}
|
||||
|
||||
func (sw *fakeSubResourceClient) Get(ctx context.Context, obj, subResource client.Object, opts ...client.SubResourceGetOption) error {
|
||||
panic("fakeSubResourceClient does not support get")
|
||||
switch sw.subResource {
|
||||
case subResourceScale:
|
||||
// Actual client looks up resource, then extracts the scale sub-resource:
|
||||
// https://github.com/kubernetes/kubernetes/blob/fb6bbc9781d11a87688c398778525c4e1dcb0f08/pkg/registry/apps/deployment/storage/storage.go#L307
|
||||
if err := sw.client.Get(ctx, client.ObjectKeyFromObject(obj), obj); err != nil {
|
||||
return err
|
||||
}
|
||||
scale, isScale := subResource.(*autoscalingv1.Scale)
|
||||
if !isScale {
|
||||
return apierrors.NewBadRequest(fmt.Sprintf("expected Scale, got %t", subResource))
|
||||
}
|
||||
scaleOut, err := extractScale(obj)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*scale = *scaleOut
|
||||
return nil
|
||||
default:
|
||||
return fmt.Errorf("fakeSubResourceClient does not support get for %s", sw.subResource)
|
||||
}
|
||||
}
|
||||
|
||||
func (sw *fakeSubResourceClient) Create(ctx context.Context, obj client.Object, subResource client.Object, opts ...client.SubResourceCreateOption) error {
|
||||
@@ -1098,11 +1187,30 @@ func (sw *fakeSubResourceClient) Update(ctx context.Context, obj client.Object,
|
||||
updateOptions := client.SubResourceUpdateOptions{}
|
||||
updateOptions.ApplyOptions(opts)
|
||||
|
||||
body := obj
|
||||
if updateOptions.SubResourceBody != nil {
|
||||
body = updateOptions.SubResourceBody
|
||||
switch sw.subResource {
|
||||
case subResourceScale:
|
||||
if err := sw.client.Get(ctx, client.ObjectKeyFromObject(obj), obj.DeepCopyObject().(client.Object)); err != nil {
|
||||
return err
|
||||
}
|
||||
if updateOptions.SubResourceBody == nil {
|
||||
return apierrors.NewBadRequest("missing SubResourceBody")
|
||||
}
|
||||
|
||||
scale, isScale := updateOptions.SubResourceBody.(*autoscalingv1.Scale)
|
||||
if !isScale {
|
||||
return apierrors.NewBadRequest(fmt.Sprintf("expected Scale, got %t", updateOptions.SubResourceBody))
|
||||
}
|
||||
if err := applyScale(obj, scale); err != nil {
|
||||
return err
|
||||
}
|
||||
return sw.client.update(obj, false, &updateOptions.UpdateOptions)
|
||||
default:
|
||||
body := obj
|
||||
if updateOptions.SubResourceBody != nil {
|
||||
body = updateOptions.SubResourceBody
|
||||
}
|
||||
return sw.client.update(body, true, &updateOptions.UpdateOptions)
|
||||
}
|
||||
return sw.client.update(body, true, &updateOptions.UpdateOptions)
|
||||
}
|
||||
|
||||
func (sw *fakeSubResourceClient) Patch(ctx context.Context, obj client.Object, patch client.Patch, opts ...client.SubResourcePatchOption) error {
|
||||
@@ -1269,3 +1377,138 @@ func zero(x interface{}) {
|
||||
res := reflect.ValueOf(x).Elem()
|
||||
res.Set(reflect.Zero(res.Type()))
|
||||
}
|
||||
|
||||
// getSingleOrZeroOptions returns the single options value in the slice, its
|
||||
// zero value if the slice is empty, or an error if the slice contains more than
|
||||
// one option value.
|
||||
func getSingleOrZeroOptions[T any](opts []T) (opt T, err error) {
|
||||
switch len(opts) {
|
||||
case 0:
|
||||
case 1:
|
||||
opt = opts[0]
|
||||
default:
|
||||
err = fmt.Errorf("expected single or no options value, got %d values", len(opts))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func extractScale(obj client.Object) (*autoscalingv1.Scale, error) {
|
||||
switch obj := obj.(type) {
|
||||
case *appsv1.Deployment:
|
||||
var replicas int32 = 1
|
||||
if obj.Spec.Replicas != nil {
|
||||
replicas = *obj.Spec.Replicas
|
||||
}
|
||||
var selector string
|
||||
if obj.Spec.Selector != nil {
|
||||
selector = obj.Spec.Selector.String()
|
||||
}
|
||||
return &autoscalingv1.Scale{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: obj.Namespace,
|
||||
Name: obj.Name,
|
||||
UID: obj.UID,
|
||||
ResourceVersion: obj.ResourceVersion,
|
||||
CreationTimestamp: obj.CreationTimestamp,
|
||||
},
|
||||
Spec: autoscalingv1.ScaleSpec{
|
||||
Replicas: replicas,
|
||||
},
|
||||
Status: autoscalingv1.ScaleStatus{
|
||||
Replicas: obj.Status.Replicas,
|
||||
Selector: selector,
|
||||
},
|
||||
}, nil
|
||||
case *appsv1.ReplicaSet:
|
||||
var replicas int32 = 1
|
||||
if obj.Spec.Replicas != nil {
|
||||
replicas = *obj.Spec.Replicas
|
||||
}
|
||||
var selector string
|
||||
if obj.Spec.Selector != nil {
|
||||
selector = obj.Spec.Selector.String()
|
||||
}
|
||||
return &autoscalingv1.Scale{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: obj.Namespace,
|
||||
Name: obj.Name,
|
||||
UID: obj.UID,
|
||||
ResourceVersion: obj.ResourceVersion,
|
||||
CreationTimestamp: obj.CreationTimestamp,
|
||||
},
|
||||
Spec: autoscalingv1.ScaleSpec{
|
||||
Replicas: replicas,
|
||||
},
|
||||
Status: autoscalingv1.ScaleStatus{
|
||||
Replicas: obj.Status.Replicas,
|
||||
Selector: selector,
|
||||
},
|
||||
}, nil
|
||||
case *corev1.ReplicationController:
|
||||
var replicas int32 = 1
|
||||
if obj.Spec.Replicas != nil {
|
||||
replicas = *obj.Spec.Replicas
|
||||
}
|
||||
return &autoscalingv1.Scale{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: obj.Namespace,
|
||||
Name: obj.Name,
|
||||
UID: obj.UID,
|
||||
ResourceVersion: obj.ResourceVersion,
|
||||
CreationTimestamp: obj.CreationTimestamp,
|
||||
},
|
||||
Spec: autoscalingv1.ScaleSpec{
|
||||
Replicas: replicas,
|
||||
},
|
||||
Status: autoscalingv1.ScaleStatus{
|
||||
Replicas: obj.Status.Replicas,
|
||||
Selector: labels.Set(obj.Spec.Selector).String(),
|
||||
},
|
||||
}, nil
|
||||
case *appsv1.StatefulSet:
|
||||
var replicas int32 = 1
|
||||
if obj.Spec.Replicas != nil {
|
||||
replicas = *obj.Spec.Replicas
|
||||
}
|
||||
var selector string
|
||||
if obj.Spec.Selector != nil {
|
||||
selector = obj.Spec.Selector.String()
|
||||
}
|
||||
return &autoscalingv1.Scale{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: obj.Namespace,
|
||||
Name: obj.Name,
|
||||
UID: obj.UID,
|
||||
ResourceVersion: obj.ResourceVersion,
|
||||
CreationTimestamp: obj.CreationTimestamp,
|
||||
},
|
||||
Spec: autoscalingv1.ScaleSpec{
|
||||
Replicas: replicas,
|
||||
},
|
||||
Status: autoscalingv1.ScaleStatus{
|
||||
Replicas: obj.Status.Replicas,
|
||||
Selector: selector,
|
||||
},
|
||||
}, nil
|
||||
default:
|
||||
// TODO: CRDs https://kubernetes.io/docs/tasks/extend-kubernetes/custom-resources/custom-resource-definitions/#scale-subresource
|
||||
return nil, fmt.Errorf("unimplemented scale subresource for resource %T", obj)
|
||||
}
|
||||
}
|
||||
|
||||
func applyScale(obj client.Object, scale *autoscalingv1.Scale) error {
|
||||
switch obj := obj.(type) {
|
||||
case *appsv1.Deployment:
|
||||
obj.Spec.Replicas = ptr.To(scale.Spec.Replicas)
|
||||
case *appsv1.ReplicaSet:
|
||||
obj.Spec.Replicas = ptr.To(scale.Spec.Replicas)
|
||||
case *corev1.ReplicationController:
|
||||
obj.Spec.Replicas = ptr.To(scale.Spec.Replicas)
|
||||
case *appsv1.StatefulSet:
|
||||
obj.Spec.Replicas = ptr.To(scale.Spec.Replicas)
|
||||
default:
|
||||
// TODO: CRDs https://kubernetes.io/docs/tasks/extend-kubernetes/custom-resources/custom-resource-definitions/#scale-subresource
|
||||
return fmt.Errorf("unimplemented scale subresource for resource %T", obj)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
106
vendor/sigs.k8s.io/controller-runtime/pkg/client/fieldowner.go
generated
vendored
Normal file
106
vendor/sigs.k8s.io/controller-runtime/pkg/client/fieldowner.go
generated
vendored
Normal file
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
)
|
||||
|
||||
// WithFieldOwner wraps a Client and adds the fieldOwner as the field
|
||||
// manager to all write requests from this client. If additional [FieldOwner]
|
||||
// options are specified on methods of this client, the value specified here
|
||||
// will be overridden.
|
||||
func WithFieldOwner(c Client, fieldOwner string) Client {
|
||||
return &clientWithFieldManager{
|
||||
owner: fieldOwner,
|
||||
c: c,
|
||||
Reader: c,
|
||||
}
|
||||
}
|
||||
|
||||
type clientWithFieldManager struct {
|
||||
owner string
|
||||
c Client
|
||||
Reader
|
||||
}
|
||||
|
||||
func (f *clientWithFieldManager) Create(ctx context.Context, obj Object, opts ...CreateOption) error {
|
||||
return f.c.Create(ctx, obj, append([]CreateOption{FieldOwner(f.owner)}, opts...)...)
|
||||
}
|
||||
|
||||
func (f *clientWithFieldManager) Update(ctx context.Context, obj Object, opts ...UpdateOption) error {
|
||||
return f.c.Update(ctx, obj, append([]UpdateOption{FieldOwner(f.owner)}, opts...)...)
|
||||
}
|
||||
|
||||
func (f *clientWithFieldManager) Patch(ctx context.Context, obj Object, patch Patch, opts ...PatchOption) error {
|
||||
return f.c.Patch(ctx, obj, patch, append([]PatchOption{FieldOwner(f.owner)}, opts...)...)
|
||||
}
|
||||
|
||||
func (f *clientWithFieldManager) Delete(ctx context.Context, obj Object, opts ...DeleteOption) error {
|
||||
return f.c.Delete(ctx, obj, opts...)
|
||||
}
|
||||
|
||||
func (f *clientWithFieldManager) DeleteAllOf(ctx context.Context, obj Object, opts ...DeleteAllOfOption) error {
|
||||
return f.c.DeleteAllOf(ctx, obj, opts...)
|
||||
}
|
||||
|
||||
func (f *clientWithFieldManager) Scheme() *runtime.Scheme { return f.c.Scheme() }
|
||||
func (f *clientWithFieldManager) RESTMapper() meta.RESTMapper { return f.c.RESTMapper() }
|
||||
func (f *clientWithFieldManager) GroupVersionKindFor(obj runtime.Object) (schema.GroupVersionKind, error) {
|
||||
return f.c.GroupVersionKindFor(obj)
|
||||
}
|
||||
func (f *clientWithFieldManager) IsObjectNamespaced(obj runtime.Object) (bool, error) {
|
||||
return f.c.IsObjectNamespaced(obj)
|
||||
}
|
||||
|
||||
func (f *clientWithFieldManager) Status() StatusWriter {
|
||||
return &subresourceClientWithFieldOwner{
|
||||
owner: f.owner,
|
||||
subresourceWriter: f.c.Status(),
|
||||
}
|
||||
}
|
||||
|
||||
func (f *clientWithFieldManager) SubResource(subresource string) SubResourceClient {
|
||||
c := f.c.SubResource(subresource)
|
||||
return &subresourceClientWithFieldOwner{
|
||||
owner: f.owner,
|
||||
subresourceWriter: c,
|
||||
SubResourceReader: c,
|
||||
}
|
||||
}
|
||||
|
||||
type subresourceClientWithFieldOwner struct {
|
||||
owner string
|
||||
subresourceWriter SubResourceWriter
|
||||
SubResourceReader
|
||||
}
|
||||
|
||||
func (f *subresourceClientWithFieldOwner) Create(ctx context.Context, obj Object, subresource Object, opts ...SubResourceCreateOption) error {
|
||||
return f.subresourceWriter.Create(ctx, obj, subresource, append([]SubResourceCreateOption{FieldOwner(f.owner)}, opts...)...)
|
||||
}
|
||||
|
||||
func (f *subresourceClientWithFieldOwner) Update(ctx context.Context, obj Object, opts ...SubResourceUpdateOption) error {
|
||||
return f.subresourceWriter.Update(ctx, obj, append([]SubResourceUpdateOption{FieldOwner(f.owner)}, opts...)...)
|
||||
}
|
||||
|
||||
func (f *subresourceClientWithFieldOwner) Patch(ctx context.Context, obj Object, patch Patch, opts ...SubResourcePatchOption) error {
|
||||
return f.subresourceWriter.Patch(ctx, obj, patch, append([]SubResourcePatchOption{FieldOwner(f.owner)}, opts...)...)
|
||||
}
|
||||
106
vendor/sigs.k8s.io/controller-runtime/pkg/client/fieldvalidation.go
generated
vendored
Normal file
106
vendor/sigs.k8s.io/controller-runtime/pkg/client/fieldvalidation.go
generated
vendored
Normal file
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
)
|
||||
|
||||
// WithFieldValidation wraps a Client and configures field validation, by
|
||||
// default, for all write requests from this client. Users can override field
|
||||
// validation for individual write requests.
|
||||
func WithFieldValidation(c Client, validation FieldValidation) Client {
|
||||
return &clientWithFieldValidation{
|
||||
validation: validation,
|
||||
client: c,
|
||||
Reader: c,
|
||||
}
|
||||
}
|
||||
|
||||
type clientWithFieldValidation struct {
|
||||
validation FieldValidation
|
||||
client Client
|
||||
Reader
|
||||
}
|
||||
|
||||
func (c *clientWithFieldValidation) Create(ctx context.Context, obj Object, opts ...CreateOption) error {
|
||||
return c.client.Create(ctx, obj, append([]CreateOption{c.validation}, opts...)...)
|
||||
}
|
||||
|
||||
func (c *clientWithFieldValidation) Update(ctx context.Context, obj Object, opts ...UpdateOption) error {
|
||||
return c.client.Update(ctx, obj, append([]UpdateOption{c.validation}, opts...)...)
|
||||
}
|
||||
|
||||
func (c *clientWithFieldValidation) Patch(ctx context.Context, obj Object, patch Patch, opts ...PatchOption) error {
|
||||
return c.client.Patch(ctx, obj, patch, append([]PatchOption{c.validation}, opts...)...)
|
||||
}
|
||||
|
||||
func (c *clientWithFieldValidation) Delete(ctx context.Context, obj Object, opts ...DeleteOption) error {
|
||||
return c.client.Delete(ctx, obj, opts...)
|
||||
}
|
||||
|
||||
func (c *clientWithFieldValidation) DeleteAllOf(ctx context.Context, obj Object, opts ...DeleteAllOfOption) error {
|
||||
return c.client.DeleteAllOf(ctx, obj, opts...)
|
||||
}
|
||||
|
||||
func (c *clientWithFieldValidation) Scheme() *runtime.Scheme { return c.client.Scheme() }
|
||||
func (c *clientWithFieldValidation) RESTMapper() meta.RESTMapper { return c.client.RESTMapper() }
|
||||
func (c *clientWithFieldValidation) GroupVersionKindFor(obj runtime.Object) (schema.GroupVersionKind, error) {
|
||||
return c.client.GroupVersionKindFor(obj)
|
||||
}
|
||||
|
||||
func (c *clientWithFieldValidation) IsObjectNamespaced(obj runtime.Object) (bool, error) {
|
||||
return c.client.IsObjectNamespaced(obj)
|
||||
}
|
||||
|
||||
func (c *clientWithFieldValidation) Status() StatusWriter {
|
||||
return &subresourceClientWithFieldValidation{
|
||||
validation: c.validation,
|
||||
subresourceWriter: c.client.Status(),
|
||||
}
|
||||
}
|
||||
|
||||
func (c *clientWithFieldValidation) SubResource(subresource string) SubResourceClient {
|
||||
srClient := c.client.SubResource(subresource)
|
||||
return &subresourceClientWithFieldValidation{
|
||||
validation: c.validation,
|
||||
subresourceWriter: srClient,
|
||||
SubResourceReader: srClient,
|
||||
}
|
||||
}
|
||||
|
||||
type subresourceClientWithFieldValidation struct {
|
||||
validation FieldValidation
|
||||
subresourceWriter SubResourceWriter
|
||||
SubResourceReader
|
||||
}
|
||||
|
||||
func (c *subresourceClientWithFieldValidation) Create(ctx context.Context, obj Object, subresource Object, opts ...SubResourceCreateOption) error {
|
||||
return c.subresourceWriter.Create(ctx, obj, subresource, append([]SubResourceCreateOption{c.validation}, opts...)...)
|
||||
}
|
||||
|
||||
func (c *subresourceClientWithFieldValidation) Update(ctx context.Context, obj Object, opts ...SubResourceUpdateOption) error {
|
||||
return c.subresourceWriter.Update(ctx, obj, append([]SubResourceUpdateOption{c.validation}, opts...)...)
|
||||
}
|
||||
|
||||
func (c *subresourceClientWithFieldValidation) Patch(ctx context.Context, obj Object, patch Patch, opts ...SubResourcePatchOption) error {
|
||||
return c.subresourceWriter.Patch(ctx, obj, patch, append([]SubResourcePatchOption{c.validation}, opts...)...)
|
||||
}
|
||||
99
vendor/sigs.k8s.io/controller-runtime/pkg/client/options.go
generated
vendored
99
vendor/sigs.k8s.io/controller-runtime/pkg/client/options.go
generated
vendored
@@ -169,6 +169,39 @@ func (f FieldOwner) ApplyToSubResourceUpdate(opts *SubResourceUpdateOptions) {
|
||||
opts.FieldManager = string(f)
|
||||
}
|
||||
|
||||
// FieldValidation configures field validation for the given requests.
|
||||
type FieldValidation string
|
||||
|
||||
// ApplyToPatch applies this configuration to the given patch options.
|
||||
func (f FieldValidation) ApplyToPatch(opts *PatchOptions) {
|
||||
opts.FieldValidation = string(f)
|
||||
}
|
||||
|
||||
// ApplyToCreate applies this configuration to the given create options.
|
||||
func (f FieldValidation) ApplyToCreate(opts *CreateOptions) {
|
||||
opts.FieldValidation = string(f)
|
||||
}
|
||||
|
||||
// ApplyToUpdate applies this configuration to the given update options.
|
||||
func (f FieldValidation) ApplyToUpdate(opts *UpdateOptions) {
|
||||
opts.FieldValidation = string(f)
|
||||
}
|
||||
|
||||
// ApplyToSubResourcePatch applies this configuration to the given patch options.
|
||||
func (f FieldValidation) ApplyToSubResourcePatch(opts *SubResourcePatchOptions) {
|
||||
opts.FieldValidation = string(f)
|
||||
}
|
||||
|
||||
// ApplyToSubResourceCreate applies this configuration to the given create options.
|
||||
func (f FieldValidation) ApplyToSubResourceCreate(opts *SubResourceCreateOptions) {
|
||||
opts.FieldValidation = string(f)
|
||||
}
|
||||
|
||||
// ApplyToSubResourceUpdate applies this configuration to the given update options.
|
||||
func (f FieldValidation) ApplyToSubResourceUpdate(opts *SubResourceUpdateOptions) {
|
||||
opts.FieldValidation = string(f)
|
||||
}
|
||||
|
||||
// }}}
|
||||
|
||||
// {{{ Create Options
|
||||
@@ -187,6 +220,24 @@ type CreateOptions struct {
|
||||
// this request. It must be set with server-side apply.
|
||||
FieldManager string
|
||||
|
||||
// fieldValidation instructs the server on how to handle
|
||||
// objects in the request (POST/PUT/PATCH) containing unknown
|
||||
// or duplicate fields. Valid values are:
|
||||
// - Ignore: This will ignore any unknown fields that are silently
|
||||
// dropped from the object, and will ignore all but the last duplicate
|
||||
// field that the decoder encounters. This is the default behavior
|
||||
// prior to v1.23.
|
||||
// - Warn: This will send a warning via the standard warning response
|
||||
// header for each unknown field that is dropped from the object, and
|
||||
// for each duplicate field that is encountered. The request will
|
||||
// still succeed if there are no other errors, and will only persist
|
||||
// the last of any duplicate fields. This is the default in v1.23+
|
||||
// - Strict: This will fail the request with a BadRequest error if
|
||||
// any unknown fields would be dropped from the object, or if any
|
||||
// duplicate fields are present. The error returned from the server
|
||||
// will contain all unknown and duplicate fields encountered.
|
||||
FieldValidation string
|
||||
|
||||
// Raw represents raw CreateOptions, as passed to the API server.
|
||||
Raw *metav1.CreateOptions
|
||||
}
|
||||
@@ -203,6 +254,7 @@ func (o *CreateOptions) AsCreateOptions() *metav1.CreateOptions {
|
||||
|
||||
o.Raw.DryRun = o.DryRun
|
||||
o.Raw.FieldManager = o.FieldManager
|
||||
o.Raw.FieldValidation = o.FieldValidation
|
||||
return o.Raw
|
||||
}
|
||||
|
||||
@@ -223,6 +275,9 @@ func (o *CreateOptions) ApplyToCreate(co *CreateOptions) {
|
||||
if o.FieldManager != "" {
|
||||
co.FieldManager = o.FieldManager
|
||||
}
|
||||
if o.FieldValidation != "" {
|
||||
co.FieldValidation = o.FieldValidation
|
||||
}
|
||||
if o.Raw != nil {
|
||||
co.Raw = o.Raw
|
||||
}
|
||||
@@ -679,6 +734,24 @@ type UpdateOptions struct {
|
||||
// this request. It must be set with server-side apply.
|
||||
FieldManager string
|
||||
|
||||
// fieldValidation instructs the server on how to handle
|
||||
// objects in the request (POST/PUT/PATCH) containing unknown
|
||||
// or duplicate fields. Valid values are:
|
||||
// - Ignore: This will ignore any unknown fields that are silently
|
||||
// dropped from the object, and will ignore all but the last duplicate
|
||||
// field that the decoder encounters. This is the default behavior
|
||||
// prior to v1.23.
|
||||
// - Warn: This will send a warning via the standard warning response
|
||||
// header for each unknown field that is dropped from the object, and
|
||||
// for each duplicate field that is encountered. The request will
|
||||
// still succeed if there are no other errors, and will only persist
|
||||
// the last of any duplicate fields. This is the default in v1.23+
|
||||
// - Strict: This will fail the request with a BadRequest error if
|
||||
// any unknown fields would be dropped from the object, or if any
|
||||
// duplicate fields are present. The error returned from the server
|
||||
// will contain all unknown and duplicate fields encountered.
|
||||
FieldValidation string
|
||||
|
||||
// Raw represents raw UpdateOptions, as passed to the API server.
|
||||
Raw *metav1.UpdateOptions
|
||||
}
|
||||
@@ -695,6 +768,7 @@ func (o *UpdateOptions) AsUpdateOptions() *metav1.UpdateOptions {
|
||||
|
||||
o.Raw.DryRun = o.DryRun
|
||||
o.Raw.FieldManager = o.FieldManager
|
||||
o.Raw.FieldValidation = o.FieldValidation
|
||||
return o.Raw
|
||||
}
|
||||
|
||||
@@ -717,6 +791,9 @@ func (o *UpdateOptions) ApplyToUpdate(uo *UpdateOptions) {
|
||||
if o.FieldManager != "" {
|
||||
uo.FieldManager = o.FieldManager
|
||||
}
|
||||
if o.FieldValidation != "" {
|
||||
uo.FieldValidation = o.FieldValidation
|
||||
}
|
||||
if o.Raw != nil {
|
||||
uo.Raw = o.Raw
|
||||
}
|
||||
@@ -745,6 +822,24 @@ type PatchOptions struct {
|
||||
// this request. It must be set with server-side apply.
|
||||
FieldManager string
|
||||
|
||||
// fieldValidation instructs the server on how to handle
|
||||
// objects in the request (POST/PUT/PATCH) containing unknown
|
||||
// or duplicate fields. Valid values are:
|
||||
// - Ignore: This will ignore any unknown fields that are silently
|
||||
// dropped from the object, and will ignore all but the last duplicate
|
||||
// field that the decoder encounters. This is the default behavior
|
||||
// prior to v1.23.
|
||||
// - Warn: This will send a warning via the standard warning response
|
||||
// header for each unknown field that is dropped from the object, and
|
||||
// for each duplicate field that is encountered. The request will
|
||||
// still succeed if there are no other errors, and will only persist
|
||||
// the last of any duplicate fields. This is the default in v1.23+
|
||||
// - Strict: This will fail the request with a BadRequest error if
|
||||
// any unknown fields would be dropped from the object, or if any
|
||||
// duplicate fields are present. The error returned from the server
|
||||
// will contain all unknown and duplicate fields encountered.
|
||||
FieldValidation string
|
||||
|
||||
// Raw represents raw PatchOptions, as passed to the API server.
|
||||
Raw *metav1.PatchOptions
|
||||
}
|
||||
@@ -771,6 +866,7 @@ func (o *PatchOptions) AsPatchOptions() *metav1.PatchOptions {
|
||||
o.Raw.DryRun = o.DryRun
|
||||
o.Raw.Force = o.Force
|
||||
o.Raw.FieldManager = o.FieldManager
|
||||
o.Raw.FieldValidation = o.FieldValidation
|
||||
return o.Raw
|
||||
}
|
||||
|
||||
@@ -787,6 +883,9 @@ func (o *PatchOptions) ApplyToPatch(po *PatchOptions) {
|
||||
if o.FieldManager != "" {
|
||||
po.FieldManager = o.FieldManager
|
||||
}
|
||||
if o.FieldValidation != "" {
|
||||
po.FieldValidation = o.FieldValidation
|
||||
}
|
||||
if o.Raw != nil {
|
||||
po.Raw = o.Raw
|
||||
}
|
||||
|
||||
112
vendor/sigs.k8s.io/controller-runtime/pkg/config/config.go
generated
vendored
112
vendor/sigs.k8s.io/controller-runtime/pkg/config/config.go
generated
vendored
@@ -1,112 +0,0 @@
|
||||
/*
|
||||
Copyright 2020 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 config
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"sync"
|
||||
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/serializer"
|
||||
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
|
||||
"sigs.k8s.io/controller-runtime/pkg/config/v1alpha1"
|
||||
)
|
||||
|
||||
// ControllerManagerConfiguration defines the functions necessary to parse a config file
|
||||
// and to configure the Options struct for the ctrl.Manager.
|
||||
//
|
||||
// Deprecated: The component config package has been deprecated and will be removed in a future release. Users should migrate to their own config implementation, please share feedback in https://github.com/kubernetes-sigs/controller-runtime/issues/895.
|
||||
type ControllerManagerConfiguration interface {
|
||||
runtime.Object
|
||||
|
||||
// Complete returns the versioned configuration
|
||||
Complete() (v1alpha1.ControllerManagerConfigurationSpec, error)
|
||||
}
|
||||
|
||||
// DeferredFileLoader is used to configure the decoder for loading controller
|
||||
// runtime component config types.
|
||||
//
|
||||
// Deprecated: The component config package has been deprecated and will be removed in a future release. Users should migrate to their own config implementation, please share feedback in https://github.com/kubernetes-sigs/controller-runtime/issues/895.
|
||||
type DeferredFileLoader struct {
|
||||
ControllerManagerConfiguration
|
||||
path string
|
||||
scheme *runtime.Scheme
|
||||
once sync.Once
|
||||
err error
|
||||
}
|
||||
|
||||
// File will set up the deferred file loader for the configuration
|
||||
// this will also configure the defaults for the loader if nothing is
|
||||
//
|
||||
// Defaults:
|
||||
// * Path: "./config.yaml"
|
||||
// * Kind: GenericControllerManagerConfiguration
|
||||
//
|
||||
// Deprecated: The component config package has been deprecated and will be removed in a future release. Users should migrate to their own config implementation, please share feedback in https://github.com/kubernetes-sigs/controller-runtime/issues/895.
|
||||
func File() *DeferredFileLoader {
|
||||
scheme := runtime.NewScheme()
|
||||
utilruntime.Must(v1alpha1.AddToScheme(scheme))
|
||||
return &DeferredFileLoader{
|
||||
path: "./config.yaml",
|
||||
ControllerManagerConfiguration: &v1alpha1.ControllerManagerConfiguration{},
|
||||
scheme: scheme,
|
||||
}
|
||||
}
|
||||
|
||||
// Complete will use sync.Once to set the scheme.
|
||||
func (d *DeferredFileLoader) Complete() (v1alpha1.ControllerManagerConfigurationSpec, error) {
|
||||
d.once.Do(d.loadFile)
|
||||
if d.err != nil {
|
||||
return v1alpha1.ControllerManagerConfigurationSpec{}, d.err
|
||||
}
|
||||
return d.ControllerManagerConfiguration.Complete()
|
||||
}
|
||||
|
||||
// AtPath will set the path to load the file for the decoder.
|
||||
func (d *DeferredFileLoader) AtPath(path string) *DeferredFileLoader {
|
||||
d.path = path
|
||||
return d
|
||||
}
|
||||
|
||||
// OfKind will set the type to be used for decoding the file into.
|
||||
func (d *DeferredFileLoader) OfKind(obj ControllerManagerConfiguration) *DeferredFileLoader {
|
||||
d.ControllerManagerConfiguration = obj
|
||||
return d
|
||||
}
|
||||
|
||||
// loadFile is used from the mutex.Once to load the file.
|
||||
func (d *DeferredFileLoader) loadFile() {
|
||||
if d.scheme == nil {
|
||||
d.err = fmt.Errorf("scheme not supplied to controller configuration loader")
|
||||
return
|
||||
}
|
||||
|
||||
content, err := os.ReadFile(d.path)
|
||||
if err != nil {
|
||||
d.err = fmt.Errorf("could not read file at %s", d.path)
|
||||
return
|
||||
}
|
||||
|
||||
codecs := serializer.NewCodecFactory(d.scheme)
|
||||
|
||||
// Regardless of if the bytes are of any external version,
|
||||
// it will be read successfully and converted into the internal version
|
||||
if err = runtime.DecodeInto(codecs.UniversalDecoder(), content, d.ControllerManagerConfiguration); err != nil {
|
||||
d.err = fmt.Errorf("could not decode file into runtime.Object")
|
||||
}
|
||||
}
|
||||
9
vendor/sigs.k8s.io/controller-runtime/pkg/config/controller.go
generated
vendored
9
vendor/sigs.k8s.io/controller-runtime/pkg/config/controller.go
generated
vendored
@@ -20,6 +20,12 @@ import "time"
|
||||
|
||||
// Controller contains configuration options for a controller.
|
||||
type Controller struct {
|
||||
// SkipNameValidation allows skipping the name validation that ensures that every controller name is unique.
|
||||
// Unique controller names are important to get unique metrics and logs for a controller.
|
||||
// Can be overwritten for a controller via the SkipNameValidation setting on the controller.
|
||||
// Defaults to false if SkipNameValidation setting on controller and Manager are unset.
|
||||
SkipNameValidation *bool
|
||||
|
||||
// GroupKindConcurrency is a map from a Kind to the number of concurrent reconciliation
|
||||
// allowed for that controller.
|
||||
//
|
||||
@@ -40,7 +46,8 @@ type Controller struct {
|
||||
CacheSyncTimeout time.Duration
|
||||
|
||||
// RecoverPanic indicates whether the panic caused by reconcile should be recovered.
|
||||
// Defaults to the Controller.RecoverPanic setting from the Manager if unset.
|
||||
// Can be overwritten for a controller via the RecoverPanic setting on the controller.
|
||||
// Defaults to true if RecoverPanic setting on controller and Manager are unset.
|
||||
RecoverPanic *bool
|
||||
|
||||
// NeedLeaderElection indicates whether the controller needs to use leader election.
|
||||
|
||||
19
vendor/sigs.k8s.io/controller-runtime/pkg/config/doc.go
generated
vendored
19
vendor/sigs.k8s.io/controller-runtime/pkg/config/doc.go
generated
vendored
@@ -1,19 +0,0 @@
|
||||
/*
|
||||
Copyright 2020 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 config contains functionality for interacting with
|
||||
// configuration for controller-runtime components.
|
||||
package config
|
||||
22
vendor/sigs.k8s.io/controller-runtime/pkg/config/v1alpha1/doc.go
generated
vendored
22
vendor/sigs.k8s.io/controller-runtime/pkg/config/v1alpha1/doc.go
generated
vendored
@@ -1,22 +0,0 @@
|
||||
/*
|
||||
Copyright 2020 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 v1alpha1 provides the ControllerManagerConfiguration used for
|
||||
// configuring ctrl.Manager
|
||||
// +kubebuilder:object:generate=true
|
||||
//
|
||||
// Deprecated: The component config package has been deprecated and will be removed in a future release. Users should migrate to their own config implementation, please share feedback in https://github.com/kubernetes-sigs/controller-runtime/issues/895.
|
||||
package v1alpha1
|
||||
43
vendor/sigs.k8s.io/controller-runtime/pkg/config/v1alpha1/register.go
generated
vendored
43
vendor/sigs.k8s.io/controller-runtime/pkg/config/v1alpha1/register.go
generated
vendored
@@ -1,43 +0,0 @@
|
||||
/*
|
||||
Copyright 2020 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 v1alpha1
|
||||
|
||||
import (
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"sigs.k8s.io/controller-runtime/pkg/scheme"
|
||||
)
|
||||
|
||||
var (
|
||||
// GroupVersion is group version used to register these objects.
|
||||
//
|
||||
// Deprecated: The component config package has been deprecated and will be removed in a future release. Users should migrate to their own config implementation, please share feedback in https://github.com/kubernetes-sigs/controller-runtime/issues/895.
|
||||
GroupVersion = schema.GroupVersion{Group: "controller-runtime.sigs.k8s.io", Version: "v1alpha1"}
|
||||
|
||||
// SchemeBuilder is used to add go types to the GroupVersionKind scheme.
|
||||
//
|
||||
// Deprecated: The component config package has been deprecated and will be removed in a future release. Users should migrate to their own config implementation, please share feedback in https://github.com/kubernetes-sigs/controller-runtime/issues/895.
|
||||
SchemeBuilder = &scheme.Builder{GroupVersion: GroupVersion}
|
||||
|
||||
// AddToScheme adds the types in this group-version to the given scheme.
|
||||
//
|
||||
// Deprecated: The component config package has been deprecated and will be removed in a future release. Users should migrate to their own config implementation, please share feedback in https://github.com/kubernetes-sigs/controller-runtime/issues/895.
|
||||
AddToScheme = SchemeBuilder.AddToScheme
|
||||
)
|
||||
|
||||
func init() {
|
||||
SchemeBuilder.Register(&ControllerManagerConfiguration{})
|
||||
}
|
||||
179
vendor/sigs.k8s.io/controller-runtime/pkg/config/v1alpha1/types.go
generated
vendored
179
vendor/sigs.k8s.io/controller-runtime/pkg/config/v1alpha1/types.go
generated
vendored
@@ -1,179 +0,0 @@
|
||||
/*
|
||||
Copyright 2020 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 v1alpha1
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
configv1alpha1 "k8s.io/component-base/config/v1alpha1"
|
||||
)
|
||||
|
||||
// ControllerManagerConfigurationSpec defines the desired state of GenericControllerManagerConfiguration.
|
||||
//
|
||||
// Deprecated: The component config package has been deprecated and will be removed in a future release. Users should migrate to their own config implementation, please share feedback in https://github.com/kubernetes-sigs/controller-runtime/issues/895.
|
||||
type ControllerManagerConfigurationSpec struct {
|
||||
// SyncPeriod determines the minimum frequency at which watched resources are
|
||||
// reconciled. A lower period will correct entropy more quickly, but reduce
|
||||
// responsiveness to change if there are many watched resources. Change this
|
||||
// value only if you know what you are doing. Defaults to 10 hours if unset.
|
||||
// there will a 10 percent jitter between the SyncPeriod of all controllers
|
||||
// so that all controllers will not send list requests simultaneously.
|
||||
// +optional
|
||||
SyncPeriod *metav1.Duration `json:"syncPeriod,omitempty"`
|
||||
|
||||
// LeaderElection is the LeaderElection config to be used when configuring
|
||||
// the manager.Manager leader election
|
||||
// +optional
|
||||
LeaderElection *configv1alpha1.LeaderElectionConfiguration `json:"leaderElection,omitempty"`
|
||||
|
||||
// CacheNamespace if specified restricts the manager's cache to watch objects in
|
||||
// the desired namespace Defaults to all namespaces
|
||||
//
|
||||
// Note: If a namespace is specified, controllers can still Watch for a
|
||||
// cluster-scoped resource (e.g Node). For namespaced resources the cache
|
||||
// will only hold objects from the desired namespace.
|
||||
// +optional
|
||||
CacheNamespace string `json:"cacheNamespace,omitempty"`
|
||||
|
||||
// GracefulShutdownTimeout is the duration given to runnable to stop before the manager actually returns on stop.
|
||||
// To disable graceful shutdown, set to time.Duration(0)
|
||||
// To use graceful shutdown without timeout, set to a negative duration, e.G. time.Duration(-1)
|
||||
// The graceful shutdown is skipped for safety reasons in case the leader election lease is lost.
|
||||
GracefulShutdownTimeout *metav1.Duration `json:"gracefulShutDown,omitempty"`
|
||||
|
||||
// Controller contains global configuration options for controllers
|
||||
// registered within this manager.
|
||||
// +optional
|
||||
Controller *ControllerConfigurationSpec `json:"controller,omitempty"`
|
||||
|
||||
// Metrics contains the controller metrics configuration
|
||||
// +optional
|
||||
Metrics ControllerMetrics `json:"metrics,omitempty"`
|
||||
|
||||
// Health contains the controller health configuration
|
||||
// +optional
|
||||
Health ControllerHealth `json:"health,omitempty"`
|
||||
|
||||
// Webhook contains the controllers webhook configuration
|
||||
// +optional
|
||||
Webhook ControllerWebhook `json:"webhook,omitempty"`
|
||||
}
|
||||
|
||||
// ControllerConfigurationSpec defines the global configuration for
|
||||
// controllers registered with the manager.
|
||||
//
|
||||
// Deprecated: The component config package has been deprecated and will be removed in a future release. Users should migrate to their own config implementation, please share feedback in https://github.com/kubernetes-sigs/controller-runtime/issues/895.
|
||||
//
|
||||
// Deprecated: Controller global configuration can now be set at the manager level,
|
||||
// using the manager.Options.Controller field.
|
||||
type ControllerConfigurationSpec struct {
|
||||
// GroupKindConcurrency is a map from a Kind to the number of concurrent reconciliation
|
||||
// allowed for that controller.
|
||||
//
|
||||
// When a controller is registered within this manager using the builder utilities,
|
||||
// users have to specify the type the controller reconciles in the For(...) call.
|
||||
// If the object's kind passed matches one of the keys in this map, the concurrency
|
||||
// for that controller is set to the number specified.
|
||||
//
|
||||
// The key is expected to be consistent in form with GroupKind.String(),
|
||||
// e.g. ReplicaSet in apps group (regardless of version) would be `ReplicaSet.apps`.
|
||||
//
|
||||
// +optional
|
||||
GroupKindConcurrency map[string]int `json:"groupKindConcurrency,omitempty"`
|
||||
|
||||
// CacheSyncTimeout refers to the time limit set to wait for syncing caches.
|
||||
// Defaults to 2 minutes if not set.
|
||||
// +optional
|
||||
CacheSyncTimeout *time.Duration `json:"cacheSyncTimeout,omitempty"`
|
||||
|
||||
// RecoverPanic indicates if panics should be recovered.
|
||||
// +optional
|
||||
RecoverPanic *bool `json:"recoverPanic,omitempty"`
|
||||
}
|
||||
|
||||
// ControllerMetrics defines the metrics configs.
|
||||
//
|
||||
// Deprecated: The component config package has been deprecated and will be removed in a future release. Users should migrate to their own config implementation, please share feedback in https://github.com/kubernetes-sigs/controller-runtime/issues/895.
|
||||
type ControllerMetrics struct {
|
||||
// BindAddress is the TCP address that the controller should bind to
|
||||
// for serving prometheus metrics.
|
||||
// It can be set to "0" to disable the metrics serving.
|
||||
// +optional
|
||||
BindAddress string `json:"bindAddress,omitempty"`
|
||||
}
|
||||
|
||||
// ControllerHealth defines the health configs.
|
||||
//
|
||||
// Deprecated: The component config package has been deprecated and will be removed in a future release. Users should migrate to their own config implementation, please share feedback in https://github.com/kubernetes-sigs/controller-runtime/issues/895.
|
||||
type ControllerHealth struct {
|
||||
// HealthProbeBindAddress is the TCP address that the controller should bind to
|
||||
// for serving health probes
|
||||
// It can be set to "0" or "" to disable serving the health probe.
|
||||
// +optional
|
||||
HealthProbeBindAddress string `json:"healthProbeBindAddress,omitempty"`
|
||||
|
||||
// ReadinessEndpointName, defaults to "readyz"
|
||||
// +optional
|
||||
ReadinessEndpointName string `json:"readinessEndpointName,omitempty"`
|
||||
|
||||
// LivenessEndpointName, defaults to "healthz"
|
||||
// +optional
|
||||
LivenessEndpointName string `json:"livenessEndpointName,omitempty"`
|
||||
}
|
||||
|
||||
// ControllerWebhook defines the webhook server for the controller.
|
||||
//
|
||||
// Deprecated: The component config package has been deprecated and will be removed in a future release. Users should migrate to their own config implementation, please share feedback in https://github.com/kubernetes-sigs/controller-runtime/issues/895.
|
||||
type ControllerWebhook struct {
|
||||
// Port is the port that the webhook server serves at.
|
||||
// It is used to set webhook.Server.Port.
|
||||
// +optional
|
||||
Port *int `json:"port,omitempty"`
|
||||
|
||||
// Host is the hostname that the webhook server binds to.
|
||||
// It is used to set webhook.Server.Host.
|
||||
// +optional
|
||||
Host string `json:"host,omitempty"`
|
||||
|
||||
// CertDir is the directory that contains the server key and certificate.
|
||||
// if not set, webhook server would look up the server key and certificate in
|
||||
// {TempDir}/k8s-webhook-server/serving-certs. The server key and certificate
|
||||
// must be named tls.key and tls.crt, respectively.
|
||||
// +optional
|
||||
CertDir string `json:"certDir,omitempty"`
|
||||
}
|
||||
|
||||
// +kubebuilder:object:root=true
|
||||
|
||||
// ControllerManagerConfiguration is the Schema for the GenericControllerManagerConfigurations API.
|
||||
//
|
||||
// Deprecated: The component config package has been deprecated and will be removed in a future release. Users should migrate to their own config implementation, please share feedback in https://github.com/kubernetes-sigs/controller-runtime/issues/895.
|
||||
type ControllerManagerConfiguration struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
|
||||
// ControllerManagerConfiguration returns the contfigurations for controllers
|
||||
ControllerManagerConfigurationSpec `json:",inline"`
|
||||
}
|
||||
|
||||
// Complete returns the configuration for controller-runtime.
|
||||
//
|
||||
// Deprecated: The component config package has been deprecated and will be removed in a future release. Users should migrate to their own config implementation, please share feedback in https://github.com/kubernetes-sigs/controller-runtime/issues/895.
|
||||
func (c *ControllerManagerConfigurationSpec) Complete() (ControllerManagerConfigurationSpec, error) {
|
||||
return *c, nil
|
||||
}
|
||||
157
vendor/sigs.k8s.io/controller-runtime/pkg/config/v1alpha1/zz_generated.deepcopy.go
generated
vendored
157
vendor/sigs.k8s.io/controller-runtime/pkg/config/v1alpha1/zz_generated.deepcopy.go
generated
vendored
@@ -1,157 +0,0 @@
|
||||
//go:build !ignore_autogenerated
|
||||
|
||||
// Code generated by controller-gen. DO NOT EDIT.
|
||||
|
||||
package v1alpha1
|
||||
|
||||
import (
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||
configv1alpha1 "k8s.io/component-base/config/v1alpha1"
|
||||
timex "time"
|
||||
)
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ControllerConfigurationSpec) DeepCopyInto(out *ControllerConfigurationSpec) {
|
||||
*out = *in
|
||||
if in.GroupKindConcurrency != nil {
|
||||
in, out := &in.GroupKindConcurrency, &out.GroupKindConcurrency
|
||||
*out = make(map[string]int, len(*in))
|
||||
for key, val := range *in {
|
||||
(*out)[key] = val
|
||||
}
|
||||
}
|
||||
if in.CacheSyncTimeout != nil {
|
||||
in, out := &in.CacheSyncTimeout, &out.CacheSyncTimeout
|
||||
*out = new(timex.Duration)
|
||||
**out = **in
|
||||
}
|
||||
if in.RecoverPanic != nil {
|
||||
in, out := &in.RecoverPanic, &out.RecoverPanic
|
||||
*out = new(bool)
|
||||
**out = **in
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ControllerConfigurationSpec.
|
||||
func (in *ControllerConfigurationSpec) DeepCopy() *ControllerConfigurationSpec {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(ControllerConfigurationSpec)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ControllerHealth) DeepCopyInto(out *ControllerHealth) {
|
||||
*out = *in
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ControllerHealth.
|
||||
func (in *ControllerHealth) DeepCopy() *ControllerHealth {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(ControllerHealth)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ControllerManagerConfiguration) DeepCopyInto(out *ControllerManagerConfiguration) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
in.ControllerManagerConfigurationSpec.DeepCopyInto(&out.ControllerManagerConfigurationSpec)
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ControllerManagerConfiguration.
|
||||
func (in *ControllerManagerConfiguration) DeepCopy() *ControllerManagerConfiguration {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(ControllerManagerConfiguration)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *ControllerManagerConfiguration) DeepCopyObject() runtime.Object {
|
||||
if c := in.DeepCopy(); c != nil {
|
||||
return c
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ControllerManagerConfigurationSpec) DeepCopyInto(out *ControllerManagerConfigurationSpec) {
|
||||
*out = *in
|
||||
if in.SyncPeriod != nil {
|
||||
in, out := &in.SyncPeriod, &out.SyncPeriod
|
||||
*out = new(v1.Duration)
|
||||
**out = **in
|
||||
}
|
||||
if in.LeaderElection != nil {
|
||||
in, out := &in.LeaderElection, &out.LeaderElection
|
||||
*out = new(configv1alpha1.LeaderElectionConfiguration)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
if in.GracefulShutdownTimeout != nil {
|
||||
in, out := &in.GracefulShutdownTimeout, &out.GracefulShutdownTimeout
|
||||
*out = new(v1.Duration)
|
||||
**out = **in
|
||||
}
|
||||
if in.Controller != nil {
|
||||
in, out := &in.Controller, &out.Controller
|
||||
*out = new(ControllerConfigurationSpec)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
out.Metrics = in.Metrics
|
||||
out.Health = in.Health
|
||||
in.Webhook.DeepCopyInto(&out.Webhook)
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ControllerManagerConfigurationSpec.
|
||||
func (in *ControllerManagerConfigurationSpec) DeepCopy() *ControllerManagerConfigurationSpec {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(ControllerManagerConfigurationSpec)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ControllerMetrics) DeepCopyInto(out *ControllerMetrics) {
|
||||
*out = *in
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ControllerMetrics.
|
||||
func (in *ControllerMetrics) DeepCopy() *ControllerMetrics {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(ControllerMetrics)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ControllerWebhook) DeepCopyInto(out *ControllerWebhook) {
|
||||
*out = *in
|
||||
if in.Port != nil {
|
||||
in, out := &in.Port, &out.Port
|
||||
*out = new(int)
|
||||
**out = **in
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ControllerWebhook.
|
||||
func (in *ControllerWebhook) DeepCopy() *ControllerWebhook {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(ControllerWebhook)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
106
vendor/sigs.k8s.io/controller-runtime/pkg/controller/controller.go
generated
vendored
106
vendor/sigs.k8s.io/controller-runtime/pkg/controller/controller.go
generated
vendored
@@ -25,17 +25,23 @@ import (
|
||||
"k8s.io/client-go/util/workqueue"
|
||||
"k8s.io/klog/v2"
|
||||
|
||||
"sigs.k8s.io/controller-runtime/pkg/handler"
|
||||
"sigs.k8s.io/controller-runtime/pkg/internal/controller"
|
||||
"sigs.k8s.io/controller-runtime/pkg/manager"
|
||||
"sigs.k8s.io/controller-runtime/pkg/predicate"
|
||||
"sigs.k8s.io/controller-runtime/pkg/ratelimiter"
|
||||
"sigs.k8s.io/controller-runtime/pkg/reconcile"
|
||||
"sigs.k8s.io/controller-runtime/pkg/source"
|
||||
)
|
||||
|
||||
// Options are the arguments for creating a new Controller.
|
||||
type Options struct {
|
||||
type Options = TypedOptions[reconcile.Request]
|
||||
|
||||
// TypedOptions are the arguments for creating a new Controller.
|
||||
type TypedOptions[request comparable] struct {
|
||||
// SkipNameValidation allows skipping the name validation that ensures that every controller name is unique.
|
||||
// Unique controller names are important to get unique metrics and logs for a controller.
|
||||
// Defaults to the Controller.SkipNameValidation setting from the Manager if unset.
|
||||
// Defaults to false if Controller.SkipNameValidation setting from the Manager is also unset.
|
||||
SkipNameValidation *bool
|
||||
|
||||
// MaxConcurrentReconciles is the maximum number of concurrent Reconciles which can be run. Defaults to 1.
|
||||
MaxConcurrentReconciles int
|
||||
|
||||
@@ -45,6 +51,7 @@ type Options struct {
|
||||
|
||||
// RecoverPanic indicates whether the panic caused by reconcile should be recovered.
|
||||
// Defaults to the Controller.RecoverPanic setting from the Manager if unset.
|
||||
// Defaults to true if Controller.RecoverPanic setting from the Manager is also unset.
|
||||
RecoverPanic *bool
|
||||
|
||||
// NeedLeaderElection indicates whether the controller needs to use leader election.
|
||||
@@ -52,33 +59,43 @@ type Options struct {
|
||||
NeedLeaderElection *bool
|
||||
|
||||
// Reconciler reconciles an object
|
||||
Reconciler reconcile.Reconciler
|
||||
Reconciler reconcile.TypedReconciler[request]
|
||||
|
||||
// RateLimiter is used to limit how frequently requests may be queued.
|
||||
// Defaults to MaxOfRateLimiter which has both overall and per-item rate limiting.
|
||||
// The overall is a token bucket and the per-item is exponential.
|
||||
RateLimiter ratelimiter.RateLimiter
|
||||
RateLimiter workqueue.TypedRateLimiter[request]
|
||||
|
||||
// NewQueue constructs the queue for this controller once the controller is ready to start.
|
||||
// With NewQueue a custom queue implementation can be used, e.g. a priority queue to prioritize with which
|
||||
// priority/order objects are reconciled (e.g. to reconcile objects with changes first).
|
||||
// This is a func because the standard Kubernetes work queues start themselves immediately, which
|
||||
// leads to goroutine leaks if something calls controller.New repeatedly.
|
||||
// The NewQueue func gets the controller name and the RateLimiter option (defaulted if necessary) passed in.
|
||||
// NewQueue defaults to NewRateLimitingQueueWithConfig.
|
||||
//
|
||||
// NOTE: LOW LEVEL PRIMITIVE!
|
||||
// Only use a custom NewQueue if you know what you are doing.
|
||||
NewQueue func(controllerName string, rateLimiter workqueue.TypedRateLimiter[request]) workqueue.TypedRateLimitingInterface[request]
|
||||
|
||||
// LogConstructor is used to construct a logger used for this controller and passed
|
||||
// to each reconciliation via the context field.
|
||||
LogConstructor func(request *reconcile.Request) logr.Logger
|
||||
LogConstructor func(request *request) logr.Logger
|
||||
}
|
||||
|
||||
// Controller implements a Kubernetes API. A Controller manages a work queue fed reconcile.Requests
|
||||
// from source.Sources. Work is performed through the reconcile.Reconciler for each enqueued item.
|
||||
// Work typically is reads and writes Kubernetes objects to make the system state match the state specified
|
||||
// in the object Spec.
|
||||
type Controller interface {
|
||||
// Reconciler is called to reconcile an object by Namespace/Name
|
||||
reconcile.Reconciler
|
||||
type Controller = TypedController[reconcile.Request]
|
||||
|
||||
// Watch takes events provided by a Source and uses the EventHandler to
|
||||
// enqueue reconcile.Requests in response to the events.
|
||||
//
|
||||
// Watch may be provided one or more Predicates to filter events before
|
||||
// they are given to the EventHandler. Events will be passed to the
|
||||
// EventHandler if all provided Predicates evaluate to true.
|
||||
Watch(src source.Source, eventhandler handler.EventHandler, predicates ...predicate.Predicate) error
|
||||
// TypedController implements an API.
|
||||
type TypedController[request comparable] interface {
|
||||
// Reconciler is called to reconcile an object by Namespace/Name
|
||||
reconcile.TypedReconciler[request]
|
||||
|
||||
// Watch watches the provided Source.
|
||||
Watch(src source.TypedSource[request]) error
|
||||
|
||||
// Start starts the controller. Start blocks until the context is closed or a
|
||||
// controller has an error starting.
|
||||
@@ -90,8 +107,17 @@ type Controller interface {
|
||||
|
||||
// New returns a new Controller registered with the Manager. The Manager will ensure that shared Caches have
|
||||
// been synced before the Controller is Started.
|
||||
//
|
||||
// The name must be unique as it is used to identify the controller in metrics and logs.
|
||||
func New(name string, mgr manager.Manager, options Options) (Controller, error) {
|
||||
c, err := NewUnmanaged(name, mgr, options)
|
||||
return NewTyped(name, mgr, options)
|
||||
}
|
||||
|
||||
// NewTyped returns a new typed controller registered with the Manager,
|
||||
//
|
||||
// The name must be unique as it is used to identify the controller in metrics and logs.
|
||||
func NewTyped[request comparable](name string, mgr manager.Manager, options TypedOptions[request]) (TypedController[request], error) {
|
||||
c, err := NewTypedUnmanaged(name, mgr, options)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -102,7 +128,16 @@ func New(name string, mgr manager.Manager, options Options) (Controller, error)
|
||||
|
||||
// NewUnmanaged returns a new controller without adding it to the manager. The
|
||||
// caller is responsible for starting the returned controller.
|
||||
//
|
||||
// The name must be unique as it is used to identify the controller in metrics and logs.
|
||||
func NewUnmanaged(name string, mgr manager.Manager, options Options) (Controller, error) {
|
||||
return NewTypedUnmanaged(name, mgr, options)
|
||||
}
|
||||
|
||||
// NewTypedUnmanaged returns a new typed controller without adding it to the manager.
|
||||
//
|
||||
// The name must be unique as it is used to identify the controller in metrics and logs.
|
||||
func NewTypedUnmanaged[request comparable](name string, mgr manager.Manager, options TypedOptions[request]) (TypedController[request], error) {
|
||||
if options.Reconciler == nil {
|
||||
return nil, fmt.Errorf("must specify Reconciler")
|
||||
}
|
||||
@@ -111,13 +146,23 @@ func NewUnmanaged(name string, mgr manager.Manager, options Options) (Controller
|
||||
return nil, fmt.Errorf("must specify Name for Controller")
|
||||
}
|
||||
|
||||
if options.SkipNameValidation == nil {
|
||||
options.SkipNameValidation = mgr.GetControllerOptions().SkipNameValidation
|
||||
}
|
||||
|
||||
if options.SkipNameValidation == nil || !*options.SkipNameValidation {
|
||||
if err := checkName(name); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if options.LogConstructor == nil {
|
||||
log := mgr.GetLogger().WithValues(
|
||||
"controller", name,
|
||||
)
|
||||
options.LogConstructor = func(req *reconcile.Request) logr.Logger {
|
||||
options.LogConstructor = func(in *request) logr.Logger {
|
||||
log := log
|
||||
if req != nil {
|
||||
if req, ok := any(in).(*reconcile.Request); ok && req != nil {
|
||||
log = log.WithValues(
|
||||
"object", klog.KRef(req.Namespace, req.Name),
|
||||
"namespace", req.Namespace, "name", req.Name,
|
||||
@@ -144,7 +189,15 @@ func NewUnmanaged(name string, mgr manager.Manager, options Options) (Controller
|
||||
}
|
||||
|
||||
if options.RateLimiter == nil {
|
||||
options.RateLimiter = workqueue.DefaultControllerRateLimiter()
|
||||
options.RateLimiter = workqueue.DefaultTypedControllerRateLimiter[request]()
|
||||
}
|
||||
|
||||
if options.NewQueue == nil {
|
||||
options.NewQueue = func(controllerName string, rateLimiter workqueue.TypedRateLimiter[request]) workqueue.TypedRateLimitingInterface[request] {
|
||||
return workqueue.NewTypedRateLimitingQueueWithConfig(rateLimiter, workqueue.TypedRateLimitingQueueConfig[request]{
|
||||
Name: controllerName,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
if options.RecoverPanic == nil {
|
||||
@@ -156,13 +209,10 @@ func NewUnmanaged(name string, mgr manager.Manager, options Options) (Controller
|
||||
}
|
||||
|
||||
// Create controller with dependencies set
|
||||
return &controller.Controller{
|
||||
Do: options.Reconciler,
|
||||
MakeQueue: func() workqueue.RateLimitingInterface {
|
||||
return workqueue.NewRateLimitingQueueWithConfig(options.RateLimiter, workqueue.RateLimitingQueueConfig{
|
||||
Name: name,
|
||||
})
|
||||
},
|
||||
return &controller.Controller[request]{
|
||||
Do: options.Reconciler,
|
||||
RateLimiter: options.RateLimiter,
|
||||
NewQueue: options.NewQueue,
|
||||
MaxConcurrentReconciles: options.MaxConcurrentReconciles,
|
||||
CacheSyncTimeout: options.CacheSyncTimeout,
|
||||
Name: name,
|
||||
|
||||
19
vendor/sigs.k8s.io/controller-runtime/pkg/controller/controllertest/testing.go
generated
vendored
19
vendor/sigs.k8s.io/controller-runtime/pkg/controller/controllertest/testing.go
generated
vendored
@@ -23,6 +23,7 @@ import (
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/client-go/util/workqueue"
|
||||
"sigs.k8s.io/controller-runtime/pkg/reconcile"
|
||||
)
|
||||
|
||||
var _ runtime.Object = &ErrorType{}
|
||||
@@ -36,23 +37,27 @@ func (ErrorType) GetObjectKind() schema.ObjectKind { return nil }
|
||||
// DeepCopyObject implements runtime.Object.
|
||||
func (ErrorType) DeepCopyObject() runtime.Object { return nil }
|
||||
|
||||
var _ workqueue.RateLimitingInterface = &Queue{}
|
||||
var _ workqueue.TypedRateLimitingInterface[reconcile.Request] = &Queue{}
|
||||
|
||||
// Queue implements a RateLimiting queue as a non-ratelimited queue for testing.
|
||||
// This helps testing by having functions that use a RateLimiting queue synchronously add items to the queue.
|
||||
type Queue struct {
|
||||
workqueue.Interface
|
||||
type Queue = TypedQueue[reconcile.Request]
|
||||
|
||||
// TypedQueue implements a RateLimiting queue as a non-ratelimited queue for testing.
|
||||
// This helps testing by having functions that use a RateLimiting queue synchronously add items to the queue.
|
||||
type TypedQueue[request comparable] struct {
|
||||
workqueue.TypedInterface[request]
|
||||
AddedRateLimitedLock sync.Mutex
|
||||
AddedRatelimited []any
|
||||
}
|
||||
|
||||
// AddAfter implements RateLimitingInterface.
|
||||
func (q *Queue) AddAfter(item interface{}, duration time.Duration) {
|
||||
func (q *TypedQueue[request]) AddAfter(item request, duration time.Duration) {
|
||||
q.Add(item)
|
||||
}
|
||||
|
||||
// AddRateLimited implements RateLimitingInterface. TODO(community): Implement this.
|
||||
func (q *Queue) AddRateLimited(item interface{}) {
|
||||
func (q *TypedQueue[request]) AddRateLimited(item request) {
|
||||
q.AddedRateLimitedLock.Lock()
|
||||
q.AddedRatelimited = append(q.AddedRatelimited, item)
|
||||
q.AddedRateLimitedLock.Unlock()
|
||||
@@ -60,9 +65,9 @@ func (q *Queue) AddRateLimited(item interface{}) {
|
||||
}
|
||||
|
||||
// Forget implements RateLimitingInterface. TODO(community): Implement this.
|
||||
func (q *Queue) Forget(item interface{}) {}
|
||||
func (q *TypedQueue[request]) Forget(item request) {}
|
||||
|
||||
// NumRequeues implements RateLimitingInterface. TODO(community): Implement this.
|
||||
func (q *Queue) NumRequeues(item interface{}) int {
|
||||
func (q *TypedQueue[request]) NumRequeues(item request) int {
|
||||
return 0
|
||||
}
|
||||
|
||||
20
vendor/sigs.k8s.io/controller-runtime/pkg/controller/controllerutil/controllerutil.go
generated
vendored
20
vendor/sigs.k8s.io/controller-runtime/pkg/controller/controllerutil/controllerutil.go
generated
vendored
@@ -52,12 +52,22 @@ func newAlreadyOwnedError(obj metav1.Object, owner metav1.OwnerReference) *Alrea
|
||||
}
|
||||
}
|
||||
|
||||
// OwnerReferenceOption is a function that can modify a `metav1.OwnerReference`.
|
||||
type OwnerReferenceOption func(*metav1.OwnerReference)
|
||||
|
||||
// WithBlockOwnerDeletion allows configuring the BlockOwnerDeletion field on the `metav1.OwnerReference`.
|
||||
func WithBlockOwnerDeletion(blockOwnerDeletion bool) OwnerReferenceOption {
|
||||
return func(ref *metav1.OwnerReference) {
|
||||
ref.BlockOwnerDeletion = &blockOwnerDeletion
|
||||
}
|
||||
}
|
||||
|
||||
// SetControllerReference sets owner as a Controller OwnerReference on controlled.
|
||||
// This is used for garbage collection of the controlled object and for
|
||||
// reconciling the owner object on changes to controlled (with a Watch + EnqueueRequestForOwner).
|
||||
// Since only one OwnerReference can be a controller, it returns an error if
|
||||
// there is another OwnerReference with Controller flag set.
|
||||
func SetControllerReference(owner, controlled metav1.Object, scheme *runtime.Scheme) error {
|
||||
func SetControllerReference(owner, controlled metav1.Object, scheme *runtime.Scheme, opts ...OwnerReferenceOption) error {
|
||||
// Validate the owner.
|
||||
ro, ok := owner.(runtime.Object)
|
||||
if !ok {
|
||||
@@ -80,6 +90,9 @@ func SetControllerReference(owner, controlled metav1.Object, scheme *runtime.Sch
|
||||
BlockOwnerDeletion: ptr.To(true),
|
||||
Controller: ptr.To(true),
|
||||
}
|
||||
for _, opt := range opts {
|
||||
opt(&ref)
|
||||
}
|
||||
|
||||
// Return early with an error if the object is already controlled.
|
||||
if existing := metav1.GetControllerOf(controlled); existing != nil && !referSameObject(*existing, ref) {
|
||||
@@ -94,7 +107,7 @@ func SetControllerReference(owner, controlled metav1.Object, scheme *runtime.Sch
|
||||
// SetOwnerReference is a helper method to make sure the given object contains an object reference to the object provided.
|
||||
// This allows you to declare that owner has a dependency on the object without specifying it as a controller.
|
||||
// If a reference to the same object already exists, it'll be overwritten with the newly provided version.
|
||||
func SetOwnerReference(owner, object metav1.Object, scheme *runtime.Scheme) error {
|
||||
func SetOwnerReference(owner, object metav1.Object, scheme *runtime.Scheme, opts ...OwnerReferenceOption) error {
|
||||
// Validate the owner.
|
||||
ro, ok := owner.(runtime.Object)
|
||||
if !ok {
|
||||
@@ -115,6 +128,9 @@ func SetOwnerReference(owner, object metav1.Object, scheme *runtime.Scheme) erro
|
||||
UID: owner.GetUID(),
|
||||
Name: owner.GetName(),
|
||||
}
|
||||
for _, opt := range opts {
|
||||
opt(&ref)
|
||||
}
|
||||
|
||||
// Update owner references and return.
|
||||
upsertOwnerRef(ref, object)
|
||||
|
||||
@@ -14,9 +14,30 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
/*
|
||||
Package ratelimiter defines rate limiters used by Controllers to limit how frequently requests may be queued.
|
||||
package controller
|
||||
|
||||
Typical rate limiters that can be used are implemented in client-go's workqueue package.
|
||||
*/
|
||||
package ratelimiter
|
||||
import (
|
||||
"fmt"
|
||||
"sync"
|
||||
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
)
|
||||
|
||||
var nameLock sync.Mutex
|
||||
var usedNames sets.Set[string]
|
||||
|
||||
func checkName(name string) error {
|
||||
nameLock.Lock()
|
||||
defer nameLock.Unlock()
|
||||
if usedNames == nil {
|
||||
usedNames = sets.Set[string]{}
|
||||
}
|
||||
|
||||
if usedNames.Has(name) {
|
||||
return fmt.Errorf("controller with name %s already exists. Controller names must be unique to avoid multiple controllers reporting to the same metric", name)
|
||||
}
|
||||
|
||||
usedNames.Insert(name)
|
||||
|
||||
return nil
|
||||
}
|
||||
25
vendor/sigs.k8s.io/controller-runtime/pkg/envtest/server.go
generated
vendored
25
vendor/sigs.k8s.io/controller-runtime/pkg/envtest/server.go
generated
vendored
@@ -17,15 +17,20 @@ limitations under the License.
|
||||
package envtest
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
"k8s.io/client-go/kubernetes/scheme"
|
||||
"k8s.io/client-go/rest"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
"sigs.k8s.io/controller-runtime/pkg/client/config"
|
||||
logf "sigs.k8s.io/controller-runtime/pkg/internal/log"
|
||||
@@ -265,6 +270,12 @@ func (te *Environment) Start() (*rest.Config, error) {
|
||||
te.Scheme = scheme.Scheme
|
||||
}
|
||||
|
||||
// If we are bringing etcd up for the first time, it can take some time for the
|
||||
// default namespace to actually be created and seen as available to the apiserver
|
||||
if err := te.waitForDefaultNamespace(te.Config); err != nil {
|
||||
return nil, fmt.Errorf("default namespace didn't register within deadline: %w", err)
|
||||
}
|
||||
|
||||
// Call PrepWithoutInstalling to setup certificates first
|
||||
// and have them available to patch CRD conversion webhook as well.
|
||||
if err := te.WebhookInstallOptions.PrepWithoutInstalling(); err != nil {
|
||||
@@ -322,6 +333,20 @@ func (te *Environment) startControlPlane() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (te *Environment) waitForDefaultNamespace(config *rest.Config) error {
|
||||
cs, err := client.New(config, client.Options{})
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to create client: %w", err)
|
||||
}
|
||||
// It shouldn't take longer than 5s for the default namespace to be brought up in etcd
|
||||
return wait.PollUntilContextTimeout(context.TODO(), time.Millisecond*50, time.Second*5, true, func(ctx context.Context) (bool, error) {
|
||||
if err = cs.Get(ctx, types.NamespacedName{Name: "default"}, &corev1.Namespace{}); err != nil {
|
||||
return false, nil //nolint:nilerr
|
||||
}
|
||||
return true, nil
|
||||
})
|
||||
}
|
||||
|
||||
func (te *Environment) defaultTimeouts() error {
|
||||
var err error
|
||||
if te.ControlPlaneStartTimeout == 0 {
|
||||
|
||||
51
vendor/sigs.k8s.io/controller-runtime/pkg/event/event.go
generated
vendored
51
vendor/sigs.k8s.io/controller-runtime/pkg/event/event.go
generated
vendored
@@ -18,38 +18,55 @@ package event
|
||||
|
||||
import "sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
// CreateEvent is an event where a Kubernetes object was created. CreateEvent should be generated
|
||||
// CreateEvent is an event where a Kubernetes object was created. CreateEvent should be generated
|
||||
// by a source.Source and transformed into a reconcile.Request by a handler.EventHandler.
|
||||
type CreateEvent = TypedCreateEvent[client.Object]
|
||||
|
||||
// UpdateEvent is an event where a Kubernetes object was updated. UpdateEvent should be generated
|
||||
// by a source.Source and transformed into a reconcile.Request by an handler.EventHandler.
|
||||
type CreateEvent struct {
|
||||
type UpdateEvent = TypedUpdateEvent[client.Object]
|
||||
|
||||
// DeleteEvent is an event where a Kubernetes object was deleted. DeleteEvent should be generated
|
||||
// by a source.Source and transformed into a reconcile.Request by an handler.EventHandler.
|
||||
type DeleteEvent = TypedDeleteEvent[client.Object]
|
||||
|
||||
// GenericEvent is an event where the operation type is unknown (e.g. polling or event originating outside the cluster).
|
||||
// GenericEvent should be generated by a source.Source and transformed into a reconcile.Request by an
|
||||
// handler.EventHandler.
|
||||
type GenericEvent = TypedGenericEvent[client.Object]
|
||||
|
||||
// TypedCreateEvent is an event where a Kubernetes object was created. TypedCreateEvent should be generated
|
||||
// by a source.Source and transformed into a reconcile.Request by an handler.TypedEventHandler.
|
||||
type TypedCreateEvent[object any] struct {
|
||||
// Object is the object from the event
|
||||
Object client.Object
|
||||
Object object
|
||||
}
|
||||
|
||||
// UpdateEvent is an event where a Kubernetes object was updated. UpdateEvent should be generated
|
||||
// by a source.Source and transformed into a reconcile.Request by an handler.EventHandler.
|
||||
type UpdateEvent struct {
|
||||
// TypedUpdateEvent is an event where a Kubernetes object was updated. TypedUpdateEvent should be generated
|
||||
// by a source.Source and transformed into a reconcile.Request by an handler.TypedEventHandler.
|
||||
type TypedUpdateEvent[object any] struct {
|
||||
// ObjectOld is the object from the event
|
||||
ObjectOld client.Object
|
||||
ObjectOld object
|
||||
|
||||
// ObjectNew is the object from the event
|
||||
ObjectNew client.Object
|
||||
ObjectNew object
|
||||
}
|
||||
|
||||
// DeleteEvent is an event where a Kubernetes object was deleted. DeleteEvent should be generated
|
||||
// by a source.Source and transformed into a reconcile.Request by an handler.EventHandler.
|
||||
type DeleteEvent struct {
|
||||
// TypedDeleteEvent is an event where a Kubernetes object was deleted. TypedDeleteEvent should be generated
|
||||
// by a source.Source and transformed into a reconcile.Request by an handler.TypedEventHandler.
|
||||
type TypedDeleteEvent[object any] struct {
|
||||
// Object is the object from the event
|
||||
Object client.Object
|
||||
Object object
|
||||
|
||||
// DeleteStateUnknown is true if the Delete event was missed but we identified the object
|
||||
// as having been deleted.
|
||||
DeleteStateUnknown bool
|
||||
}
|
||||
|
||||
// GenericEvent is an event where the operation type is unknown (e.g. polling or event originating outside the cluster).
|
||||
// GenericEvent should be generated by a source.Source and transformed into a reconcile.Request by an
|
||||
// handler.EventHandler.
|
||||
type GenericEvent struct {
|
||||
// TypedGenericEvent is an event where the operation type is unknown (e.g. polling or event originating outside the cluster).
|
||||
// TypedGenericEvent should be generated by a source.Source and transformed into a reconcile.Request by an
|
||||
// handler.TypedEventHandler.
|
||||
type TypedGenericEvent[object any] struct {
|
||||
// Object is the object from the event
|
||||
Object client.Object
|
||||
Object object
|
||||
}
|
||||
|
||||
43
vendor/sigs.k8s.io/controller-runtime/pkg/handler/enqueue.go
generated
vendored
43
vendor/sigs.k8s.io/controller-runtime/pkg/handler/enqueue.go
generated
vendored
@@ -18,9 +18,11 @@ package handler
|
||||
|
||||
import (
|
||||
"context"
|
||||
"reflect"
|
||||
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/client-go/util/workqueue"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
"sigs.k8s.io/controller-runtime/pkg/event"
|
||||
logf "sigs.k8s.io/controller-runtime/pkg/internal/log"
|
||||
"sigs.k8s.io/controller-runtime/pkg/reconcile"
|
||||
@@ -33,13 +35,20 @@ type empty struct{}
|
||||
var _ EventHandler = &EnqueueRequestForObject{}
|
||||
|
||||
// EnqueueRequestForObject enqueues a Request containing the Name and Namespace of the object that is the source of the Event.
|
||||
// (e.g. the created / deleted / updated objects Name and Namespace). handler.EnqueueRequestForObject is used by almost all
|
||||
// (e.g. the created / deleted / updated objects Name and Namespace). handler.EnqueueRequestForObject is used by almost all
|
||||
// Controllers that have associated Resources (e.g. CRDs) to reconcile the associated Resource.
|
||||
type EnqueueRequestForObject struct{}
|
||||
type EnqueueRequestForObject = TypedEnqueueRequestForObject[client.Object]
|
||||
|
||||
// TypedEnqueueRequestForObject enqueues a Request containing the Name and Namespace of the object that is the source of the Event.
|
||||
// (e.g. the created / deleted / updated objects Name and Namespace). handler.TypedEnqueueRequestForObject is used by almost all
|
||||
// Controllers that have associated Resources (e.g. CRDs) to reconcile the associated Resource.
|
||||
//
|
||||
// TypedEnqueueRequestForObject is experimental and subject to future change.
|
||||
type TypedEnqueueRequestForObject[object client.Object] struct{}
|
||||
|
||||
// Create implements EventHandler.
|
||||
func (e *EnqueueRequestForObject) Create(ctx context.Context, evt event.CreateEvent, q workqueue.RateLimitingInterface) {
|
||||
if evt.Object == nil {
|
||||
func (e *TypedEnqueueRequestForObject[T]) Create(ctx context.Context, evt event.TypedCreateEvent[T], q workqueue.TypedRateLimitingInterface[reconcile.Request]) {
|
||||
if isNil(evt.Object) {
|
||||
enqueueLog.Error(nil, "CreateEvent received with no metadata", "event", evt)
|
||||
return
|
||||
}
|
||||
@@ -50,14 +59,14 @@ func (e *EnqueueRequestForObject) Create(ctx context.Context, evt event.CreateEv
|
||||
}
|
||||
|
||||
// Update implements EventHandler.
|
||||
func (e *EnqueueRequestForObject) Update(ctx context.Context, evt event.UpdateEvent, q workqueue.RateLimitingInterface) {
|
||||
func (e *TypedEnqueueRequestForObject[T]) Update(ctx context.Context, evt event.TypedUpdateEvent[T], q workqueue.TypedRateLimitingInterface[reconcile.Request]) {
|
||||
switch {
|
||||
case evt.ObjectNew != nil:
|
||||
case !isNil(evt.ObjectNew):
|
||||
q.Add(reconcile.Request{NamespacedName: types.NamespacedName{
|
||||
Name: evt.ObjectNew.GetName(),
|
||||
Namespace: evt.ObjectNew.GetNamespace(),
|
||||
}})
|
||||
case evt.ObjectOld != nil:
|
||||
case !isNil(evt.ObjectOld):
|
||||
q.Add(reconcile.Request{NamespacedName: types.NamespacedName{
|
||||
Name: evt.ObjectOld.GetName(),
|
||||
Namespace: evt.ObjectOld.GetNamespace(),
|
||||
@@ -68,8 +77,8 @@ func (e *EnqueueRequestForObject) Update(ctx context.Context, evt event.UpdateEv
|
||||
}
|
||||
|
||||
// Delete implements EventHandler.
|
||||
func (e *EnqueueRequestForObject) Delete(ctx context.Context, evt event.DeleteEvent, q workqueue.RateLimitingInterface) {
|
||||
if evt.Object == nil {
|
||||
func (e *TypedEnqueueRequestForObject[T]) Delete(ctx context.Context, evt event.TypedDeleteEvent[T], q workqueue.TypedRateLimitingInterface[reconcile.Request]) {
|
||||
if isNil(evt.Object) {
|
||||
enqueueLog.Error(nil, "DeleteEvent received with no metadata", "event", evt)
|
||||
return
|
||||
}
|
||||
@@ -80,8 +89,8 @@ func (e *EnqueueRequestForObject) Delete(ctx context.Context, evt event.DeleteEv
|
||||
}
|
||||
|
||||
// Generic implements EventHandler.
|
||||
func (e *EnqueueRequestForObject) Generic(ctx context.Context, evt event.GenericEvent, q workqueue.RateLimitingInterface) {
|
||||
if evt.Object == nil {
|
||||
func (e *TypedEnqueueRequestForObject[T]) Generic(ctx context.Context, evt event.TypedGenericEvent[T], q workqueue.TypedRateLimitingInterface[reconcile.Request]) {
|
||||
if isNil(evt.Object) {
|
||||
enqueueLog.Error(nil, "GenericEvent received with no metadata", "event", evt)
|
||||
return
|
||||
}
|
||||
@@ -90,3 +99,15 @@ func (e *EnqueueRequestForObject) Generic(ctx context.Context, evt event.Generic
|
||||
Namespace: evt.Object.GetNamespace(),
|
||||
}})
|
||||
}
|
||||
|
||||
func isNil(arg any) bool {
|
||||
if v := reflect.ValueOf(arg); !v.IsValid() || ((v.Kind() == reflect.Ptr ||
|
||||
v.Kind() == reflect.Interface ||
|
||||
v.Kind() == reflect.Slice ||
|
||||
v.Kind() == reflect.Map ||
|
||||
v.Kind() == reflect.Chan ||
|
||||
v.Kind() == reflect.Func) && v.IsNil()) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
68
vendor/sigs.k8s.io/controller-runtime/pkg/handler/enqueue_mapped.go
generated
vendored
68
vendor/sigs.k8s.io/controller-runtime/pkg/handler/enqueue_mapped.go
generated
vendored
@@ -27,7 +27,13 @@ import (
|
||||
|
||||
// MapFunc is the signature required for enqueueing requests from a generic function.
|
||||
// This type is usually used with EnqueueRequestsFromMapFunc when registering an event handler.
|
||||
type MapFunc func(context.Context, client.Object) []reconcile.Request
|
||||
type MapFunc = TypedMapFunc[client.Object, reconcile.Request]
|
||||
|
||||
// TypedMapFunc is the signature required for enqueueing requests from a generic function.
|
||||
// This type is usually used with EnqueueRequestsFromTypedMapFunc when registering an event handler.
|
||||
//
|
||||
// TypedMapFunc is experimental and subject to future change.
|
||||
type TypedMapFunc[object any, request comparable] func(context.Context, object) []request
|
||||
|
||||
// EnqueueRequestsFromMapFunc enqueues Requests by running a transformation function that outputs a collection
|
||||
// of reconcile.Requests on each Event. The reconcile.Requests may be for an arbitrary set of objects
|
||||
@@ -40,45 +46,77 @@ type MapFunc func(context.Context, client.Object) []reconcile.Request
|
||||
// For UpdateEvents which contain both a new and old object, the transformation function is run on both
|
||||
// objects and both sets of Requests are enqueue.
|
||||
func EnqueueRequestsFromMapFunc(fn MapFunc) EventHandler {
|
||||
return &enqueueRequestsFromMapFunc{
|
||||
return TypedEnqueueRequestsFromMapFunc(fn)
|
||||
}
|
||||
|
||||
// TypedEnqueueRequestsFromMapFunc enqueues Requests by running a transformation function that outputs a collection
|
||||
// of reconcile.Requests on each Event. The reconcile.Requests may be for an arbitrary set of objects
|
||||
// defined by some user specified transformation of the source Event. (e.g. trigger Reconciler for a set of objects
|
||||
// in response to a cluster resize event caused by adding or deleting a Node)
|
||||
//
|
||||
// TypedEnqueueRequestsFromMapFunc is frequently used to fan-out updates from one object to one or more other
|
||||
// objects of a differing type.
|
||||
//
|
||||
// For TypedUpdateEvents which contain both a new and old object, the transformation function is run on both
|
||||
// objects and both sets of Requests are enqueue.
|
||||
//
|
||||
// TypedEnqueueRequestsFromMapFunc is experimental and subject to future change.
|
||||
func TypedEnqueueRequestsFromMapFunc[object any, request comparable](fn TypedMapFunc[object, request]) TypedEventHandler[object, request] {
|
||||
return &enqueueRequestsFromMapFunc[object, request]{
|
||||
toRequests: fn,
|
||||
}
|
||||
}
|
||||
|
||||
var _ EventHandler = &enqueueRequestsFromMapFunc{}
|
||||
var _ EventHandler = &enqueueRequestsFromMapFunc[client.Object, reconcile.Request]{}
|
||||
|
||||
type enqueueRequestsFromMapFunc struct {
|
||||
type enqueueRequestsFromMapFunc[object any, request comparable] struct {
|
||||
// Mapper transforms the argument into a slice of keys to be reconciled
|
||||
toRequests MapFunc
|
||||
toRequests TypedMapFunc[object, request]
|
||||
}
|
||||
|
||||
// Create implements EventHandler.
|
||||
func (e *enqueueRequestsFromMapFunc) Create(ctx context.Context, evt event.CreateEvent, q workqueue.RateLimitingInterface) {
|
||||
reqs := map[reconcile.Request]empty{}
|
||||
func (e *enqueueRequestsFromMapFunc[object, request]) Create(
|
||||
ctx context.Context,
|
||||
evt event.TypedCreateEvent[object],
|
||||
q workqueue.TypedRateLimitingInterface[request],
|
||||
) {
|
||||
reqs := map[request]empty{}
|
||||
e.mapAndEnqueue(ctx, q, evt.Object, reqs)
|
||||
}
|
||||
|
||||
// Update implements EventHandler.
|
||||
func (e *enqueueRequestsFromMapFunc) Update(ctx context.Context, evt event.UpdateEvent, q workqueue.RateLimitingInterface) {
|
||||
reqs := map[reconcile.Request]empty{}
|
||||
func (e *enqueueRequestsFromMapFunc[object, request]) Update(
|
||||
ctx context.Context,
|
||||
evt event.TypedUpdateEvent[object],
|
||||
q workqueue.TypedRateLimitingInterface[request],
|
||||
) {
|
||||
reqs := map[request]empty{}
|
||||
e.mapAndEnqueue(ctx, q, evt.ObjectOld, reqs)
|
||||
e.mapAndEnqueue(ctx, q, evt.ObjectNew, reqs)
|
||||
}
|
||||
|
||||
// Delete implements EventHandler.
|
||||
func (e *enqueueRequestsFromMapFunc) Delete(ctx context.Context, evt event.DeleteEvent, q workqueue.RateLimitingInterface) {
|
||||
reqs := map[reconcile.Request]empty{}
|
||||
func (e *enqueueRequestsFromMapFunc[object, request]) Delete(
|
||||
ctx context.Context,
|
||||
evt event.TypedDeleteEvent[object],
|
||||
q workqueue.TypedRateLimitingInterface[request],
|
||||
) {
|
||||
reqs := map[request]empty{}
|
||||
e.mapAndEnqueue(ctx, q, evt.Object, reqs)
|
||||
}
|
||||
|
||||
// Generic implements EventHandler.
|
||||
func (e *enqueueRequestsFromMapFunc) Generic(ctx context.Context, evt event.GenericEvent, q workqueue.RateLimitingInterface) {
|
||||
reqs := map[reconcile.Request]empty{}
|
||||
func (e *enqueueRequestsFromMapFunc[object, request]) Generic(
|
||||
ctx context.Context,
|
||||
evt event.TypedGenericEvent[object],
|
||||
q workqueue.TypedRateLimitingInterface[request],
|
||||
) {
|
||||
reqs := map[request]empty{}
|
||||
e.mapAndEnqueue(ctx, q, evt.Object, reqs)
|
||||
}
|
||||
|
||||
func (e *enqueueRequestsFromMapFunc) mapAndEnqueue(ctx context.Context, q workqueue.RateLimitingInterface, object client.Object, reqs map[reconcile.Request]empty) {
|
||||
for _, req := range e.toRequests(ctx, object) {
|
||||
func (e *enqueueRequestsFromMapFunc[object, request]) mapAndEnqueue(ctx context.Context, q workqueue.TypedRateLimitingInterface[request], o object, reqs map[request]empty) {
|
||||
for _, req := range e.toRequests(ctx, o) {
|
||||
_, ok := reqs[req]
|
||||
if !ok {
|
||||
q.Add(req)
|
||||
|
||||
58
vendor/sigs.k8s.io/controller-runtime/pkg/handler/enqueue_owner.go
generated
vendored
58
vendor/sigs.k8s.io/controller-runtime/pkg/handler/enqueue_owner.go
generated
vendored
@@ -32,12 +32,12 @@ import (
|
||||
"sigs.k8s.io/controller-runtime/pkg/reconcile"
|
||||
)
|
||||
|
||||
var _ EventHandler = &enqueueRequestForOwner{}
|
||||
var _ EventHandler = &enqueueRequestForOwner[client.Object]{}
|
||||
|
||||
var log = logf.RuntimeLog.WithName("eventhandler").WithName("enqueueRequestForOwner")
|
||||
|
||||
// OwnerOption modifies an EnqueueRequestForOwner EventHandler.
|
||||
type OwnerOption func(e *enqueueRequestForOwner)
|
||||
type OwnerOption func(e enqueueRequestForOwnerInterface)
|
||||
|
||||
// EnqueueRequestForOwner enqueues Requests for the Owners of an object. E.g. the object that created
|
||||
// the object that was the source of the Event.
|
||||
@@ -48,7 +48,21 @@ type OwnerOption func(e *enqueueRequestForOwner)
|
||||
//
|
||||
// - a handler.enqueueRequestForOwner EventHandler with an OwnerType of ReplicaSet and OnlyControllerOwner set to true.
|
||||
func EnqueueRequestForOwner(scheme *runtime.Scheme, mapper meta.RESTMapper, ownerType client.Object, opts ...OwnerOption) EventHandler {
|
||||
e := &enqueueRequestForOwner{
|
||||
return TypedEnqueueRequestForOwner[client.Object](scheme, mapper, ownerType, opts...)
|
||||
}
|
||||
|
||||
// TypedEnqueueRequestForOwner enqueues Requests for the Owners of an object. E.g. the object that created
|
||||
// the object that was the source of the Event.
|
||||
//
|
||||
// If a ReplicaSet creates Pods, users may reconcile the ReplicaSet in response to Pod Events using:
|
||||
//
|
||||
// - a source.Kind Source with Type of Pod.
|
||||
//
|
||||
// - a handler.typedEnqueueRequestForOwner EventHandler with an OwnerType of ReplicaSet and OnlyControllerOwner set to true.
|
||||
//
|
||||
// TypedEnqueueRequestForOwner is experimental and subject to future change.
|
||||
func TypedEnqueueRequestForOwner[object client.Object](scheme *runtime.Scheme, mapper meta.RESTMapper, ownerType client.Object, opts ...OwnerOption) TypedEventHandler[object, reconcile.Request] {
|
||||
e := &enqueueRequestForOwner[object]{
|
||||
ownerType: ownerType,
|
||||
mapper: mapper,
|
||||
}
|
||||
@@ -63,12 +77,16 @@ func EnqueueRequestForOwner(scheme *runtime.Scheme, mapper meta.RESTMapper, owne
|
||||
|
||||
// OnlyControllerOwner if provided will only look at the first OwnerReference with Controller: true.
|
||||
func OnlyControllerOwner() OwnerOption {
|
||||
return func(e *enqueueRequestForOwner) {
|
||||
e.isController = true
|
||||
return func(e enqueueRequestForOwnerInterface) {
|
||||
e.setIsController(true)
|
||||
}
|
||||
}
|
||||
|
||||
type enqueueRequestForOwner struct {
|
||||
type enqueueRequestForOwnerInterface interface {
|
||||
setIsController(bool)
|
||||
}
|
||||
|
||||
type enqueueRequestForOwner[object client.Object] struct {
|
||||
// ownerType is the type of the Owner object to look for in OwnerReferences. Only Group and Kind are compared.
|
||||
ownerType runtime.Object
|
||||
|
||||
@@ -82,8 +100,12 @@ type enqueueRequestForOwner struct {
|
||||
mapper meta.RESTMapper
|
||||
}
|
||||
|
||||
func (e *enqueueRequestForOwner[object]) setIsController(isController bool) {
|
||||
e.isController = isController
|
||||
}
|
||||
|
||||
// Create implements EventHandler.
|
||||
func (e *enqueueRequestForOwner) Create(ctx context.Context, evt event.CreateEvent, q workqueue.RateLimitingInterface) {
|
||||
func (e *enqueueRequestForOwner[object]) Create(ctx context.Context, evt event.TypedCreateEvent[object], q workqueue.TypedRateLimitingInterface[reconcile.Request]) {
|
||||
reqs := map[reconcile.Request]empty{}
|
||||
e.getOwnerReconcileRequest(evt.Object, reqs)
|
||||
for req := range reqs {
|
||||
@@ -92,7 +114,7 @@ func (e *enqueueRequestForOwner) Create(ctx context.Context, evt event.CreateEve
|
||||
}
|
||||
|
||||
// Update implements EventHandler.
|
||||
func (e *enqueueRequestForOwner) Update(ctx context.Context, evt event.UpdateEvent, q workqueue.RateLimitingInterface) {
|
||||
func (e *enqueueRequestForOwner[object]) Update(ctx context.Context, evt event.TypedUpdateEvent[object], q workqueue.TypedRateLimitingInterface[reconcile.Request]) {
|
||||
reqs := map[reconcile.Request]empty{}
|
||||
e.getOwnerReconcileRequest(evt.ObjectOld, reqs)
|
||||
e.getOwnerReconcileRequest(evt.ObjectNew, reqs)
|
||||
@@ -102,7 +124,7 @@ func (e *enqueueRequestForOwner) Update(ctx context.Context, evt event.UpdateEve
|
||||
}
|
||||
|
||||
// Delete implements EventHandler.
|
||||
func (e *enqueueRequestForOwner) Delete(ctx context.Context, evt event.DeleteEvent, q workqueue.RateLimitingInterface) {
|
||||
func (e *enqueueRequestForOwner[object]) Delete(ctx context.Context, evt event.TypedDeleteEvent[object], q workqueue.TypedRateLimitingInterface[reconcile.Request]) {
|
||||
reqs := map[reconcile.Request]empty{}
|
||||
e.getOwnerReconcileRequest(evt.Object, reqs)
|
||||
for req := range reqs {
|
||||
@@ -111,7 +133,7 @@ func (e *enqueueRequestForOwner) Delete(ctx context.Context, evt event.DeleteEve
|
||||
}
|
||||
|
||||
// Generic implements EventHandler.
|
||||
func (e *enqueueRequestForOwner) Generic(ctx context.Context, evt event.GenericEvent, q workqueue.RateLimitingInterface) {
|
||||
func (e *enqueueRequestForOwner[object]) Generic(ctx context.Context, evt event.TypedGenericEvent[object], q workqueue.TypedRateLimitingInterface[reconcile.Request]) {
|
||||
reqs := map[reconcile.Request]empty{}
|
||||
e.getOwnerReconcileRequest(evt.Object, reqs)
|
||||
for req := range reqs {
|
||||
@@ -121,7 +143,7 @@ func (e *enqueueRequestForOwner) Generic(ctx context.Context, evt event.GenericE
|
||||
|
||||
// parseOwnerTypeGroupKind parses the OwnerType into a Group and Kind and caches the result. Returns false
|
||||
// if the OwnerType could not be parsed using the scheme.
|
||||
func (e *enqueueRequestForOwner) parseOwnerTypeGroupKind(scheme *runtime.Scheme) error {
|
||||
func (e *enqueueRequestForOwner[object]) parseOwnerTypeGroupKind(scheme *runtime.Scheme) error {
|
||||
// Get the kinds of the type
|
||||
kinds, _, err := scheme.ObjectKinds(e.ownerType)
|
||||
if err != nil {
|
||||
@@ -141,10 +163,10 @@ func (e *enqueueRequestForOwner) parseOwnerTypeGroupKind(scheme *runtime.Scheme)
|
||||
|
||||
// getOwnerReconcileRequest looks at object and builds a map of reconcile.Request to reconcile
|
||||
// owners of object that match e.OwnerType.
|
||||
func (e *enqueueRequestForOwner) getOwnerReconcileRequest(object metav1.Object, result map[reconcile.Request]empty) {
|
||||
func (e *enqueueRequestForOwner[object]) getOwnerReconcileRequest(obj metav1.Object, result map[reconcile.Request]empty) {
|
||||
// Iterate through the OwnerReferences looking for a match on Group and Kind against what was requested
|
||||
// by the user
|
||||
for _, ref := range e.getOwnersReferences(object) {
|
||||
for _, ref := range e.getOwnersReferences(obj) {
|
||||
// Parse the Group out of the OwnerReference to compare it to what was parsed out of the requested OwnerType
|
||||
refGV, err := schema.ParseGroupVersion(ref.APIVersion)
|
||||
if err != nil {
|
||||
@@ -170,7 +192,7 @@ func (e *enqueueRequestForOwner) getOwnerReconcileRequest(object metav1.Object,
|
||||
return
|
||||
}
|
||||
if mapping.Scope.Name() != meta.RESTScopeNameRoot {
|
||||
request.Namespace = object.GetNamespace()
|
||||
request.Namespace = obj.GetNamespace()
|
||||
}
|
||||
|
||||
result[request] = empty{}
|
||||
@@ -181,17 +203,17 @@ func (e *enqueueRequestForOwner) getOwnerReconcileRequest(object metav1.Object,
|
||||
// getOwnersReferences returns the OwnerReferences for an object as specified by the enqueueRequestForOwner
|
||||
// - if IsController is true: only take the Controller OwnerReference (if found)
|
||||
// - if IsController is false: take all OwnerReferences.
|
||||
func (e *enqueueRequestForOwner) getOwnersReferences(object metav1.Object) []metav1.OwnerReference {
|
||||
if object == nil {
|
||||
func (e *enqueueRequestForOwner[object]) getOwnersReferences(obj metav1.Object) []metav1.OwnerReference {
|
||||
if obj == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
// If not filtered as Controller only, then use all the OwnerReferences
|
||||
if !e.isController {
|
||||
return object.GetOwnerReferences()
|
||||
return obj.GetOwnerReferences()
|
||||
}
|
||||
// If filtered to a Controller, only take the Controller OwnerReference
|
||||
if ownerRef := metav1.GetControllerOf(object); ownerRef != nil {
|
||||
if ownerRef := metav1.GetControllerOf(obj); ownerRef != nil {
|
||||
return []metav1.OwnerReference{*ownerRef}
|
||||
}
|
||||
// No Controller OwnerReference found
|
||||
|
||||
61
vendor/sigs.k8s.io/controller-runtime/pkg/handler/eventhandler.go
generated
vendored
61
vendor/sigs.k8s.io/controller-runtime/pkg/handler/eventhandler.go
generated
vendored
@@ -20,12 +20,14 @@ import (
|
||||
"context"
|
||||
|
||||
"k8s.io/client-go/util/workqueue"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
"sigs.k8s.io/controller-runtime/pkg/event"
|
||||
"sigs.k8s.io/controller-runtime/pkg/reconcile"
|
||||
)
|
||||
|
||||
// EventHandler enqueues reconcile.Requests in response to events (e.g. Pod Create). EventHandlers map an Event
|
||||
// for one object to trigger Reconciles for either the same object or different objects - e.g. if there is an
|
||||
// Event for object with type Foo (using source.KindSource) then reconcile one or more object(s) with type Bar.
|
||||
// Event for object with type Foo (using source.Kind) then reconcile one or more object(s) with type Bar.
|
||||
//
|
||||
// Identical reconcile.Requests will be batched together through the queuing mechanism before reconcile is called.
|
||||
//
|
||||
@@ -41,65 +43,92 @@ import (
|
||||
//
|
||||
// Unless you are implementing your own EventHandler, you can ignore the functions on the EventHandler interface.
|
||||
// Most users shouldn't need to implement their own EventHandler.
|
||||
type EventHandler interface {
|
||||
type EventHandler = TypedEventHandler[client.Object, reconcile.Request]
|
||||
|
||||
// TypedEventHandler enqueues reconcile.Requests in response to events (e.g. Pod Create). TypedEventHandlers map an Event
|
||||
// for one object to trigger Reconciles for either the same object or different objects - e.g. if there is an
|
||||
// Event for object with type Foo (using source.Kind) then reconcile one or more object(s) with type Bar.
|
||||
//
|
||||
// Identical reconcile.Requests will be batched together through the queuing mechanism before reconcile is called.
|
||||
//
|
||||
// * Use TypedEnqueueRequestForObject to reconcile the object the event is for
|
||||
// - do this for events for the type the Controller Reconciles. (e.g. Deployment for a Deployment Controller)
|
||||
//
|
||||
// * Use TypedEnqueueRequestForOwner to reconcile the owner of the object the event is for
|
||||
// - do this for events for the types the Controller creates. (e.g. ReplicaSets created by a Deployment Controller)
|
||||
//
|
||||
// * Use TypedEnqueueRequestsFromMapFunc to transform an event for an object to a reconcile of an object
|
||||
// of a different type - do this for events for types the Controller may be interested in, but doesn't create.
|
||||
// (e.g. If Foo responds to cluster size events, map Node events to Foo objects.)
|
||||
//
|
||||
// Unless you are implementing your own TypedEventHandler, you can ignore the functions on the TypedEventHandler interface.
|
||||
// Most users shouldn't need to implement their own TypedEventHandler.
|
||||
//
|
||||
// TypedEventHandler is experimental and subject to future change.
|
||||
type TypedEventHandler[object any, request comparable] interface {
|
||||
// Create is called in response to a create event - e.g. Pod Creation.
|
||||
Create(context.Context, event.CreateEvent, workqueue.RateLimitingInterface)
|
||||
Create(context.Context, event.TypedCreateEvent[object], workqueue.TypedRateLimitingInterface[request])
|
||||
|
||||
// Update is called in response to an update event - e.g. Pod Updated.
|
||||
Update(context.Context, event.UpdateEvent, workqueue.RateLimitingInterface)
|
||||
Update(context.Context, event.TypedUpdateEvent[object], workqueue.TypedRateLimitingInterface[request])
|
||||
|
||||
// Delete is called in response to a delete event - e.g. Pod Deleted.
|
||||
Delete(context.Context, event.DeleteEvent, workqueue.RateLimitingInterface)
|
||||
Delete(context.Context, event.TypedDeleteEvent[object], workqueue.TypedRateLimitingInterface[request])
|
||||
|
||||
// Generic is called in response to an event of an unknown type or a synthetic event triggered as a cron or
|
||||
// external trigger request - e.g. reconcile Autoscaling, or a Webhook.
|
||||
Generic(context.Context, event.GenericEvent, workqueue.RateLimitingInterface)
|
||||
Generic(context.Context, event.TypedGenericEvent[object], workqueue.TypedRateLimitingInterface[request])
|
||||
}
|
||||
|
||||
var _ EventHandler = Funcs{}
|
||||
|
||||
// Funcs implements EventHandler.
|
||||
type Funcs struct {
|
||||
// Funcs implements eventhandler.
|
||||
type Funcs = TypedFuncs[client.Object, reconcile.Request]
|
||||
|
||||
// TypedFuncs implements eventhandler.
|
||||
//
|
||||
// TypedFuncs is experimental and subject to future change.
|
||||
type TypedFuncs[object any, request comparable] struct {
|
||||
// Create is called in response to an add event. Defaults to no-op.
|
||||
// RateLimitingInterface is used to enqueue reconcile.Requests.
|
||||
CreateFunc func(context.Context, event.CreateEvent, workqueue.RateLimitingInterface)
|
||||
CreateFunc func(context.Context, event.TypedCreateEvent[object], workqueue.TypedRateLimitingInterface[request])
|
||||
|
||||
// Update is called in response to an update event. Defaults to no-op.
|
||||
// RateLimitingInterface is used to enqueue reconcile.Requests.
|
||||
UpdateFunc func(context.Context, event.UpdateEvent, workqueue.RateLimitingInterface)
|
||||
UpdateFunc func(context.Context, event.TypedUpdateEvent[object], workqueue.TypedRateLimitingInterface[request])
|
||||
|
||||
// Delete is called in response to a delete event. Defaults to no-op.
|
||||
// RateLimitingInterface is used to enqueue reconcile.Requests.
|
||||
DeleteFunc func(context.Context, event.DeleteEvent, workqueue.RateLimitingInterface)
|
||||
DeleteFunc func(context.Context, event.TypedDeleteEvent[object], workqueue.TypedRateLimitingInterface[request])
|
||||
|
||||
// GenericFunc is called in response to a generic event. Defaults to no-op.
|
||||
// RateLimitingInterface is used to enqueue reconcile.Requests.
|
||||
GenericFunc func(context.Context, event.GenericEvent, workqueue.RateLimitingInterface)
|
||||
GenericFunc func(context.Context, event.TypedGenericEvent[object], workqueue.TypedRateLimitingInterface[request])
|
||||
}
|
||||
|
||||
// Create implements EventHandler.
|
||||
func (h Funcs) Create(ctx context.Context, e event.CreateEvent, q workqueue.RateLimitingInterface) {
|
||||
func (h TypedFuncs[object, request]) Create(ctx context.Context, e event.TypedCreateEvent[object], q workqueue.TypedRateLimitingInterface[request]) {
|
||||
if h.CreateFunc != nil {
|
||||
h.CreateFunc(ctx, e, q)
|
||||
}
|
||||
}
|
||||
|
||||
// Delete implements EventHandler.
|
||||
func (h Funcs) Delete(ctx context.Context, e event.DeleteEvent, q workqueue.RateLimitingInterface) {
|
||||
func (h TypedFuncs[object, request]) Delete(ctx context.Context, e event.TypedDeleteEvent[object], q workqueue.TypedRateLimitingInterface[request]) {
|
||||
if h.DeleteFunc != nil {
|
||||
h.DeleteFunc(ctx, e, q)
|
||||
}
|
||||
}
|
||||
|
||||
// Update implements EventHandler.
|
||||
func (h Funcs) Update(ctx context.Context, e event.UpdateEvent, q workqueue.RateLimitingInterface) {
|
||||
func (h TypedFuncs[object, request]) Update(ctx context.Context, e event.TypedUpdateEvent[object], q workqueue.TypedRateLimitingInterface[request]) {
|
||||
if h.UpdateFunc != nil {
|
||||
h.UpdateFunc(ctx, e, q)
|
||||
}
|
||||
}
|
||||
|
||||
// Generic implements EventHandler.
|
||||
func (h Funcs) Generic(ctx context.Context, e event.GenericEvent, q workqueue.RateLimitingInterface) {
|
||||
func (h TypedFuncs[object, request]) Generic(ctx context.Context, e event.TypedGenericEvent[object], q workqueue.TypedRateLimitingInterface[request]) {
|
||||
if h.GenericFunc != nil {
|
||||
h.GenericFunc(ctx, e, q)
|
||||
}
|
||||
|
||||
87
vendor/sigs.k8s.io/controller-runtime/pkg/internal/controller/controller.go
generated
vendored
87
vendor/sigs.k8s.io/controller-runtime/pkg/internal/controller/controller.go
generated
vendored
@@ -29,16 +29,14 @@ import (
|
||||
"k8s.io/apimachinery/pkg/util/uuid"
|
||||
"k8s.io/client-go/util/workqueue"
|
||||
|
||||
"sigs.k8s.io/controller-runtime/pkg/handler"
|
||||
ctrlmetrics "sigs.k8s.io/controller-runtime/pkg/internal/controller/metrics"
|
||||
logf "sigs.k8s.io/controller-runtime/pkg/log"
|
||||
"sigs.k8s.io/controller-runtime/pkg/predicate"
|
||||
"sigs.k8s.io/controller-runtime/pkg/reconcile"
|
||||
"sigs.k8s.io/controller-runtime/pkg/source"
|
||||
)
|
||||
|
||||
// Controller implements controller.Controller.
|
||||
type Controller struct {
|
||||
type Controller[request comparable] struct {
|
||||
// Name is used to uniquely identify a Controller in tracing, logging and monitoring. Name is required.
|
||||
Name string
|
||||
|
||||
@@ -48,16 +46,19 @@ type Controller struct {
|
||||
// Reconciler is a function that can be called at any time with the Name / Namespace of an object and
|
||||
// ensures that the state of the system matches the state specified in the object.
|
||||
// Defaults to the DefaultReconcileFunc.
|
||||
Do reconcile.Reconciler
|
||||
Do reconcile.TypedReconciler[request]
|
||||
|
||||
// MakeQueue constructs the queue for this controller once the controller is ready to start.
|
||||
// This exists because the standard Kubernetes workqueues start themselves immediately, which
|
||||
// RateLimiter is used to limit how frequently requests may be queued into the work queue.
|
||||
RateLimiter workqueue.TypedRateLimiter[request]
|
||||
|
||||
// NewQueue constructs the queue for this controller once the controller is ready to start.
|
||||
// This is a func because the standard Kubernetes work queues start themselves immediately, which
|
||||
// leads to goroutine leaks if something calls controller.New repeatedly.
|
||||
MakeQueue func() workqueue.RateLimitingInterface
|
||||
NewQueue func(controllerName string, rateLimiter workqueue.TypedRateLimiter[request]) workqueue.TypedRateLimitingInterface[request]
|
||||
|
||||
// Queue is an listeningQueue that listens for events from Informers and adds object keys to
|
||||
// the Queue for processing
|
||||
Queue workqueue.RateLimitingInterface
|
||||
Queue workqueue.TypedRateLimitingInterface[request]
|
||||
|
||||
// mu is used to synchronize Controller setup
|
||||
mu sync.Mutex
|
||||
@@ -77,35 +78,31 @@ type Controller struct {
|
||||
CacheSyncTimeout time.Duration
|
||||
|
||||
// startWatches maintains a list of sources, handlers, and predicates to start when the controller is started.
|
||||
startWatches []watchDescription
|
||||
startWatches []source.TypedSource[request]
|
||||
|
||||
// LogConstructor is used to construct a logger to then log messages to users during reconciliation,
|
||||
// or for example when a watch is started.
|
||||
// Note: LogConstructor has to be able to handle nil requests as we are also using it
|
||||
// outside the context of a reconciliation.
|
||||
LogConstructor func(request *reconcile.Request) logr.Logger
|
||||
LogConstructor func(request *request) logr.Logger
|
||||
|
||||
// RecoverPanic indicates whether the panic caused by reconcile should be recovered.
|
||||
// Defaults to true.
|
||||
RecoverPanic *bool
|
||||
|
||||
// LeaderElected indicates whether the controller is leader elected or always running.
|
||||
LeaderElected *bool
|
||||
}
|
||||
|
||||
// watchDescription contains all the information necessary to start a watch.
|
||||
type watchDescription struct {
|
||||
src source.Source
|
||||
handler handler.EventHandler
|
||||
predicates []predicate.Predicate
|
||||
}
|
||||
|
||||
// Reconcile implements reconcile.Reconciler.
|
||||
func (c *Controller) Reconcile(ctx context.Context, req reconcile.Request) (_ reconcile.Result, err error) {
|
||||
func (c *Controller[request]) Reconcile(ctx context.Context, req request) (_ reconcile.Result, err error) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
if c.RecoverPanic != nil && *c.RecoverPanic {
|
||||
ctrlmetrics.ReconcilePanics.WithLabelValues(c.Name).Inc()
|
||||
|
||||
if c.RecoverPanic == nil || *c.RecoverPanic {
|
||||
for _, fn := range utilruntime.PanicHandlers {
|
||||
fn(r)
|
||||
fn(ctx, r)
|
||||
}
|
||||
err = fmt.Errorf("panic: %v [recovered]", r)
|
||||
return
|
||||
@@ -120,7 +117,7 @@ func (c *Controller) Reconcile(ctx context.Context, req reconcile.Request) (_ re
|
||||
}
|
||||
|
||||
// Watch implements controller.Controller.
|
||||
func (c *Controller) Watch(src source.Source, evthdler handler.EventHandler, prct ...predicate.Predicate) error {
|
||||
func (c *Controller[request]) Watch(src source.TypedSource[request]) error {
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
|
||||
@@ -128,16 +125,16 @@ func (c *Controller) Watch(src source.Source, evthdler handler.EventHandler, prc
|
||||
//
|
||||
// These watches are going to be held on the controller struct until the manager or user calls Start(...).
|
||||
if !c.Started {
|
||||
c.startWatches = append(c.startWatches, watchDescription{src: src, handler: evthdler, predicates: prct})
|
||||
c.startWatches = append(c.startWatches, src)
|
||||
return nil
|
||||
}
|
||||
|
||||
c.LogConstructor(nil).Info("Starting EventSource", "source", src)
|
||||
return src.Start(c.ctx, evthdler, c.Queue, prct...)
|
||||
return src.Start(c.ctx, c.Queue)
|
||||
}
|
||||
|
||||
// NeedLeaderElection implements the manager.LeaderElectionRunnable interface.
|
||||
func (c *Controller) NeedLeaderElection() bool {
|
||||
func (c *Controller[request]) NeedLeaderElection() bool {
|
||||
if c.LeaderElected == nil {
|
||||
return true
|
||||
}
|
||||
@@ -145,7 +142,7 @@ func (c *Controller) NeedLeaderElection() bool {
|
||||
}
|
||||
|
||||
// Start implements controller.Controller.
|
||||
func (c *Controller) Start(ctx context.Context) error {
|
||||
func (c *Controller[request]) Start(ctx context.Context) error {
|
||||
// use an IIFE to get proper lock handling
|
||||
// but lock outside to get proper handling of the queue shutdown
|
||||
c.mu.Lock()
|
||||
@@ -158,7 +155,7 @@ func (c *Controller) Start(ctx context.Context) error {
|
||||
// Set the internal context.
|
||||
c.ctx = ctx
|
||||
|
||||
c.Queue = c.MakeQueue()
|
||||
c.Queue = c.NewQueue(c.Name, c.RateLimiter)
|
||||
go func() {
|
||||
<-ctx.Done()
|
||||
c.Queue.ShutDown()
|
||||
@@ -175,9 +172,9 @@ func (c *Controller) Start(ctx context.Context) error {
|
||||
// caches to sync so that they have a chance to register their intendeded
|
||||
// caches.
|
||||
for _, watch := range c.startWatches {
|
||||
c.LogConstructor(nil).Info("Starting EventSource", "source", fmt.Sprintf("%s", watch.src))
|
||||
c.LogConstructor(nil).Info("Starting EventSource", "source", fmt.Sprintf("%s", watch))
|
||||
|
||||
if err := watch.src.Start(ctx, watch.handler, c.Queue, watch.predicates...); err != nil {
|
||||
if err := watch.Start(ctx, c.Queue); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@@ -186,7 +183,7 @@ func (c *Controller) Start(ctx context.Context) error {
|
||||
c.LogConstructor(nil).Info("Starting Controller")
|
||||
|
||||
for _, watch := range c.startWatches {
|
||||
syncingSource, ok := watch.src.(source.SyncingSource)
|
||||
syncingSource, ok := watch.(source.SyncingSource)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
@@ -245,7 +242,7 @@ func (c *Controller) Start(ctx context.Context) error {
|
||||
|
||||
// processNextWorkItem will read a single work item off the workqueue and
|
||||
// attempt to process it, by calling the reconcileHandler.
|
||||
func (c *Controller) processNextWorkItem(ctx context.Context) bool {
|
||||
func (c *Controller[request]) processNextWorkItem(ctx context.Context) bool {
|
||||
obj, shutdown := c.Queue.Get()
|
||||
if shutdown {
|
||||
// Stop working
|
||||
@@ -274,35 +271,25 @@ const (
|
||||
labelSuccess = "success"
|
||||
)
|
||||
|
||||
func (c *Controller) initMetrics() {
|
||||
ctrlmetrics.ActiveWorkers.WithLabelValues(c.Name).Set(0)
|
||||
ctrlmetrics.ReconcileErrors.WithLabelValues(c.Name).Add(0)
|
||||
func (c *Controller[request]) initMetrics() {
|
||||
ctrlmetrics.ReconcileTotal.WithLabelValues(c.Name, labelError).Add(0)
|
||||
ctrlmetrics.ReconcileTotal.WithLabelValues(c.Name, labelRequeueAfter).Add(0)
|
||||
ctrlmetrics.ReconcileTotal.WithLabelValues(c.Name, labelRequeue).Add(0)
|
||||
ctrlmetrics.ReconcileTotal.WithLabelValues(c.Name, labelSuccess).Add(0)
|
||||
ctrlmetrics.ReconcileErrors.WithLabelValues(c.Name).Add(0)
|
||||
ctrlmetrics.TerminalReconcileErrors.WithLabelValues(c.Name).Add(0)
|
||||
ctrlmetrics.ReconcilePanics.WithLabelValues(c.Name).Add(0)
|
||||
ctrlmetrics.WorkerCount.WithLabelValues(c.Name).Set(float64(c.MaxConcurrentReconciles))
|
||||
ctrlmetrics.ActiveWorkers.WithLabelValues(c.Name).Set(0)
|
||||
}
|
||||
|
||||
func (c *Controller) reconcileHandler(ctx context.Context, obj interface{}) {
|
||||
func (c *Controller[request]) reconcileHandler(ctx context.Context, req request) {
|
||||
// Update metrics after processing each item
|
||||
reconcileStartTS := time.Now()
|
||||
defer func() {
|
||||
c.updateMetrics(time.Since(reconcileStartTS))
|
||||
}()
|
||||
|
||||
// Make sure that the object is a valid request.
|
||||
req, ok := obj.(reconcile.Request)
|
||||
if !ok {
|
||||
// As the item in the workqueue is actually invalid, we call
|
||||
// Forget here else we'd go into a loop of attempting to
|
||||
// process a work item that is invalid.
|
||||
c.Queue.Forget(obj)
|
||||
c.LogConstructor(nil).Error(nil, "Queue item was not a Request", "type", fmt.Sprintf("%T", obj), "value", obj)
|
||||
// Return true, don't take a break
|
||||
return
|
||||
}
|
||||
|
||||
log := c.LogConstructor(&req)
|
||||
reconcileID := uuid.NewUUID()
|
||||
|
||||
@@ -333,7 +320,7 @@ func (c *Controller) reconcileHandler(ctx context.Context, obj interface{}) {
|
||||
// along with a non-nil error. But this is intended as
|
||||
// We need to drive to stable reconcile loops before queuing due
|
||||
// to result.RequestAfter
|
||||
c.Queue.Forget(obj)
|
||||
c.Queue.Forget(req)
|
||||
c.Queue.AddAfter(req, result.RequeueAfter)
|
||||
ctrlmetrics.ReconcileTotal.WithLabelValues(c.Name, labelRequeueAfter).Inc()
|
||||
case result.Requeue:
|
||||
@@ -344,18 +331,18 @@ func (c *Controller) reconcileHandler(ctx context.Context, obj interface{}) {
|
||||
log.V(5).Info("Reconcile successful")
|
||||
// Finally, if no error occurs we Forget this item so it does not
|
||||
// get queued again until another change happens.
|
||||
c.Queue.Forget(obj)
|
||||
c.Queue.Forget(req)
|
||||
ctrlmetrics.ReconcileTotal.WithLabelValues(c.Name, labelSuccess).Inc()
|
||||
}
|
||||
}
|
||||
|
||||
// GetLogger returns this controller's logger.
|
||||
func (c *Controller) GetLogger() logr.Logger {
|
||||
func (c *Controller[request]) GetLogger() logr.Logger {
|
||||
return c.LogConstructor(nil)
|
||||
}
|
||||
|
||||
// updateMetrics updates prometheus metrics within the controller.
|
||||
func (c *Controller) updateMetrics(reconcileTime time.Duration) {
|
||||
func (c *Controller[request]) updateMetrics(reconcileTime time.Duration) {
|
||||
ctrlmetrics.ReconcileTime.WithLabelValues(c.Name).Observe(reconcileTime.Seconds())
|
||||
}
|
||||
|
||||
|
||||
8
vendor/sigs.k8s.io/controller-runtime/pkg/internal/controller/metrics/metrics.go
generated
vendored
8
vendor/sigs.k8s.io/controller-runtime/pkg/internal/controller/metrics/metrics.go
generated
vendored
@@ -46,6 +46,13 @@ var (
|
||||
Help: "Total number of terminal reconciliation errors per controller",
|
||||
}, []string{"controller"})
|
||||
|
||||
// ReconcilePanics is a prometheus counter metrics which holds the total
|
||||
// number of panics from the Reconciler.
|
||||
ReconcilePanics = prometheus.NewCounterVec(prometheus.CounterOpts{
|
||||
Name: "controller_runtime_reconcile_panics_total",
|
||||
Help: "Total number of reconciliation panics per controller",
|
||||
}, []string{"controller"})
|
||||
|
||||
// ReconcileTime is a prometheus metric which keeps track of the duration
|
||||
// of reconciliations.
|
||||
ReconcileTime = prometheus.NewHistogramVec(prometheus.HistogramOpts{
|
||||
@@ -75,6 +82,7 @@ func init() {
|
||||
ReconcileTotal,
|
||||
ReconcileErrors,
|
||||
TerminalReconcileErrors,
|
||||
ReconcilePanics,
|
||||
ReconcileTime,
|
||||
WorkerCount,
|
||||
ActiveWorkers,
|
||||
|
||||
38
vendor/sigs.k8s.io/controller-runtime/pkg/internal/source/event_handler.go
generated
vendored
38
vendor/sigs.k8s.io/controller-runtime/pkg/internal/source/event_handler.go
generated
vendored
@@ -33,8 +33,12 @@ import (
|
||||
var log = logf.RuntimeLog.WithName("source").WithName("EventHandler")
|
||||
|
||||
// NewEventHandler creates a new EventHandler.
|
||||
func NewEventHandler(ctx context.Context, queue workqueue.RateLimitingInterface, handler handler.EventHandler, predicates []predicate.Predicate) *EventHandler {
|
||||
return &EventHandler{
|
||||
func NewEventHandler[object client.Object, request comparable](
|
||||
ctx context.Context,
|
||||
queue workqueue.TypedRateLimitingInterface[request],
|
||||
handler handler.TypedEventHandler[object, request],
|
||||
predicates []predicate.TypedPredicate[object]) *EventHandler[object, request] {
|
||||
return &EventHandler[object, request]{
|
||||
ctx: ctx,
|
||||
handler: handler,
|
||||
queue: queue,
|
||||
@@ -43,19 +47,19 @@ func NewEventHandler(ctx context.Context, queue workqueue.RateLimitingInterface,
|
||||
}
|
||||
|
||||
// EventHandler adapts a handler.EventHandler interface to a cache.ResourceEventHandler interface.
|
||||
type EventHandler struct {
|
||||
type EventHandler[object client.Object, request comparable] struct {
|
||||
// ctx stores the context that created the event handler
|
||||
// that is used to propagate cancellation signals to each handler function.
|
||||
ctx context.Context
|
||||
|
||||
handler handler.EventHandler
|
||||
queue workqueue.RateLimitingInterface
|
||||
predicates []predicate.Predicate
|
||||
handler handler.TypedEventHandler[object, request]
|
||||
queue workqueue.TypedRateLimitingInterface[request]
|
||||
predicates []predicate.TypedPredicate[object]
|
||||
}
|
||||
|
||||
// HandlerFuncs converts EventHandler to a ResourceEventHandlerFuncs
|
||||
// TODO: switch to ResourceEventHandlerDetailedFuncs with client-go 1.27
|
||||
func (e *EventHandler) HandlerFuncs() cache.ResourceEventHandlerFuncs {
|
||||
func (e *EventHandler[object, request]) HandlerFuncs() cache.ResourceEventHandlerFuncs {
|
||||
return cache.ResourceEventHandlerFuncs{
|
||||
AddFunc: e.OnAdd,
|
||||
UpdateFunc: e.OnUpdate,
|
||||
@@ -64,11 +68,11 @@ func (e *EventHandler) HandlerFuncs() cache.ResourceEventHandlerFuncs {
|
||||
}
|
||||
|
||||
// OnAdd creates CreateEvent and calls Create on EventHandler.
|
||||
func (e *EventHandler) OnAdd(obj interface{}) {
|
||||
c := event.CreateEvent{}
|
||||
func (e *EventHandler[object, request]) OnAdd(obj interface{}) {
|
||||
c := event.TypedCreateEvent[object]{}
|
||||
|
||||
// Pull Object out of the object
|
||||
if o, ok := obj.(client.Object); ok {
|
||||
if o, ok := obj.(object); ok {
|
||||
c.Object = o
|
||||
} else {
|
||||
log.Error(nil, "OnAdd missing Object",
|
||||
@@ -89,10 +93,10 @@ func (e *EventHandler) OnAdd(obj interface{}) {
|
||||
}
|
||||
|
||||
// OnUpdate creates UpdateEvent and calls Update on EventHandler.
|
||||
func (e *EventHandler) OnUpdate(oldObj, newObj interface{}) {
|
||||
u := event.UpdateEvent{}
|
||||
func (e *EventHandler[object, request]) OnUpdate(oldObj, newObj interface{}) {
|
||||
u := event.TypedUpdateEvent[object]{}
|
||||
|
||||
if o, ok := oldObj.(client.Object); ok {
|
||||
if o, ok := oldObj.(object); ok {
|
||||
u.ObjectOld = o
|
||||
} else {
|
||||
log.Error(nil, "OnUpdate missing ObjectOld",
|
||||
@@ -101,7 +105,7 @@ func (e *EventHandler) OnUpdate(oldObj, newObj interface{}) {
|
||||
}
|
||||
|
||||
// Pull Object out of the object
|
||||
if o, ok := newObj.(client.Object); ok {
|
||||
if o, ok := newObj.(object); ok {
|
||||
u.ObjectNew = o
|
||||
} else {
|
||||
log.Error(nil, "OnUpdate missing ObjectNew",
|
||||
@@ -122,8 +126,8 @@ func (e *EventHandler) OnUpdate(oldObj, newObj interface{}) {
|
||||
}
|
||||
|
||||
// OnDelete creates DeleteEvent and calls Delete on EventHandler.
|
||||
func (e *EventHandler) OnDelete(obj interface{}) {
|
||||
d := event.DeleteEvent{}
|
||||
func (e *EventHandler[object, request]) OnDelete(obj interface{}) {
|
||||
d := event.TypedDeleteEvent[object]{}
|
||||
|
||||
// Deal with tombstone events by pulling the object out. Tombstone events wrap the object in a
|
||||
// DeleteFinalStateUnknown struct, so the object needs to be pulled out.
|
||||
@@ -149,7 +153,7 @@ func (e *EventHandler) OnDelete(obj interface{}) {
|
||||
}
|
||||
|
||||
// Pull Object out of the object
|
||||
if o, ok := obj.(client.Object); ok {
|
||||
if o, ok := obj.(object); ok {
|
||||
d.Object = o
|
||||
} else {
|
||||
log.Error(nil, "OnDelete missing Object",
|
||||
|
||||
58
vendor/sigs.k8s.io/controller-runtime/pkg/internal/source/kind.go
generated
vendored
58
vendor/sigs.k8s.io/controller-runtime/pkg/internal/source/kind.go
generated
vendored
@@ -4,12 +4,14 @@ import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"time"
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
"k8s.io/client-go/util/workqueue"
|
||||
|
||||
"sigs.k8s.io/controller-runtime/pkg/cache"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
"sigs.k8s.io/controller-runtime/pkg/handler"
|
||||
@@ -17,34 +19,40 @@ import (
|
||||
)
|
||||
|
||||
// Kind is used to provide a source of events originating inside the cluster from Watches (e.g. Pod Create).
|
||||
type Kind struct {
|
||||
type Kind[object client.Object, request comparable] struct {
|
||||
// Type is the type of object to watch. e.g. &v1.Pod{}
|
||||
Type client.Object
|
||||
Type object
|
||||
|
||||
// Cache used to watch APIs
|
||||
Cache cache.Cache
|
||||
|
||||
// started may contain an error if one was encountered during startup. If its closed and does not
|
||||
Handler handler.TypedEventHandler[object, request]
|
||||
|
||||
Predicates []predicate.TypedPredicate[object]
|
||||
|
||||
// startedErr may contain an error if one was encountered during startup. If its closed and does not
|
||||
// contain an error, startup and syncing finished.
|
||||
started chan error
|
||||
startedErr chan error
|
||||
startCancel func()
|
||||
}
|
||||
|
||||
// Start is internal and should be called only by the Controller to register an EventHandler with the Informer
|
||||
// to enqueue reconcile.Requests.
|
||||
func (ks *Kind) Start(ctx context.Context, handler handler.EventHandler, queue workqueue.RateLimitingInterface,
|
||||
prct ...predicate.Predicate) error {
|
||||
if ks.Type == nil {
|
||||
func (ks *Kind[object, request]) Start(ctx context.Context, queue workqueue.TypedRateLimitingInterface[request]) error {
|
||||
if isNil(ks.Type) {
|
||||
return fmt.Errorf("must create Kind with a non-nil object")
|
||||
}
|
||||
if ks.Cache == nil {
|
||||
if isNil(ks.Cache) {
|
||||
return fmt.Errorf("must create Kind with a non-nil cache")
|
||||
}
|
||||
if isNil(ks.Handler) {
|
||||
return errors.New("must create Kind with non-nil handler")
|
||||
}
|
||||
|
||||
// cache.GetInformer will block until its context is cancelled if the cache was already started and it can not
|
||||
// sync that informer (most commonly due to RBAC issues).
|
||||
ctx, ks.startCancel = context.WithCancel(ctx)
|
||||
ks.started = make(chan error)
|
||||
ks.startedErr = make(chan error)
|
||||
go func() {
|
||||
var (
|
||||
i cache.Informer
|
||||
@@ -72,30 +80,30 @@ func (ks *Kind) Start(ctx context.Context, handler handler.EventHandler, queue w
|
||||
return true, nil
|
||||
}); err != nil {
|
||||
if lastErr != nil {
|
||||
ks.started <- fmt.Errorf("failed to get informer from cache: %w", lastErr)
|
||||
ks.startedErr <- fmt.Errorf("failed to get informer from cache: %w", lastErr)
|
||||
return
|
||||
}
|
||||
ks.started <- err
|
||||
ks.startedErr <- err
|
||||
return
|
||||
}
|
||||
|
||||
_, err := i.AddEventHandler(NewEventHandler(ctx, queue, handler, prct).HandlerFuncs())
|
||||
_, err := i.AddEventHandler(NewEventHandler(ctx, queue, ks.Handler, ks.Predicates).HandlerFuncs())
|
||||
if err != nil {
|
||||
ks.started <- err
|
||||
ks.startedErr <- err
|
||||
return
|
||||
}
|
||||
if !ks.Cache.WaitForCacheSync(ctx) {
|
||||
// Would be great to return something more informative here
|
||||
ks.started <- errors.New("cache did not sync")
|
||||
ks.startedErr <- errors.New("cache did not sync")
|
||||
}
|
||||
close(ks.started)
|
||||
close(ks.startedErr)
|
||||
}()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ks *Kind) String() string {
|
||||
if ks.Type != nil {
|
||||
func (ks *Kind[object, request]) String() string {
|
||||
if !isNil(ks.Type) {
|
||||
return fmt.Sprintf("kind source: %T", ks.Type)
|
||||
}
|
||||
return "kind source: unknown type"
|
||||
@@ -103,9 +111,9 @@ func (ks *Kind) String() string {
|
||||
|
||||
// WaitForSync implements SyncingSource to allow controllers to wait with starting
|
||||
// workers until the cache is synced.
|
||||
func (ks *Kind) WaitForSync(ctx context.Context) error {
|
||||
func (ks *Kind[object, request]) WaitForSync(ctx context.Context) error {
|
||||
select {
|
||||
case err := <-ks.started:
|
||||
case err := <-ks.startedErr:
|
||||
return err
|
||||
case <-ctx.Done():
|
||||
ks.startCancel()
|
||||
@@ -115,3 +123,15 @@ func (ks *Kind) WaitForSync(ctx context.Context) error {
|
||||
return fmt.Errorf("timed out waiting for cache to be synced for Kind %T", ks.Type)
|
||||
}
|
||||
}
|
||||
|
||||
func isNil(arg any) bool {
|
||||
if v := reflect.ValueOf(arg); !v.IsValid() || ((v.Kind() == reflect.Ptr ||
|
||||
v.Kind() == reflect.Interface ||
|
||||
v.Kind() == reflect.Slice ||
|
||||
v.Kind() == reflect.Map ||
|
||||
v.Kind() == reflect.Chan ||
|
||||
v.Kind() == reflect.Func) && v.IsNil()) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
110
vendor/sigs.k8s.io/controller-runtime/pkg/manager/internal.go
generated
vendored
110
vendor/sigs.k8s.io/controller-runtime/pkg/manager/internal.go
generated
vendored
@@ -179,6 +179,24 @@ func (cm *controllerManager) add(r Runnable) error {
|
||||
return cm.runnables.Add(r)
|
||||
}
|
||||
|
||||
// AddMetricsServerExtraHandler adds extra handler served on path to the http server that serves metrics.
|
||||
func (cm *controllerManager) AddMetricsServerExtraHandler(path string, handler http.Handler) error {
|
||||
cm.Lock()
|
||||
defer cm.Unlock()
|
||||
if cm.started {
|
||||
return fmt.Errorf("unable to add new metrics handler because metrics endpoint has already been created")
|
||||
}
|
||||
if cm.metricsServer == nil {
|
||||
cm.GetLogger().Info("warn: metrics server is currently disabled, registering extra handler will be ignored", "path", path)
|
||||
return nil
|
||||
}
|
||||
if err := cm.metricsServer.AddExtraHandler(path, handler); err != nil {
|
||||
return err
|
||||
}
|
||||
cm.logger.V(2).Info("Registering metrics http server extra handler", "path", path)
|
||||
return nil
|
||||
}
|
||||
|
||||
// AddHealthzCheck allows you to add Healthz checker.
|
||||
func (cm *controllerManager) AddHealthzCheck(name string, check healthz.Checker) error {
|
||||
cm.Lock()
|
||||
@@ -284,9 +302,8 @@ func (cm *controllerManager) addHealthProbeServer() error {
|
||||
mux.Handle(cm.livenessEndpointName+"/", http.StripPrefix(cm.livenessEndpointName, cm.healthzHandler))
|
||||
}
|
||||
|
||||
return cm.add(&server{
|
||||
Kind: "health probe",
|
||||
Log: cm.logger,
|
||||
return cm.add(&Server{
|
||||
Name: "health probe",
|
||||
Server: srv,
|
||||
Listener: cm.healthProbeListener,
|
||||
})
|
||||
@@ -302,9 +319,8 @@ func (cm *controllerManager) addPprofServer() error {
|
||||
mux.HandleFunc("/debug/pprof/symbol", pprof.Symbol)
|
||||
mux.HandleFunc("/debug/pprof/trace", pprof.Trace)
|
||||
|
||||
return cm.add(&server{
|
||||
Kind: "pprof",
|
||||
Log: cm.logger,
|
||||
return cm.add(&Server{
|
||||
Name: "pprof",
|
||||
Server: srv,
|
||||
Listener: cm.pprofListener,
|
||||
})
|
||||
@@ -335,6 +351,16 @@ func (cm *controllerManager) Start(ctx context.Context) (err error) {
|
||||
// Initialize the internal context.
|
||||
cm.internalCtx, cm.internalCancel = context.WithCancel(ctx)
|
||||
|
||||
// Leader elector must be created before defer that contains engageStopProcedure function
|
||||
// https://github.com/kubernetes-sigs/controller-runtime/issues/2873
|
||||
var leaderElector *leaderelection.LeaderElector
|
||||
if cm.resourceLock != nil {
|
||||
leaderElector, err = cm.initLeaderElector()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed during initialization leader election process: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
// This chan indicates that stop is complete, in other words all runnables have returned or timeout on stop request
|
||||
stopComplete := make(chan struct{})
|
||||
defer close(stopComplete)
|
||||
@@ -384,14 +410,13 @@ func (cm *controllerManager) Start(ctx context.Context) (err error) {
|
||||
}
|
||||
}
|
||||
|
||||
// First start any internal HTTP servers, which includes health probes, metrics and profiling if enabled.
|
||||
// First start any HTTP servers, which includes health probes, metrics and profiling if enabled.
|
||||
//
|
||||
// WARNING: Internal HTTP servers MUST start before any cache is populated, otherwise it would block
|
||||
// conversion webhooks to be ready for serving which make the cache never get ready.
|
||||
if err := cm.runnables.HTTPServers.Start(cm.internalCtx); err != nil {
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to start HTTP servers: %w", err)
|
||||
}
|
||||
// WARNING: HTTPServers includes the health probes, which MUST start before any cache is populated, otherwise
|
||||
// it would block conversion webhooks to be ready for serving which make the cache never get ready.
|
||||
logCtx := logr.NewContext(cm.internalCtx, cm.logger)
|
||||
if err := cm.runnables.HTTPServers.Start(logCtx); err != nil {
|
||||
return fmt.Errorf("failed to start HTTP servers: %w", err)
|
||||
}
|
||||
|
||||
// Start any webhook servers, which includes conversion, validation, and defaulting
|
||||
@@ -401,42 +426,39 @@ func (cm *controllerManager) Start(ctx context.Context) (err error) {
|
||||
// between conversion webhooks and the cache sync (usually initial list) which causes the webhooks
|
||||
// to never start because no cache can be populated.
|
||||
if err := cm.runnables.Webhooks.Start(cm.internalCtx); err != nil {
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to start webhooks: %w", err)
|
||||
}
|
||||
return fmt.Errorf("failed to start webhooks: %w", err)
|
||||
}
|
||||
|
||||
// Start and wait for caches.
|
||||
if err := cm.runnables.Caches.Start(cm.internalCtx); err != nil {
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to start caches: %w", err)
|
||||
}
|
||||
return fmt.Errorf("failed to start caches: %w", err)
|
||||
}
|
||||
|
||||
// Start the non-leaderelection Runnables after the cache has synced.
|
||||
if err := cm.runnables.Others.Start(cm.internalCtx); err != nil {
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to start other runnables: %w", err)
|
||||
}
|
||||
return fmt.Errorf("failed to start other runnables: %w", err)
|
||||
}
|
||||
|
||||
// Start the leader election and all required runnables.
|
||||
{
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
cm.leaderElectionCancel = cancel
|
||||
go func() {
|
||||
if cm.resourceLock != nil {
|
||||
if err := cm.startLeaderElection(ctx); err != nil {
|
||||
cm.errChan <- err
|
||||
}
|
||||
} else {
|
||||
if leaderElector != nil {
|
||||
// Start the leader elector process
|
||||
go func() {
|
||||
leaderElector.Run(ctx)
|
||||
<-ctx.Done()
|
||||
close(cm.leaderElectionStopped)
|
||||
}()
|
||||
} else {
|
||||
go func() {
|
||||
// Treat not having leader election enabled the same as being elected.
|
||||
if err := cm.startLeaderElectionRunnables(); err != nil {
|
||||
cm.errChan <- err
|
||||
}
|
||||
close(cm.elected)
|
||||
}
|
||||
}()
|
||||
}()
|
||||
}
|
||||
}
|
||||
|
||||
ready = true
|
||||
@@ -485,8 +507,8 @@ func (cm *controllerManager) engageStopProcedure(stopComplete <-chan struct{}) e
|
||||
cm.internalCancel()
|
||||
})
|
||||
select {
|
||||
case err, ok := <-cm.errChan:
|
||||
if ok {
|
||||
case err := <-cm.errChan:
|
||||
if !errors.Is(err, context.Canceled) {
|
||||
cm.logger.Error(err, "error received after stop sequence was engaged")
|
||||
}
|
||||
case <-stopComplete:
|
||||
@@ -518,6 +540,8 @@ func (cm *controllerManager) engageStopProcedure(stopComplete <-chan struct{}) e
|
||||
|
||||
// Stop all the leader election runnables, which includes reconcilers.
|
||||
cm.logger.Info("Stopping and waiting for leader election runnables")
|
||||
// Prevent leader election when shutting down a non-elected manager
|
||||
cm.runnables.LeaderElection.startOnce.Do(func() {})
|
||||
cm.runnables.LeaderElection.StopAndWait(cm.shutdownCtx)
|
||||
|
||||
// Stop the caches before the leader election runnables, this is an important
|
||||
@@ -553,12 +577,8 @@ func (cm *controllerManager) engageStopProcedure(stopComplete <-chan struct{}) e
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cm *controllerManager) startLeaderElectionRunnables() error {
|
||||
return cm.runnables.LeaderElection.Start(cm.internalCtx)
|
||||
}
|
||||
|
||||
func (cm *controllerManager) startLeaderElection(ctx context.Context) (err error) {
|
||||
l, err := leaderelection.NewLeaderElector(leaderelection.LeaderElectionConfig{
|
||||
func (cm *controllerManager) initLeaderElector() (*leaderelection.LeaderElector, error) {
|
||||
leaderElector, err := leaderelection.NewLeaderElector(leaderelection.LeaderElectionConfig{
|
||||
Lock: cm.resourceLock,
|
||||
LeaseDuration: cm.leaseDuration,
|
||||
RenewDeadline: cm.renewDeadline,
|
||||
@@ -588,16 +608,14 @@ func (cm *controllerManager) startLeaderElection(ctx context.Context) (err error
|
||||
Name: cm.leaderElectionID,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Start the leader elector process
|
||||
go func() {
|
||||
l.Run(ctx)
|
||||
<-ctx.Done()
|
||||
close(cm.leaderElectionStopped)
|
||||
}()
|
||||
return nil
|
||||
return leaderElector, nil
|
||||
}
|
||||
|
||||
func (cm *controllerManager) startLeaderElectionRunnables() error {
|
||||
return cm.runnables.LeaderElection.Start(cm.internalCtx)
|
||||
}
|
||||
|
||||
func (cm *controllerManager) Elected() <-chan struct{} {
|
||||
|
||||
132
vendor/sigs.k8s.io/controller-runtime/pkg/manager/manager.go
generated
vendored
132
vendor/sigs.k8s.io/controller-runtime/pkg/manager/manager.go
generated
vendored
@@ -22,14 +22,12 @@ import (
|
||||
"fmt"
|
||||
"net"
|
||||
"net/http"
|
||||
"reflect"
|
||||
"time"
|
||||
|
||||
"github.com/go-logr/logr"
|
||||
coordinationv1 "k8s.io/api/coordination/v1"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/client-go/rest"
|
||||
"k8s.io/client-go/tools/leaderelection/resourcelock"
|
||||
@@ -41,7 +39,6 @@ import (
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
"sigs.k8s.io/controller-runtime/pkg/cluster"
|
||||
"sigs.k8s.io/controller-runtime/pkg/config"
|
||||
"sigs.k8s.io/controller-runtime/pkg/config/v1alpha1"
|
||||
"sigs.k8s.io/controller-runtime/pkg/healthz"
|
||||
intrec "sigs.k8s.io/controller-runtime/pkg/internal/recorder"
|
||||
"sigs.k8s.io/controller-runtime/pkg/leaderelection"
|
||||
@@ -67,6 +64,15 @@ type Manager interface {
|
||||
// election was configured.
|
||||
Elected() <-chan struct{}
|
||||
|
||||
// AddMetricsServerExtraHandler adds an extra handler served on path to the http server that serves metrics.
|
||||
// Might be useful to register some diagnostic endpoints e.g. pprof.
|
||||
//
|
||||
// Note that these endpoints are meant to be sensitive and shouldn't be exposed publicly.
|
||||
//
|
||||
// If the simple path -> handler mapping offered here is not enough,
|
||||
// a new http server/listener should be added as Runnable to the manager via Add method.
|
||||
AddMetricsServerExtraHandler(path string, handler http.Handler) error
|
||||
|
||||
// AddHealthzCheck allows you to add Healthz checker
|
||||
AddHealthzCheck(name string, check healthz.Checker) error
|
||||
|
||||
@@ -438,126 +444,6 @@ func New(config *rest.Config, options Options) (Manager, error) {
|
||||
}, nil
|
||||
}
|
||||
|
||||
// AndFrom will use a supplied type and convert to Options
|
||||
// any options already set on Options will be ignored, this is used to allow
|
||||
// cli flags to override anything specified in the config file.
|
||||
//
|
||||
// Deprecated: This function has been deprecated and will be removed in a future release,
|
||||
// The Component Configuration package has been unmaintained for over a year and is no longer
|
||||
// actively developed. Users should migrate to their own configuration format
|
||||
// and configure Manager.Options directly.
|
||||
// See https://github.com/kubernetes-sigs/controller-runtime/issues/895
|
||||
// for more information, feedback, and comments.
|
||||
func (o Options) AndFrom(loader config.ControllerManagerConfiguration) (Options, error) {
|
||||
newObj, err := loader.Complete()
|
||||
if err != nil {
|
||||
return o, err
|
||||
}
|
||||
|
||||
o = o.setLeaderElectionConfig(newObj)
|
||||
|
||||
if o.Cache.SyncPeriod == nil && newObj.SyncPeriod != nil {
|
||||
o.Cache.SyncPeriod = &newObj.SyncPeriod.Duration
|
||||
}
|
||||
|
||||
if len(o.Cache.DefaultNamespaces) == 0 && newObj.CacheNamespace != "" {
|
||||
o.Cache.DefaultNamespaces = map[string]cache.Config{newObj.CacheNamespace: {}}
|
||||
}
|
||||
|
||||
if o.Metrics.BindAddress == "" && newObj.Metrics.BindAddress != "" {
|
||||
o.Metrics.BindAddress = newObj.Metrics.BindAddress
|
||||
}
|
||||
|
||||
if o.HealthProbeBindAddress == "" && newObj.Health.HealthProbeBindAddress != "" {
|
||||
o.HealthProbeBindAddress = newObj.Health.HealthProbeBindAddress
|
||||
}
|
||||
|
||||
if o.ReadinessEndpointName == "" && newObj.Health.ReadinessEndpointName != "" {
|
||||
o.ReadinessEndpointName = newObj.Health.ReadinessEndpointName
|
||||
}
|
||||
|
||||
if o.LivenessEndpointName == "" && newObj.Health.LivenessEndpointName != "" {
|
||||
o.LivenessEndpointName = newObj.Health.LivenessEndpointName
|
||||
}
|
||||
|
||||
if o.WebhookServer == nil {
|
||||
port := 0
|
||||
if newObj.Webhook.Port != nil {
|
||||
port = *newObj.Webhook.Port
|
||||
}
|
||||
o.WebhookServer = webhook.NewServer(webhook.Options{
|
||||
Port: port,
|
||||
Host: newObj.Webhook.Host,
|
||||
CertDir: newObj.Webhook.CertDir,
|
||||
})
|
||||
}
|
||||
|
||||
if newObj.Controller != nil {
|
||||
if o.Controller.CacheSyncTimeout == 0 && newObj.Controller.CacheSyncTimeout != nil {
|
||||
o.Controller.CacheSyncTimeout = *newObj.Controller.CacheSyncTimeout
|
||||
}
|
||||
|
||||
if len(o.Controller.GroupKindConcurrency) == 0 && len(newObj.Controller.GroupKindConcurrency) > 0 {
|
||||
o.Controller.GroupKindConcurrency = newObj.Controller.GroupKindConcurrency
|
||||
}
|
||||
}
|
||||
|
||||
return o, nil
|
||||
}
|
||||
|
||||
// AndFromOrDie will use options.AndFrom() and will panic if there are errors.
|
||||
//
|
||||
// Deprecated: This function has been deprecated and will be removed in a future release,
|
||||
// The Component Configuration package has been unmaintained for over a year and is no longer
|
||||
// actively developed. Users should migrate to their own configuration format
|
||||
// and configure Manager.Options directly.
|
||||
// See https://github.com/kubernetes-sigs/controller-runtime/issues/895
|
||||
// for more information, feedback, and comments.
|
||||
func (o Options) AndFromOrDie(loader config.ControllerManagerConfiguration) Options {
|
||||
o, err := o.AndFrom(loader)
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("could not parse config file: %v", err))
|
||||
}
|
||||
return o
|
||||
}
|
||||
|
||||
func (o Options) setLeaderElectionConfig(obj v1alpha1.ControllerManagerConfigurationSpec) Options {
|
||||
if obj.LeaderElection == nil {
|
||||
// The source does not have any configuration; noop
|
||||
return o
|
||||
}
|
||||
|
||||
if !o.LeaderElection && obj.LeaderElection.LeaderElect != nil {
|
||||
o.LeaderElection = *obj.LeaderElection.LeaderElect
|
||||
}
|
||||
|
||||
if o.LeaderElectionResourceLock == "" && obj.LeaderElection.ResourceLock != "" {
|
||||
o.LeaderElectionResourceLock = obj.LeaderElection.ResourceLock
|
||||
}
|
||||
|
||||
if o.LeaderElectionNamespace == "" && obj.LeaderElection.ResourceNamespace != "" {
|
||||
o.LeaderElectionNamespace = obj.LeaderElection.ResourceNamespace
|
||||
}
|
||||
|
||||
if o.LeaderElectionID == "" && obj.LeaderElection.ResourceName != "" {
|
||||
o.LeaderElectionID = obj.LeaderElection.ResourceName
|
||||
}
|
||||
|
||||
if o.LeaseDuration == nil && !reflect.DeepEqual(obj.LeaderElection.LeaseDuration, metav1.Duration{}) {
|
||||
o.LeaseDuration = &obj.LeaderElection.LeaseDuration.Duration
|
||||
}
|
||||
|
||||
if o.RenewDeadline == nil && !reflect.DeepEqual(obj.LeaderElection.RenewDeadline, metav1.Duration{}) {
|
||||
o.RenewDeadline = &obj.LeaderElection.RenewDeadline.Duration
|
||||
}
|
||||
|
||||
if o.RetryPeriod == nil && !reflect.DeepEqual(obj.LeaderElection.RetryPeriod, metav1.Duration{}) {
|
||||
o.RetryPeriod = &obj.LeaderElection.RetryPeriod.Duration
|
||||
}
|
||||
|
||||
return o
|
||||
}
|
||||
|
||||
// defaultHealthProbeListener creates the default health probes listener bound to the given address.
|
||||
func defaultHealthProbeListener(addr string) (net.Listener, error) {
|
||||
if addr == "" || addr == "0" {
|
||||
|
||||
20
vendor/sigs.k8s.io/controller-runtime/pkg/manager/runnable_group.go
generated
vendored
20
vendor/sigs.k8s.io/controller-runtime/pkg/manager/runnable_group.go
generated
vendored
@@ -54,7 +54,10 @@ func newRunnables(baseContext BaseContextFunc, errChan chan error) *runnables {
|
||||
// The runnables added after Start are started directly.
|
||||
func (r *runnables) Add(fn Runnable) error {
|
||||
switch runnable := fn.(type) {
|
||||
case *server:
|
||||
case *Server:
|
||||
if runnable.NeedLeaderElection() {
|
||||
return r.LeaderElection.Add(fn, nil)
|
||||
}
|
||||
return r.HTTPServers.Add(fn, nil)
|
||||
case hasCache:
|
||||
return r.Caches.Add(fn, func(ctx context.Context) bool {
|
||||
@@ -263,6 +266,15 @@ func (r *runnableGroup) Add(rn Runnable, ready runnableCheck) error {
|
||||
r.start.Unlock()
|
||||
}
|
||||
|
||||
// Recheck if we're stopped and hold the readlock, given that the stop and start can be called
|
||||
// at the same time, we can end up in a situation where the runnable is added
|
||||
// after the group is stopped and the channel is closed.
|
||||
r.stop.RLock()
|
||||
defer r.stop.RUnlock()
|
||||
if r.stopped {
|
||||
return errRunnableGroupStopped
|
||||
}
|
||||
|
||||
// Enqueue the runnable.
|
||||
r.ch <- readyRunnable
|
||||
return nil
|
||||
@@ -272,7 +284,11 @@ func (r *runnableGroup) Add(rn Runnable, ready runnableCheck) error {
|
||||
func (r *runnableGroup) StopAndWait(ctx context.Context) {
|
||||
r.stopOnce.Do(func() {
|
||||
// Close the reconciler channel once we're done.
|
||||
defer close(r.ch)
|
||||
defer func() {
|
||||
r.stop.Lock()
|
||||
close(r.ch)
|
||||
r.stop.Unlock()
|
||||
}()
|
||||
|
||||
_ = r.Start(ctx)
|
||||
r.stop.Lock()
|
||||
|
||||
74
vendor/sigs.k8s.io/controller-runtime/pkg/manager/server.go
generated
vendored
74
vendor/sigs.k8s.io/controller-runtime/pkg/manager/server.go
generated
vendored
@@ -21,34 +21,67 @@ import (
|
||||
"errors"
|
||||
"net"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/go-logr/logr"
|
||||
crlog "sigs.k8s.io/controller-runtime/pkg/log"
|
||||
)
|
||||
|
||||
// server is a general purpose HTTP server Runnable for a manager
|
||||
// to serve some internal handlers such as health probes, metrics and profiling.
|
||||
type server struct {
|
||||
Kind string
|
||||
Log logr.Logger
|
||||
Server *http.Server
|
||||
var (
|
||||
_ Runnable = (*Server)(nil)
|
||||
_ LeaderElectionRunnable = (*Server)(nil)
|
||||
)
|
||||
|
||||
// Server is a general purpose HTTP server Runnable for a manager.
|
||||
// It is used to serve some internal handlers for health probes and profiling,
|
||||
// but it can also be used to run custom servers.
|
||||
type Server struct {
|
||||
// Name is an optional string that describes the purpose of the server. It is used in logs to distinguish
|
||||
// among multiple servers.
|
||||
Name string
|
||||
|
||||
// Server is the HTTP server to run. It is required.
|
||||
Server *http.Server
|
||||
|
||||
// Listener is an optional listener to use. If not set, the server start a listener using the server.Addr.
|
||||
// Using a listener is useful when the port reservation needs to happen in advance of this runnable starting.
|
||||
Listener net.Listener
|
||||
|
||||
// OnlyServeWhenLeader is an optional bool that indicates that the server should only be started when the manager is the leader.
|
||||
OnlyServeWhenLeader bool
|
||||
|
||||
// ShutdownTimeout is an optional duration that indicates how long to wait for the server to shutdown gracefully. If not set,
|
||||
// the server will wait indefinitely for all connections to close.
|
||||
ShutdownTimeout *time.Duration
|
||||
}
|
||||
|
||||
func (s *server) Start(ctx context.Context) error {
|
||||
log := s.Log.WithValues("kind", s.Kind, "addr", s.Listener.Addr())
|
||||
// Start starts the server. It will block until the server is stopped or an error occurs.
|
||||
func (s *Server) Start(ctx context.Context) error {
|
||||
log := crlog.FromContext(ctx)
|
||||
if s.Name != "" {
|
||||
log = log.WithValues("name", s.Name)
|
||||
}
|
||||
log = log.WithValues("addr", s.addr())
|
||||
|
||||
serverShutdown := make(chan struct{})
|
||||
go func() {
|
||||
<-ctx.Done()
|
||||
log.Info("shutting down server")
|
||||
if err := s.Server.Shutdown(context.Background()); err != nil {
|
||||
|
||||
shutdownCtx := context.Background()
|
||||
if s.ShutdownTimeout != nil {
|
||||
var shutdownCancel context.CancelFunc
|
||||
shutdownCtx, shutdownCancel = context.WithTimeout(context.Background(), *s.ShutdownTimeout)
|
||||
defer shutdownCancel()
|
||||
}
|
||||
|
||||
if err := s.Server.Shutdown(shutdownCtx); err != nil {
|
||||
log.Error(err, "error shutting down server")
|
||||
}
|
||||
close(serverShutdown)
|
||||
}()
|
||||
|
||||
log.Info("starting server")
|
||||
if err := s.Server.Serve(s.Listener); err != nil && !errors.Is(err, http.ErrServerClosed) {
|
||||
if err := s.serve(); err != nil && !errors.Is(err, http.ErrServerClosed) {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -56,6 +89,21 @@ func (s *server) Start(ctx context.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *server) NeedLeaderElection() bool {
|
||||
return false
|
||||
// NeedLeaderElection returns true if the server should only be started when the manager is the leader.
|
||||
func (s *Server) NeedLeaderElection() bool {
|
||||
return s.OnlyServeWhenLeader
|
||||
}
|
||||
|
||||
func (s *Server) addr() string {
|
||||
if s.Listener != nil {
|
||||
return s.Listener.Addr().String()
|
||||
}
|
||||
return s.Server.Addr
|
||||
}
|
||||
|
||||
func (s *Server) serve() error {
|
||||
if s.Listener != nil {
|
||||
return s.Server.Serve(s.Listener)
|
||||
}
|
||||
return s.Server.ListenAndServe()
|
||||
}
|
||||
|
||||
23
vendor/sigs.k8s.io/controller-runtime/pkg/metrics/leaderelection.go
generated
vendored
23
vendor/sigs.k8s.io/controller-runtime/pkg/metrics/leaderelection.go
generated
vendored
@@ -14,6 +14,11 @@ var (
|
||||
Name: "leader_election_master_status",
|
||||
Help: "Gauge of if the reporting system is master of the relevant lease, 0 indicates backup, 1 indicates master. 'name' is the string used to identify the lease. Please make sure to group by name.",
|
||||
}, []string{"name"})
|
||||
|
||||
leaderSlowpathCounter = prometheus.NewCounterVec(prometheus.CounterOpts{
|
||||
Name: "leader_election_slowpath_total",
|
||||
Help: "Total number of slow path exercised in renewing leader leases. 'name' is the string used to identify the lease. Please make sure to group by name.",
|
||||
}, []string{"name"})
|
||||
)
|
||||
|
||||
func init() {
|
||||
@@ -23,18 +28,20 @@ func init() {
|
||||
|
||||
type leaderelectionMetricsProvider struct{}
|
||||
|
||||
func (leaderelectionMetricsProvider) NewLeaderMetric() leaderelection.SwitchMetric {
|
||||
return &switchAdapter{gauge: leaderGauge}
|
||||
func (leaderelectionMetricsProvider) NewLeaderMetric() leaderelection.LeaderMetric {
|
||||
return leaderElectionPrometheusAdapter{}
|
||||
}
|
||||
|
||||
type switchAdapter struct {
|
||||
gauge *prometheus.GaugeVec
|
||||
type leaderElectionPrometheusAdapter struct{}
|
||||
|
||||
func (s leaderElectionPrometheusAdapter) On(name string) {
|
||||
leaderGauge.WithLabelValues(name).Set(1.0)
|
||||
}
|
||||
|
||||
func (s *switchAdapter) On(name string) {
|
||||
s.gauge.WithLabelValues(name).Set(1.0)
|
||||
func (s leaderElectionPrometheusAdapter) Off(name string) {
|
||||
leaderGauge.WithLabelValues(name).Set(0.0)
|
||||
}
|
||||
|
||||
func (s *switchAdapter) Off(name string) {
|
||||
s.gauge.WithLabelValues(name).Set(0.0)
|
||||
func (leaderElectionPrometheusAdapter) SlowpathExercised(name string) {
|
||||
leaderSlowpathCounter.WithLabelValues(name).Inc()
|
||||
}
|
||||
|
||||
32
vendor/sigs.k8s.io/controller-runtime/pkg/metrics/server/server.go
generated
vendored
32
vendor/sigs.k8s.io/controller-runtime/pkg/metrics/server/server.go
generated
vendored
@@ -46,6 +46,9 @@ var DefaultBindAddress = ":8080"
|
||||
|
||||
// Server is a server that serves metrics.
|
||||
type Server interface {
|
||||
// AddExtraHandler adds extra handler served on path to the http server that serves metrics.
|
||||
AddExtraHandler(path string, handler http.Handler) error
|
||||
|
||||
// NeedLeaderElection implements the LeaderElectionRunnable interface, which indicates
|
||||
// the metrics server doesn't need leader election.
|
||||
NeedLeaderElection() bool
|
||||
@@ -101,6 +104,9 @@ type Options struct {
|
||||
// TLSOpts is used to allow configuring the TLS config used for the server.
|
||||
// This also allows providing a certificate via GetCertificate.
|
||||
TLSOpts []func(*tls.Config)
|
||||
|
||||
// ListenConfig contains options for listening to an address on the metric server.
|
||||
ListenConfig net.ListenConfig
|
||||
}
|
||||
|
||||
// Filter is a func that is added around metrics and extra handlers on the metrics server.
|
||||
@@ -179,6 +185,23 @@ func (*defaultServer) NeedLeaderElection() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// AddExtraHandler adds extra handler served on path to the http server that serves metrics.
|
||||
func (s *defaultServer) AddExtraHandler(path string, handler http.Handler) error {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
if s.options.ExtraHandlers == nil {
|
||||
s.options.ExtraHandlers = make(map[string]http.Handler)
|
||||
}
|
||||
if path == defaultMetricsEndpoint {
|
||||
return fmt.Errorf("overriding builtin %s endpoint is not allowed", defaultMetricsEndpoint)
|
||||
}
|
||||
if _, found := s.options.ExtraHandlers[path]; found {
|
||||
return fmt.Errorf("can't register extra handler by duplicate path %q on metrics http server", path)
|
||||
}
|
||||
s.options.ExtraHandlers[path] = handler
|
||||
return nil
|
||||
}
|
||||
|
||||
// Start runs the server.
|
||||
// It will install the metrics related resources depend on the server configuration.
|
||||
func (s *defaultServer) Start(ctx context.Context) error {
|
||||
@@ -249,7 +272,7 @@ func (s *defaultServer) Start(ctx context.Context) error {
|
||||
|
||||
func (s *defaultServer) createListener(ctx context.Context, log logr.Logger) (net.Listener, error) {
|
||||
if !s.options.SecureServing {
|
||||
return net.Listen("tcp", s.options.BindAddress)
|
||||
return s.options.ListenConfig.Listen(ctx, "tcp", s.options.BindAddress)
|
||||
}
|
||||
|
||||
cfg := &tls.Config{ //nolint:gosec
|
||||
@@ -302,7 +325,12 @@ func (s *defaultServer) createListener(ctx context.Context, log logr.Logger) (ne
|
||||
cfg.Certificates = []tls.Certificate{keyPair}
|
||||
}
|
||||
|
||||
return tls.Listen("tcp", s.options.BindAddress, cfg)
|
||||
l, err := s.options.ListenConfig.Listen(ctx, "tcp", s.options.BindAddress)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return tls.NewListener(l, cfg), nil
|
||||
}
|
||||
|
||||
func (s *defaultServer) GetBindAddr() string {
|
||||
|
||||
28
vendor/sigs.k8s.io/controller-runtime/pkg/metrics/workqueue.go
generated
vendored
28
vendor/sigs.k8s.io/controller-runtime/pkg/metrics/workqueue.go
generated
vendored
@@ -42,27 +42,27 @@ var (
|
||||
Subsystem: WorkQueueSubsystem,
|
||||
Name: DepthKey,
|
||||
Help: "Current depth of workqueue",
|
||||
}, []string{"name"})
|
||||
}, []string{"name", "controller"})
|
||||
|
||||
adds = prometheus.NewCounterVec(prometheus.CounterOpts{
|
||||
Subsystem: WorkQueueSubsystem,
|
||||
Name: AddsKey,
|
||||
Help: "Total number of adds handled by workqueue",
|
||||
}, []string{"name"})
|
||||
}, []string{"name", "controller"})
|
||||
|
||||
latency = prometheus.NewHistogramVec(prometheus.HistogramOpts{
|
||||
Subsystem: WorkQueueSubsystem,
|
||||
Name: QueueLatencyKey,
|
||||
Help: "How long in seconds an item stays in workqueue before being requested",
|
||||
Buckets: prometheus.ExponentialBuckets(10e-9, 10, 12),
|
||||
}, []string{"name"})
|
||||
}, []string{"name", "controller"})
|
||||
|
||||
workDuration = prometheus.NewHistogramVec(prometheus.HistogramOpts{
|
||||
Subsystem: WorkQueueSubsystem,
|
||||
Name: WorkDurationKey,
|
||||
Help: "How long in seconds processing an item from workqueue takes.",
|
||||
Buckets: prometheus.ExponentialBuckets(10e-9, 10, 12),
|
||||
}, []string{"name"})
|
||||
}, []string{"name", "controller"})
|
||||
|
||||
unfinished = prometheus.NewGaugeVec(prometheus.GaugeOpts{
|
||||
Subsystem: WorkQueueSubsystem,
|
||||
@@ -71,20 +71,20 @@ var (
|
||||
"is in progress and hasn't been observed by work_duration. Large " +
|
||||
"values indicate stuck threads. One can deduce the number of stuck " +
|
||||
"threads by observing the rate at which this increases.",
|
||||
}, []string{"name"})
|
||||
}, []string{"name", "controller"})
|
||||
|
||||
longestRunningProcessor = prometheus.NewGaugeVec(prometheus.GaugeOpts{
|
||||
Subsystem: WorkQueueSubsystem,
|
||||
Name: LongestRunningProcessorKey,
|
||||
Help: "How many seconds has the longest running " +
|
||||
"processor for workqueue been running.",
|
||||
}, []string{"name"})
|
||||
}, []string{"name", "controller"})
|
||||
|
||||
retries = prometheus.NewCounterVec(prometheus.CounterOpts{
|
||||
Subsystem: WorkQueueSubsystem,
|
||||
Name: RetriesKey,
|
||||
Help: "Total number of retries handled by workqueue",
|
||||
}, []string{"name"})
|
||||
}, []string{"name", "controller"})
|
||||
)
|
||||
|
||||
func init() {
|
||||
@@ -102,29 +102,29 @@ func init() {
|
||||
type workqueueMetricsProvider struct{}
|
||||
|
||||
func (workqueueMetricsProvider) NewDepthMetric(name string) workqueue.GaugeMetric {
|
||||
return depth.WithLabelValues(name)
|
||||
return depth.WithLabelValues(name, name)
|
||||
}
|
||||
|
||||
func (workqueueMetricsProvider) NewAddsMetric(name string) workqueue.CounterMetric {
|
||||
return adds.WithLabelValues(name)
|
||||
return adds.WithLabelValues(name, name)
|
||||
}
|
||||
|
||||
func (workqueueMetricsProvider) NewLatencyMetric(name string) workqueue.HistogramMetric {
|
||||
return latency.WithLabelValues(name)
|
||||
return latency.WithLabelValues(name, name)
|
||||
}
|
||||
|
||||
func (workqueueMetricsProvider) NewWorkDurationMetric(name string) workqueue.HistogramMetric {
|
||||
return workDuration.WithLabelValues(name)
|
||||
return workDuration.WithLabelValues(name, name)
|
||||
}
|
||||
|
||||
func (workqueueMetricsProvider) NewUnfinishedWorkSecondsMetric(name string) workqueue.SettableGaugeMetric {
|
||||
return unfinished.WithLabelValues(name)
|
||||
return unfinished.WithLabelValues(name, name)
|
||||
}
|
||||
|
||||
func (workqueueMetricsProvider) NewLongestRunningProcessorSecondsMetric(name string) workqueue.SettableGaugeMetric {
|
||||
return longestRunningProcessor.WithLabelValues(name)
|
||||
return longestRunningProcessor.WithLabelValues(name, name)
|
||||
}
|
||||
|
||||
func (workqueueMetricsProvider) NewRetriesMetric(name string) workqueue.CounterMetric {
|
||||
return retries.WithLabelValues(name)
|
||||
return retries.WithLabelValues(name, name)
|
||||
}
|
||||
|
||||
192
vendor/sigs.k8s.io/controller-runtime/pkg/predicate/predicate.go
generated
vendored
192
vendor/sigs.k8s.io/controller-runtime/pkg/predicate/predicate.go
generated
vendored
@@ -17,6 +17,7 @@ limitations under the License.
|
||||
package predicate
|
||||
|
||||
import (
|
||||
"maps"
|
||||
"reflect"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
@@ -29,45 +30,51 @@ import (
|
||||
var log = logf.RuntimeLog.WithName("predicate").WithName("eventFilters")
|
||||
|
||||
// Predicate filters events before enqueuing the keys.
|
||||
type Predicate interface {
|
||||
type Predicate = TypedPredicate[client.Object]
|
||||
|
||||
// TypedPredicate filters events before enqueuing the keys.
|
||||
type TypedPredicate[object any] interface {
|
||||
// Create returns true if the Create event should be processed
|
||||
Create(event.CreateEvent) bool
|
||||
Create(event.TypedCreateEvent[object]) bool
|
||||
|
||||
// Delete returns true if the Delete event should be processed
|
||||
Delete(event.DeleteEvent) bool
|
||||
Delete(event.TypedDeleteEvent[object]) bool
|
||||
|
||||
// Update returns true if the Update event should be processed
|
||||
Update(event.UpdateEvent) bool
|
||||
Update(event.TypedUpdateEvent[object]) bool
|
||||
|
||||
// Generic returns true if the Generic event should be processed
|
||||
Generic(event.GenericEvent) bool
|
||||
Generic(event.TypedGenericEvent[object]) bool
|
||||
}
|
||||
|
||||
var _ Predicate = Funcs{}
|
||||
var _ Predicate = ResourceVersionChangedPredicate{}
|
||||
var _ Predicate = GenerationChangedPredicate{}
|
||||
var _ Predicate = AnnotationChangedPredicate{}
|
||||
var _ Predicate = or{}
|
||||
var _ Predicate = and{}
|
||||
var _ Predicate = not{}
|
||||
var _ Predicate = or[client.Object]{}
|
||||
var _ Predicate = and[client.Object]{}
|
||||
var _ Predicate = not[client.Object]{}
|
||||
|
||||
// Funcs is a function that implements Predicate.
|
||||
type Funcs struct {
|
||||
type Funcs = TypedFuncs[client.Object]
|
||||
|
||||
// TypedFuncs is a function that implements TypedPredicate.
|
||||
type TypedFuncs[object any] struct {
|
||||
// Create returns true if the Create event should be processed
|
||||
CreateFunc func(event.CreateEvent) bool
|
||||
CreateFunc func(event.TypedCreateEvent[object]) bool
|
||||
|
||||
// Delete returns true if the Delete event should be processed
|
||||
DeleteFunc func(event.DeleteEvent) bool
|
||||
DeleteFunc func(event.TypedDeleteEvent[object]) bool
|
||||
|
||||
// Update returns true if the Update event should be processed
|
||||
UpdateFunc func(event.UpdateEvent) bool
|
||||
UpdateFunc func(event.TypedUpdateEvent[object]) bool
|
||||
|
||||
// Generic returns true if the Generic event should be processed
|
||||
GenericFunc func(event.GenericEvent) bool
|
||||
GenericFunc func(event.TypedGenericEvent[object]) bool
|
||||
}
|
||||
|
||||
// Create implements Predicate.
|
||||
func (p Funcs) Create(e event.CreateEvent) bool {
|
||||
func (p TypedFuncs[object]) Create(e event.TypedCreateEvent[object]) bool {
|
||||
if p.CreateFunc != nil {
|
||||
return p.CreateFunc(e)
|
||||
}
|
||||
@@ -75,7 +82,7 @@ func (p Funcs) Create(e event.CreateEvent) bool {
|
||||
}
|
||||
|
||||
// Delete implements Predicate.
|
||||
func (p Funcs) Delete(e event.DeleteEvent) bool {
|
||||
func (p TypedFuncs[object]) Delete(e event.TypedDeleteEvent[object]) bool {
|
||||
if p.DeleteFunc != nil {
|
||||
return p.DeleteFunc(e)
|
||||
}
|
||||
@@ -83,7 +90,7 @@ func (p Funcs) Delete(e event.DeleteEvent) bool {
|
||||
}
|
||||
|
||||
// Update implements Predicate.
|
||||
func (p Funcs) Update(e event.UpdateEvent) bool {
|
||||
func (p TypedFuncs[object]) Update(e event.TypedUpdateEvent[object]) bool {
|
||||
if p.UpdateFunc != nil {
|
||||
return p.UpdateFunc(e)
|
||||
}
|
||||
@@ -91,7 +98,7 @@ func (p Funcs) Update(e event.UpdateEvent) bool {
|
||||
}
|
||||
|
||||
// Generic implements Predicate.
|
||||
func (p Funcs) Generic(e event.GenericEvent) bool {
|
||||
func (p TypedFuncs[object]) Generic(e event.TypedGenericEvent[object]) bool {
|
||||
if p.GenericFunc != nil {
|
||||
return p.GenericFunc(e)
|
||||
}
|
||||
@@ -118,18 +125,41 @@ func NewPredicateFuncs(filter func(object client.Object) bool) Funcs {
|
||||
}
|
||||
}
|
||||
|
||||
// NewTypedPredicateFuncs returns a predicate funcs that applies the given filter function
|
||||
// on CREATE, UPDATE, DELETE and GENERIC events. For UPDATE events, the filter is applied
|
||||
// to the new object.
|
||||
func NewTypedPredicateFuncs[object any](filter func(object object) bool) TypedFuncs[object] {
|
||||
return TypedFuncs[object]{
|
||||
CreateFunc: func(e event.TypedCreateEvent[object]) bool {
|
||||
return filter(e.Object)
|
||||
},
|
||||
UpdateFunc: func(e event.TypedUpdateEvent[object]) bool {
|
||||
return filter(e.ObjectNew)
|
||||
},
|
||||
DeleteFunc: func(e event.TypedDeleteEvent[object]) bool {
|
||||
return filter(e.Object)
|
||||
},
|
||||
GenericFunc: func(e event.TypedGenericEvent[object]) bool {
|
||||
return filter(e.Object)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// ResourceVersionChangedPredicate implements a default update predicate function on resource version change.
|
||||
type ResourceVersionChangedPredicate struct {
|
||||
Funcs
|
||||
type ResourceVersionChangedPredicate = TypedResourceVersionChangedPredicate[client.Object]
|
||||
|
||||
// TypedResourceVersionChangedPredicate implements a default update predicate function on resource version change.
|
||||
type TypedResourceVersionChangedPredicate[T metav1.Object] struct {
|
||||
TypedFuncs[T]
|
||||
}
|
||||
|
||||
// Update implements default UpdateEvent filter for validating resource version change.
|
||||
func (ResourceVersionChangedPredicate) Update(e event.UpdateEvent) bool {
|
||||
if e.ObjectOld == nil {
|
||||
func (TypedResourceVersionChangedPredicate[T]) Update(e event.TypedUpdateEvent[T]) bool {
|
||||
if isNil(e.ObjectOld) {
|
||||
log.Error(nil, "Update event has no old object to update", "event", e)
|
||||
return false
|
||||
}
|
||||
if e.ObjectNew == nil {
|
||||
if isNil(e.ObjectNew) {
|
||||
log.Error(nil, "Update event has no new object to update", "event", e)
|
||||
return false
|
||||
}
|
||||
@@ -153,17 +183,35 @@ func (ResourceVersionChangedPredicate) Update(e event.UpdateEvent) bool {
|
||||
//
|
||||
// * With this predicate, any update events with writes only to the status field will not be reconciled.
|
||||
// So in the event that the status block is overwritten or wiped by someone else the controller will not self-correct to restore the correct status.
|
||||
type GenerationChangedPredicate struct {
|
||||
Funcs
|
||||
type GenerationChangedPredicate = TypedGenerationChangedPredicate[client.Object]
|
||||
|
||||
// TypedGenerationChangedPredicate implements a default update predicate function on Generation change.
|
||||
//
|
||||
// This predicate will skip update events that have no change in the object's metadata.generation field.
|
||||
// The metadata.generation field of an object is incremented by the API server when writes are made to the spec field of an object.
|
||||
// This allows a controller to ignore update events where the spec is unchanged, and only the metadata and/or status fields are changed.
|
||||
//
|
||||
// For CustomResource objects the Generation is only incremented when the status subresource is enabled.
|
||||
//
|
||||
// Caveats:
|
||||
//
|
||||
// * The assumption that the Generation is incremented only on writing to the spec does not hold for all APIs.
|
||||
// E.g For Deployment objects the Generation is also incremented on writes to the metadata.annotations field.
|
||||
// For object types other than CustomResources be sure to verify which fields will trigger a Generation increment when they are written to.
|
||||
//
|
||||
// * With this predicate, any update events with writes only to the status field will not be reconciled.
|
||||
// So in the event that the status block is overwritten or wiped by someone else the controller will not self-correct to restore the correct status.
|
||||
type TypedGenerationChangedPredicate[object metav1.Object] struct {
|
||||
TypedFuncs[object]
|
||||
}
|
||||
|
||||
// Update implements default UpdateEvent filter for validating generation change.
|
||||
func (GenerationChangedPredicate) Update(e event.UpdateEvent) bool {
|
||||
if e.ObjectOld == nil {
|
||||
func (TypedGenerationChangedPredicate[object]) Update(e event.TypedUpdateEvent[object]) bool {
|
||||
if isNil(e.ObjectOld) {
|
||||
log.Error(nil, "Update event has no old object to update", "event", e)
|
||||
return false
|
||||
}
|
||||
if e.ObjectNew == nil {
|
||||
if isNil(e.ObjectNew) {
|
||||
log.Error(nil, "Update event has no new object for update", "event", e)
|
||||
return false
|
||||
}
|
||||
@@ -183,22 +231,25 @@ func (GenerationChangedPredicate) Update(e event.UpdateEvent) bool {
|
||||
//
|
||||
// This is mostly useful for controllers that needs to trigger both when the resource's generation is incremented
|
||||
// (i.e., when the resource' .spec changes), or an annotation changes (e.g., for a staging/alpha API).
|
||||
type AnnotationChangedPredicate struct {
|
||||
Funcs
|
||||
type AnnotationChangedPredicate = TypedAnnotationChangedPredicate[client.Object]
|
||||
|
||||
// TypedAnnotationChangedPredicate implements a default update predicate function on annotation change.
|
||||
type TypedAnnotationChangedPredicate[object metav1.Object] struct {
|
||||
TypedFuncs[object]
|
||||
}
|
||||
|
||||
// Update implements default UpdateEvent filter for validating annotation change.
|
||||
func (AnnotationChangedPredicate) Update(e event.UpdateEvent) bool {
|
||||
if e.ObjectOld == nil {
|
||||
func (TypedAnnotationChangedPredicate[object]) Update(e event.TypedUpdateEvent[object]) bool {
|
||||
if isNil(e.ObjectOld) {
|
||||
log.Error(nil, "Update event has no old object to update", "event", e)
|
||||
return false
|
||||
}
|
||||
if e.ObjectNew == nil {
|
||||
if isNil(e.ObjectNew) {
|
||||
log.Error(nil, "Update event has no new object for update", "event", e)
|
||||
return false
|
||||
}
|
||||
|
||||
return !reflect.DeepEqual(e.ObjectNew.GetAnnotations(), e.ObjectOld.GetAnnotations())
|
||||
return !maps.Equal(e.ObjectNew.GetAnnotations(), e.ObjectOld.GetAnnotations())
|
||||
}
|
||||
|
||||
// LabelChangedPredicate implements a default update predicate function on label change.
|
||||
@@ -214,34 +265,37 @@ func (AnnotationChangedPredicate) Update(e event.UpdateEvent) bool {
|
||||
//
|
||||
// This will be helpful when object's labels is carrying some extra specification information beyond object's spec,
|
||||
// and the controller will be triggered if any valid spec change (not only in spec, but also in labels) happens.
|
||||
type LabelChangedPredicate struct {
|
||||
Funcs
|
||||
type LabelChangedPredicate = TypedLabelChangedPredicate[client.Object]
|
||||
|
||||
// TypedLabelChangedPredicate implements a default update predicate function on label change.
|
||||
type TypedLabelChangedPredicate[object metav1.Object] struct {
|
||||
TypedFuncs[object]
|
||||
}
|
||||
|
||||
// Update implements default UpdateEvent filter for checking label change.
|
||||
func (LabelChangedPredicate) Update(e event.UpdateEvent) bool {
|
||||
if e.ObjectOld == nil {
|
||||
func (TypedLabelChangedPredicate[object]) Update(e event.TypedUpdateEvent[object]) bool {
|
||||
if isNil(e.ObjectOld) {
|
||||
log.Error(nil, "Update event has no old object to update", "event", e)
|
||||
return false
|
||||
}
|
||||
if e.ObjectNew == nil {
|
||||
if isNil(e.ObjectNew) {
|
||||
log.Error(nil, "Update event has no new object for update", "event", e)
|
||||
return false
|
||||
}
|
||||
|
||||
return !reflect.DeepEqual(e.ObjectNew.GetLabels(), e.ObjectOld.GetLabels())
|
||||
return !maps.Equal(e.ObjectNew.GetLabels(), e.ObjectOld.GetLabels())
|
||||
}
|
||||
|
||||
// And returns a composite predicate that implements a logical AND of the predicates passed to it.
|
||||
func And(predicates ...Predicate) Predicate {
|
||||
return and{predicates}
|
||||
func And[object any](predicates ...TypedPredicate[object]) TypedPredicate[object] {
|
||||
return and[object]{predicates}
|
||||
}
|
||||
|
||||
type and struct {
|
||||
predicates []Predicate
|
||||
type and[object any] struct {
|
||||
predicates []TypedPredicate[object]
|
||||
}
|
||||
|
||||
func (a and) Create(e event.CreateEvent) bool {
|
||||
func (a and[object]) Create(e event.TypedCreateEvent[object]) bool {
|
||||
for _, p := range a.predicates {
|
||||
if !p.Create(e) {
|
||||
return false
|
||||
@@ -250,7 +304,7 @@ func (a and) Create(e event.CreateEvent) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (a and) Update(e event.UpdateEvent) bool {
|
||||
func (a and[object]) Update(e event.TypedUpdateEvent[object]) bool {
|
||||
for _, p := range a.predicates {
|
||||
if !p.Update(e) {
|
||||
return false
|
||||
@@ -259,7 +313,7 @@ func (a and) Update(e event.UpdateEvent) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (a and) Delete(e event.DeleteEvent) bool {
|
||||
func (a and[object]) Delete(e event.TypedDeleteEvent[object]) bool {
|
||||
for _, p := range a.predicates {
|
||||
if !p.Delete(e) {
|
||||
return false
|
||||
@@ -268,7 +322,7 @@ func (a and) Delete(e event.DeleteEvent) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (a and) Generic(e event.GenericEvent) bool {
|
||||
func (a and[object]) Generic(e event.TypedGenericEvent[object]) bool {
|
||||
for _, p := range a.predicates {
|
||||
if !p.Generic(e) {
|
||||
return false
|
||||
@@ -278,15 +332,15 @@ func (a and) Generic(e event.GenericEvent) bool {
|
||||
}
|
||||
|
||||
// Or returns a composite predicate that implements a logical OR of the predicates passed to it.
|
||||
func Or(predicates ...Predicate) Predicate {
|
||||
return or{predicates}
|
||||
func Or[object any](predicates ...TypedPredicate[object]) TypedPredicate[object] {
|
||||
return or[object]{predicates}
|
||||
}
|
||||
|
||||
type or struct {
|
||||
predicates []Predicate
|
||||
type or[object any] struct {
|
||||
predicates []TypedPredicate[object]
|
||||
}
|
||||
|
||||
func (o or) Create(e event.CreateEvent) bool {
|
||||
func (o or[object]) Create(e event.TypedCreateEvent[object]) bool {
|
||||
for _, p := range o.predicates {
|
||||
if p.Create(e) {
|
||||
return true
|
||||
@@ -295,7 +349,7 @@ func (o or) Create(e event.CreateEvent) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (o or) Update(e event.UpdateEvent) bool {
|
||||
func (o or[object]) Update(e event.TypedUpdateEvent[object]) bool {
|
||||
for _, p := range o.predicates {
|
||||
if p.Update(e) {
|
||||
return true
|
||||
@@ -304,7 +358,7 @@ func (o or) Update(e event.UpdateEvent) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (o or) Delete(e event.DeleteEvent) bool {
|
||||
func (o or[object]) Delete(e event.TypedDeleteEvent[object]) bool {
|
||||
for _, p := range o.predicates {
|
||||
if p.Delete(e) {
|
||||
return true
|
||||
@@ -313,7 +367,7 @@ func (o or) Delete(e event.DeleteEvent) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (o or) Generic(e event.GenericEvent) bool {
|
||||
func (o or[object]) Generic(e event.TypedGenericEvent[object]) bool {
|
||||
for _, p := range o.predicates {
|
||||
if p.Generic(e) {
|
||||
return true
|
||||
@@ -323,27 +377,27 @@ func (o or) Generic(e event.GenericEvent) bool {
|
||||
}
|
||||
|
||||
// Not returns a predicate that implements a logical NOT of the predicate passed to it.
|
||||
func Not(predicate Predicate) Predicate {
|
||||
return not{predicate}
|
||||
func Not[object any](predicate TypedPredicate[object]) TypedPredicate[object] {
|
||||
return not[object]{predicate}
|
||||
}
|
||||
|
||||
type not struct {
|
||||
predicate Predicate
|
||||
type not[object any] struct {
|
||||
predicate TypedPredicate[object]
|
||||
}
|
||||
|
||||
func (n not) Create(e event.CreateEvent) bool {
|
||||
func (n not[object]) Create(e event.TypedCreateEvent[object]) bool {
|
||||
return !n.predicate.Create(e)
|
||||
}
|
||||
|
||||
func (n not) Update(e event.UpdateEvent) bool {
|
||||
func (n not[object]) Update(e event.TypedUpdateEvent[object]) bool {
|
||||
return !n.predicate.Update(e)
|
||||
}
|
||||
|
||||
func (n not) Delete(e event.DeleteEvent) bool {
|
||||
func (n not[object]) Delete(e event.TypedDeleteEvent[object]) bool {
|
||||
return !n.predicate.Delete(e)
|
||||
}
|
||||
|
||||
func (n not) Generic(e event.GenericEvent) bool {
|
||||
func (n not[object]) Generic(e event.TypedGenericEvent[object]) bool {
|
||||
return !n.predicate.Generic(e)
|
||||
}
|
||||
|
||||
@@ -358,3 +412,15 @@ func LabelSelectorPredicate(s metav1.LabelSelector) (Predicate, error) {
|
||||
return selector.Matches(labels.Set(o.GetLabels()))
|
||||
}), nil
|
||||
}
|
||||
|
||||
func isNil(arg any) bool {
|
||||
if v := reflect.ValueOf(arg); !v.IsValid() || ((v.Kind() == reflect.Ptr ||
|
||||
v.Kind() == reflect.Interface ||
|
||||
v.Kind() == reflect.Slice ||
|
||||
v.Kind() == reflect.Map ||
|
||||
v.Kind() == reflect.Chan ||
|
||||
v.Kind() == reflect.Func) && v.IsNil()) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
30
vendor/sigs.k8s.io/controller-runtime/pkg/ratelimiter/ratelimiter.go
generated
vendored
30
vendor/sigs.k8s.io/controller-runtime/pkg/ratelimiter/ratelimiter.go
generated
vendored
@@ -1,30 +0,0 @@
|
||||
/*
|
||||
Copyright 2020 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 ratelimiter
|
||||
|
||||
import "time"
|
||||
|
||||
// RateLimiter is an identical interface of client-go workqueue RateLimiter.
|
||||
type RateLimiter interface {
|
||||
// When gets an item and gets to decide how long that item should wait
|
||||
When(item interface{}) time.Duration
|
||||
// Forget indicates that an item is finished being retried. Doesn't matter whether its for perm failing
|
||||
// or for success, we'll stop tracking it
|
||||
Forget(item interface{})
|
||||
// NumRequeues returns back how many failures the item has had
|
||||
NumRequeues(item interface{}) int
|
||||
}
|
||||
36
vendor/sigs.k8s.io/controller-runtime/pkg/reconcile/reconcile.go
generated
vendored
36
vendor/sigs.k8s.io/controller-runtime/pkg/reconcile/reconcile.go
generated
vendored
@@ -89,7 +89,14 @@ driven by actual cluster state read from the apiserver or a local cache.
|
||||
For example if responding to a Pod Delete Event, the Request won't contain that a Pod was deleted,
|
||||
instead the reconcile function observes this when reading the cluster state and seeing the Pod as missing.
|
||||
*/
|
||||
type Reconciler interface {
|
||||
type Reconciler = TypedReconciler[Request]
|
||||
|
||||
// TypedReconciler implements an API for a specific Resource by Creating, Updating or Deleting Kubernetes
|
||||
// objects, or by making changes to systems external to the cluster (e.g. cloudproviders, github, etc).
|
||||
//
|
||||
// The request type is what event handlers put into the workqueue. The workqueue then de-duplicates identical
|
||||
// requests.
|
||||
type TypedReconciler[request comparable] interface {
|
||||
// Reconcile performs a full reconciliation for the object referred to by the Request.
|
||||
//
|
||||
// If the returned error is non-nil, the Result is ignored and the request will be
|
||||
@@ -101,40 +108,45 @@ type Reconciler interface {
|
||||
//
|
||||
// If the error is nil and result.RequeueAfter is zero and result.Requeue is true, the request
|
||||
// will be requeued using exponential backoff.
|
||||
Reconcile(context.Context, Request) (Result, error)
|
||||
Reconcile(context.Context, request) (Result, error)
|
||||
}
|
||||
|
||||
// Func is a function that implements the reconcile interface.
|
||||
type Func func(context.Context, Request) (Result, error)
|
||||
type Func = TypedFunc[Request]
|
||||
|
||||
// TypedFunc is a function that implements the reconcile interface.
|
||||
type TypedFunc[request comparable] func(context.Context, request) (Result, error)
|
||||
|
||||
var _ Reconciler = Func(nil)
|
||||
|
||||
// Reconcile implements Reconciler.
|
||||
func (r Func) Reconcile(ctx context.Context, o Request) (Result, error) { return r(ctx, o) }
|
||||
func (r TypedFunc[request]) Reconcile(ctx context.Context, req request) (Result, error) {
|
||||
return r(ctx, req)
|
||||
}
|
||||
|
||||
// ObjectReconciler is a specialized version of Reconciler that acts on instances of client.Object. Each reconciliation
|
||||
// event gets the associated object from Kubernetes before passing it to Reconcile. An ObjectReconciler can be used in
|
||||
// Builder.Complete by calling AsReconciler. See Reconciler for more details.
|
||||
type ObjectReconciler[T client.Object] interface {
|
||||
Reconcile(context.Context, T) (Result, error)
|
||||
type ObjectReconciler[object client.Object] interface {
|
||||
Reconcile(context.Context, object) (Result, error)
|
||||
}
|
||||
|
||||
// AsReconciler creates a Reconciler based on the given ObjectReconciler.
|
||||
func AsReconciler[T client.Object](client client.Client, rec ObjectReconciler[T]) Reconciler {
|
||||
return &objectReconcilerAdapter[T]{
|
||||
func AsReconciler[object client.Object](client client.Client, rec ObjectReconciler[object]) Reconciler {
|
||||
return &objectReconcilerAdapter[object]{
|
||||
objReconciler: rec,
|
||||
client: client,
|
||||
}
|
||||
}
|
||||
|
||||
type objectReconcilerAdapter[T client.Object] struct {
|
||||
objReconciler ObjectReconciler[T]
|
||||
type objectReconcilerAdapter[object client.Object] struct {
|
||||
objReconciler ObjectReconciler[object]
|
||||
client client.Client
|
||||
}
|
||||
|
||||
// Reconcile implements Reconciler.
|
||||
func (a *objectReconcilerAdapter[T]) Reconcile(ctx context.Context, req Request) (Result, error) {
|
||||
o := reflect.New(reflect.TypeOf(*new(T)).Elem()).Interface().(T)
|
||||
func (a *objectReconcilerAdapter[object]) Reconcile(ctx context.Context, req Request) (Result, error) {
|
||||
o := reflect.New(reflect.TypeOf(*new(object)).Elem()).Interface().(object)
|
||||
if err := a.client.Get(ctx, req.NamespacedName, o); err != nil {
|
||||
return Result{}, client.IgnoreNotFound(err)
|
||||
}
|
||||
|
||||
188
vendor/sigs.k8s.io/controller-runtime/pkg/source/source.go
generated
vendored
188
vendor/sigs.k8s.io/controller-runtime/pkg/source/source.go
generated
vendored
@@ -18,94 +18,174 @@ package source
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"sync"
|
||||
|
||||
"k8s.io/client-go/util/workqueue"
|
||||
"k8s.io/utils/ptr"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
"sigs.k8s.io/controller-runtime/pkg/event"
|
||||
"sigs.k8s.io/controller-runtime/pkg/handler"
|
||||
internal "sigs.k8s.io/controller-runtime/pkg/internal/source"
|
||||
"sigs.k8s.io/controller-runtime/pkg/reconcile"
|
||||
|
||||
"sigs.k8s.io/controller-runtime/pkg/cache"
|
||||
"sigs.k8s.io/controller-runtime/pkg/predicate"
|
||||
)
|
||||
|
||||
const (
|
||||
// defaultBufferSize is the default number of event notifications that can be buffered.
|
||||
defaultBufferSize = 1024
|
||||
)
|
||||
|
||||
// Source is a source of events (eh.g. Create, Update, Delete operations on Kubernetes Objects, Webhook callbacks, etc)
|
||||
// Source is a source of events (e.g. Create, Update, Delete operations on Kubernetes Objects, Webhook callbacks, etc)
|
||||
// which should be processed by event.EventHandlers to enqueue reconcile.Requests.
|
||||
//
|
||||
// * Use Kind for events originating in the cluster (e.g. Pod Create, Pod Update, Deployment Update).
|
||||
//
|
||||
// * Use Channel for events originating outside the cluster (eh.g. GitHub Webhook callback, Polling external urls).
|
||||
// * Use Channel for events originating outside the cluster (e.g. GitHub Webhook callback, Polling external urls).
|
||||
//
|
||||
// Users may build their own Source implementations.
|
||||
type Source interface {
|
||||
// Start is internal and should be called only by the Controller to register an EventHandler with the Informer
|
||||
// to enqueue reconcile.Requests.
|
||||
Start(context.Context, handler.EventHandler, workqueue.RateLimitingInterface, ...predicate.Predicate) error
|
||||
type Source = TypedSource[reconcile.Request]
|
||||
|
||||
// TypedSource is a generic source of events (e.g. Create, Update, Delete operations on Kubernetes Objects, Webhook callbacks, etc)
|
||||
// which should be processed by event.EventHandlers to enqueue a request.
|
||||
//
|
||||
// * Use Kind for events originating in the cluster (e.g. Pod Create, Pod Update, Deployment Update).
|
||||
//
|
||||
// * Use Channel for events originating outside the cluster (e.g. GitHub Webhook callback, Polling external urls).
|
||||
//
|
||||
// Users may build their own Source implementations.
|
||||
type TypedSource[request comparable] interface {
|
||||
// Start is internal and should be called only by the Controller to start the source.
|
||||
// Start must be non-blocking.
|
||||
Start(context.Context, workqueue.TypedRateLimitingInterface[request]) error
|
||||
}
|
||||
|
||||
// SyncingSource is a source that needs syncing prior to being usable. The controller
|
||||
// will call its WaitForSync prior to starting workers.
|
||||
type SyncingSource interface {
|
||||
Source
|
||||
type SyncingSource = TypedSyncingSource[reconcile.Request]
|
||||
|
||||
// TypedSyncingSource is a source that needs syncing prior to being usable. The controller
|
||||
// will call its WaitForSync prior to starting workers.
|
||||
type TypedSyncingSource[request comparable] interface {
|
||||
TypedSource[request]
|
||||
WaitForSync(ctx context.Context) error
|
||||
}
|
||||
|
||||
// Kind creates a KindSource with the given cache provider.
|
||||
func Kind(cache cache.Cache, object client.Object) SyncingSource {
|
||||
return &internal.Kind{Type: object, Cache: cache}
|
||||
func Kind[object client.Object](
|
||||
cache cache.Cache,
|
||||
obj object,
|
||||
handler handler.TypedEventHandler[object, reconcile.Request],
|
||||
predicates ...predicate.TypedPredicate[object],
|
||||
) SyncingSource {
|
||||
return TypedKind(cache, obj, handler, predicates...)
|
||||
}
|
||||
|
||||
var _ Source = &Channel{}
|
||||
// TypedKind creates a KindSource with the given cache provider.
|
||||
func TypedKind[object client.Object, request comparable](
|
||||
cache cache.Cache,
|
||||
obj object,
|
||||
handler handler.TypedEventHandler[object, request],
|
||||
predicates ...predicate.TypedPredicate[object],
|
||||
) TypedSyncingSource[request] {
|
||||
return &internal.Kind[object, request]{
|
||||
Type: obj,
|
||||
Cache: cache,
|
||||
Handler: handler,
|
||||
Predicates: predicates,
|
||||
}
|
||||
}
|
||||
|
||||
var _ Source = &channel[string, reconcile.Request]{}
|
||||
|
||||
// ChannelOpt allows to configure a source.Channel.
|
||||
type ChannelOpt[object any, request comparable] func(*channel[object, request])
|
||||
|
||||
// WithPredicates adds the configured predicates to a source.Channel.
|
||||
func WithPredicates[object any, request comparable](p ...predicate.TypedPredicate[object]) ChannelOpt[object, request] {
|
||||
return func(c *channel[object, request]) {
|
||||
c.predicates = append(c.predicates, p...)
|
||||
}
|
||||
}
|
||||
|
||||
// WithBufferSize configures the buffer size for a source.Channel. By
|
||||
// default, the buffer size is 1024.
|
||||
func WithBufferSize[object any, request comparable](bufferSize int) ChannelOpt[object, request] {
|
||||
return func(c *channel[object, request]) {
|
||||
c.bufferSize = &bufferSize
|
||||
}
|
||||
}
|
||||
|
||||
// Channel is used to provide a source of events originating outside the cluster
|
||||
// (e.g. GitHub Webhook callback). Channel requires the user to wire the external
|
||||
// source (eh.g. http handler) to write GenericEvents to the underlying channel.
|
||||
type Channel struct {
|
||||
// source (e.g. http handler) to write GenericEvents to the underlying channel.
|
||||
func Channel[object any](
|
||||
source <-chan event.TypedGenericEvent[object],
|
||||
handler handler.TypedEventHandler[object, reconcile.Request],
|
||||
opts ...ChannelOpt[object, reconcile.Request],
|
||||
) Source {
|
||||
return TypedChannel[object, reconcile.Request](source, handler, opts...)
|
||||
}
|
||||
|
||||
// TypedChannel is used to provide a source of events originating outside the cluster
|
||||
// (e.g. GitHub Webhook callback). Channel requires the user to wire the external
|
||||
// source (e.g. http handler) to write GenericEvents to the underlying channel.
|
||||
func TypedChannel[object any, request comparable](
|
||||
source <-chan event.TypedGenericEvent[object],
|
||||
handler handler.TypedEventHandler[object, request],
|
||||
opts ...ChannelOpt[object, request],
|
||||
) TypedSource[request] {
|
||||
c := &channel[object, request]{
|
||||
source: source,
|
||||
handler: handler,
|
||||
}
|
||||
for _, opt := range opts {
|
||||
opt(c)
|
||||
}
|
||||
|
||||
return c
|
||||
}
|
||||
|
||||
type channel[object any, request comparable] struct {
|
||||
// once ensures the event distribution goroutine will be performed only once
|
||||
once sync.Once
|
||||
|
||||
// Source is the source channel to fetch GenericEvents
|
||||
Source <-chan event.GenericEvent
|
||||
// source is the source channel to fetch GenericEvents
|
||||
source <-chan event.TypedGenericEvent[object]
|
||||
|
||||
handler handler.TypedEventHandler[object, request]
|
||||
|
||||
predicates []predicate.TypedPredicate[object]
|
||||
|
||||
bufferSize *int
|
||||
|
||||
// dest is the destination channels of the added event handlers
|
||||
dest []chan event.GenericEvent
|
||||
|
||||
// DestBufferSize is the specified buffer size of dest channels.
|
||||
// Default to 1024 if not specified.
|
||||
DestBufferSize int
|
||||
dest []chan event.TypedGenericEvent[object]
|
||||
|
||||
// destLock is to ensure the destination channels are safely added/removed
|
||||
destLock sync.Mutex
|
||||
}
|
||||
|
||||
func (cs *Channel) String() string {
|
||||
func (cs *channel[object, request]) String() string {
|
||||
return fmt.Sprintf("channel source: %p", cs)
|
||||
}
|
||||
|
||||
// Start implements Source and should only be called by the Controller.
|
||||
func (cs *Channel) Start(
|
||||
func (cs *channel[object, request]) Start(
|
||||
ctx context.Context,
|
||||
handler handler.EventHandler,
|
||||
queue workqueue.RateLimitingInterface,
|
||||
prct ...predicate.Predicate) error {
|
||||
queue workqueue.TypedRateLimitingInterface[request],
|
||||
) error {
|
||||
// Source should have been specified by the user.
|
||||
if cs.Source == nil {
|
||||
if cs.source == nil {
|
||||
return fmt.Errorf("must specify Channel.Source")
|
||||
}
|
||||
|
||||
// use default value if DestBufferSize not specified
|
||||
if cs.DestBufferSize == 0 {
|
||||
cs.DestBufferSize = defaultBufferSize
|
||||
if cs.handler == nil {
|
||||
return errors.New("must specify Channel.Handler")
|
||||
}
|
||||
|
||||
dst := make(chan event.GenericEvent, cs.DestBufferSize)
|
||||
if cs.bufferSize == nil {
|
||||
cs.bufferSize = ptr.To(1024)
|
||||
}
|
||||
|
||||
dst := make(chan event.TypedGenericEvent[object], *cs.bufferSize)
|
||||
|
||||
cs.destLock.Lock()
|
||||
cs.dest = append(cs.dest, dst)
|
||||
@@ -119,7 +199,7 @@ func (cs *Channel) Start(
|
||||
go func() {
|
||||
for evt := range dst {
|
||||
shouldHandle := true
|
||||
for _, p := range prct {
|
||||
for _, p := range cs.predicates {
|
||||
if !p.Generic(evt) {
|
||||
shouldHandle = false
|
||||
break
|
||||
@@ -130,7 +210,7 @@ func (cs *Channel) Start(
|
||||
func() {
|
||||
ctx, cancel := context.WithCancel(ctx)
|
||||
defer cancel()
|
||||
handler.Generic(ctx, evt, queue)
|
||||
cs.handler.Generic(ctx, evt, queue)
|
||||
}()
|
||||
}
|
||||
}
|
||||
@@ -139,7 +219,7 @@ func (cs *Channel) Start(
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cs *Channel) doStop() {
|
||||
func (cs *channel[object, request]) doStop() {
|
||||
cs.destLock.Lock()
|
||||
defer cs.destLock.Unlock()
|
||||
|
||||
@@ -148,7 +228,7 @@ func (cs *Channel) doStop() {
|
||||
}
|
||||
}
|
||||
|
||||
func (cs *Channel) distribute(evt event.GenericEvent) {
|
||||
func (cs *channel[object, request]) distribute(evt event.TypedGenericEvent[object]) {
|
||||
cs.destLock.Lock()
|
||||
defer cs.destLock.Unlock()
|
||||
|
||||
@@ -162,14 +242,14 @@ func (cs *Channel) distribute(evt event.GenericEvent) {
|
||||
}
|
||||
}
|
||||
|
||||
func (cs *Channel) syncLoop(ctx context.Context) {
|
||||
func (cs *channel[object, request]) syncLoop(ctx context.Context) {
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
// Close destination channels
|
||||
cs.doStop()
|
||||
return
|
||||
case evt, stillOpen := <-cs.Source:
|
||||
case evt, stillOpen := <-cs.source:
|
||||
if !stillOpen {
|
||||
// if the source channel is closed, we're never gonna get
|
||||
// anything more on it, so stop & bail
|
||||
@@ -184,21 +264,25 @@ func (cs *Channel) syncLoop(ctx context.Context) {
|
||||
// Informer is used to provide a source of events originating inside the cluster from Watches (e.g. Pod Create).
|
||||
type Informer struct {
|
||||
// Informer is the controller-runtime Informer
|
||||
Informer cache.Informer
|
||||
Informer cache.Informer
|
||||
Handler handler.EventHandler
|
||||
Predicates []predicate.Predicate
|
||||
}
|
||||
|
||||
var _ Source = &Informer{}
|
||||
|
||||
// Start is internal and should be called only by the Controller to register an EventHandler with the Informer
|
||||
// to enqueue reconcile.Requests.
|
||||
func (is *Informer) Start(ctx context.Context, handler handler.EventHandler, queue workqueue.RateLimitingInterface,
|
||||
prct ...predicate.Predicate) error {
|
||||
func (is *Informer) Start(ctx context.Context, queue workqueue.TypedRateLimitingInterface[reconcile.Request]) error {
|
||||
// Informer should have been specified by the user.
|
||||
if is.Informer == nil {
|
||||
return fmt.Errorf("must specify Informer.Informer")
|
||||
}
|
||||
if is.Handler == nil {
|
||||
return errors.New("must specify Informer.Handler")
|
||||
}
|
||||
|
||||
_, err := is.Informer.AddEventHandler(internal.NewEventHandler(ctx, queue, handler, prct).HandlerFuncs())
|
||||
_, err := is.Informer.AddEventHandler(internal.NewEventHandler(ctx, queue, is.Handler, is.Predicates).HandlerFuncs())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -212,14 +296,16 @@ func (is *Informer) String() string {
|
||||
var _ Source = Func(nil)
|
||||
|
||||
// Func is a function that implements Source.
|
||||
type Func func(context.Context, handler.EventHandler, workqueue.RateLimitingInterface, ...predicate.Predicate) error
|
||||
type Func = TypedFunc[reconcile.Request]
|
||||
|
||||
// TypedFunc is a function that implements Source.
|
||||
type TypedFunc[request comparable] func(context.Context, workqueue.TypedRateLimitingInterface[request]) error
|
||||
|
||||
// Start implements Source.
|
||||
func (f Func) Start(ctx context.Context, evt handler.EventHandler, queue workqueue.RateLimitingInterface,
|
||||
pr ...predicate.Predicate) error {
|
||||
return f(ctx, evt, queue, pr...)
|
||||
func (f TypedFunc[request]) Start(ctx context.Context, queue workqueue.TypedRateLimitingInterface[request]) error {
|
||||
return f(ctx, queue)
|
||||
}
|
||||
|
||||
func (f Func) String() string {
|
||||
func (f TypedFunc[request]) String() string {
|
||||
return fmt.Sprintf("func source: %p", f)
|
||||
}
|
||||
|
||||
25
vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/decode.go
generated
vendored
25
vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/decode.go
generated
vendored
@@ -26,22 +26,35 @@ import (
|
||||
|
||||
// Decoder knows how to decode the contents of an admission
|
||||
// request into a concrete object.
|
||||
type Decoder struct {
|
||||
type Decoder interface {
|
||||
// Decode decodes the inlined object in the AdmissionRequest into the passed-in runtime.Object.
|
||||
// If you want decode the OldObject in the AdmissionRequest, use DecodeRaw.
|
||||
// It errors out if req.Object.Raw is empty i.e. containing 0 raw bytes.
|
||||
Decode(req Request, into runtime.Object) error
|
||||
|
||||
// DecodeRaw decodes a RawExtension object into the passed-in runtime.Object.
|
||||
// It errors out if rawObj is empty i.e. containing 0 raw bytes.
|
||||
DecodeRaw(rawObj runtime.RawExtension, into runtime.Object) error
|
||||
}
|
||||
|
||||
// decoder knows how to decode the contents of an admission
|
||||
// request into a concrete object.
|
||||
type decoder struct {
|
||||
codecs serializer.CodecFactory
|
||||
}
|
||||
|
||||
// NewDecoder creates a Decoder given the runtime.Scheme.
|
||||
func NewDecoder(scheme *runtime.Scheme) *Decoder {
|
||||
// NewDecoder creates a decoder given the runtime.Scheme.
|
||||
func NewDecoder(scheme *runtime.Scheme) Decoder {
|
||||
if scheme == nil {
|
||||
panic("scheme should never be nil")
|
||||
}
|
||||
return &Decoder{codecs: serializer.NewCodecFactory(scheme)}
|
||||
return &decoder{codecs: serializer.NewCodecFactory(scheme)}
|
||||
}
|
||||
|
||||
// Decode decodes the inlined object in the AdmissionRequest into the passed-in runtime.Object.
|
||||
// If you want decode the OldObject in the AdmissionRequest, use DecodeRaw.
|
||||
// It errors out if req.Object.Raw is empty i.e. containing 0 raw bytes.
|
||||
func (d *Decoder) Decode(req Request, into runtime.Object) error {
|
||||
func (d *decoder) Decode(req Request, into runtime.Object) error {
|
||||
// we error out if rawObj is an empty object.
|
||||
if len(req.Object.Raw) == 0 {
|
||||
return fmt.Errorf("there is no content to decode")
|
||||
@@ -51,7 +64,7 @@ func (d *Decoder) Decode(req Request, into runtime.Object) error {
|
||||
|
||||
// DecodeRaw decodes a RawExtension object into the passed-in runtime.Object.
|
||||
// It errors out if rawObj is empty i.e. containing 0 raw bytes.
|
||||
func (d *Decoder) DecodeRaw(rawObj runtime.RawExtension, into runtime.Object) error {
|
||||
func (d *decoder) DecodeRaw(rawObj runtime.RawExtension, into runtime.Object) error {
|
||||
// NB(directxman12): there's a bug/weird interaction between decoders and
|
||||
// the API server where the API server doesn't send a GVK on the embedded
|
||||
// objects, which means the unstructured decoder refuses to decode. It
|
||||
|
||||
2
vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/defaulter.go
generated
vendored
2
vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/defaulter.go
generated
vendored
@@ -43,7 +43,7 @@ func DefaultingWebhookFor(scheme *runtime.Scheme, defaulter Defaulter) *Webhook
|
||||
|
||||
type mutatingHandler struct {
|
||||
defaulter Defaulter
|
||||
decoder *Decoder
|
||||
decoder Decoder
|
||||
}
|
||||
|
||||
// Handle handles admission requests.
|
||||
|
||||
2
vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/defaulter_custom.go
generated
vendored
2
vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/defaulter_custom.go
generated
vendored
@@ -43,7 +43,7 @@ func WithCustomDefaulter(scheme *runtime.Scheme, obj runtime.Object, defaulter C
|
||||
type defaulterForType struct {
|
||||
defaulter CustomDefaulter
|
||||
object runtime.Object
|
||||
decoder *Decoder
|
||||
decoder Decoder
|
||||
}
|
||||
|
||||
// Handle handles admission requests.
|
||||
|
||||
39
vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/metrics/metrics.go
generated
vendored
Normal file
39
vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/metrics/metrics.go
generated
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
package metrics
|
||||
|
||||
import (
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"sigs.k8s.io/controller-runtime/pkg/metrics"
|
||||
)
|
||||
|
||||
var (
|
||||
// WebhookPanics is a prometheus counter metrics which holds the total
|
||||
// number of panics from webhooks.
|
||||
WebhookPanics = prometheus.NewCounterVec(prometheus.CounterOpts{
|
||||
Name: "controller_runtime_webhook_panics_total",
|
||||
Help: "Total number of webhook panics",
|
||||
}, []string{})
|
||||
)
|
||||
|
||||
func init() {
|
||||
metrics.Registry.MustRegister(
|
||||
WebhookPanics,
|
||||
)
|
||||
// Init metric.
|
||||
WebhookPanics.WithLabelValues().Add(0)
|
||||
}
|
||||
2
vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/validator.go
generated
vendored
2
vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/validator.go
generated
vendored
@@ -63,7 +63,7 @@ func ValidatingWebhookFor(scheme *runtime.Scheme, validator Validator) *Webhook
|
||||
|
||||
type validatingHandler struct {
|
||||
validator Validator
|
||||
decoder *Decoder
|
||||
decoder Decoder
|
||||
}
|
||||
|
||||
// Handle handles admission requests.
|
||||
|
||||
2
vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/validator_custom.go
generated
vendored
2
vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/validator_custom.go
generated
vendored
@@ -56,7 +56,7 @@ func WithCustomValidator(scheme *runtime.Scheme, obj runtime.Object, validator C
|
||||
type validatorForType struct {
|
||||
validator CustomValidator
|
||||
object runtime.Object
|
||||
decoder *Decoder
|
||||
decoder Decoder
|
||||
}
|
||||
|
||||
// Handle handles admission requests.
|
||||
|
||||
33
vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/webhook.go
generated
vendored
33
vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/webhook.go
generated
vendored
@@ -30,6 +30,7 @@ import (
|
||||
"k8s.io/apimachinery/pkg/util/json"
|
||||
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
|
||||
"k8s.io/klog/v2"
|
||||
admissionmetrics "sigs.k8s.io/controller-runtime/pkg/webhook/admission/metrics"
|
||||
|
||||
logf "sigs.k8s.io/controller-runtime/pkg/log"
|
||||
"sigs.k8s.io/controller-runtime/pkg/webhook/internal/metrics"
|
||||
@@ -123,7 +124,8 @@ type Webhook struct {
|
||||
Handler Handler
|
||||
|
||||
// RecoverPanic indicates whether the panic caused by webhook should be recovered.
|
||||
RecoverPanic bool
|
||||
// Defaults to true.
|
||||
RecoverPanic *bool
|
||||
|
||||
// WithContextFunc will allow you to take the http.Request.Context() and
|
||||
// add any additional information such as passing the request path or
|
||||
@@ -141,8 +143,9 @@ type Webhook struct {
|
||||
}
|
||||
|
||||
// WithRecoverPanic takes a bool flag which indicates whether the panic caused by webhook should be recovered.
|
||||
// Defaults to true.
|
||||
func (wh *Webhook) WithRecoverPanic(recoverPanic bool) *Webhook {
|
||||
wh.RecoverPanic = recoverPanic
|
||||
wh.RecoverPanic = &recoverPanic
|
||||
return wh
|
||||
}
|
||||
|
||||
@@ -151,17 +154,26 @@ func (wh *Webhook) WithRecoverPanic(recoverPanic bool) *Webhook {
|
||||
// If the webhook is validating type, it delegates the AdmissionRequest to each handler and
|
||||
// deny the request if anyone denies.
|
||||
func (wh *Webhook) Handle(ctx context.Context, req Request) (response Response) {
|
||||
if wh.RecoverPanic {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
admissionmetrics.WebhookPanics.WithLabelValues().Inc()
|
||||
|
||||
if wh.RecoverPanic == nil || *wh.RecoverPanic {
|
||||
for _, fn := range utilruntime.PanicHandlers {
|
||||
fn(r)
|
||||
fn(ctx, r)
|
||||
}
|
||||
response = Errored(http.StatusInternalServerError, fmt.Errorf("panic: %v [recovered]", r))
|
||||
// Note: We explicitly have to set the response UID. Usually that is done via resp.Complete below,
|
||||
// but if we encounter a panic in wh.Handler.Handle we are never going to reach resp.Complete.
|
||||
response.UID = req.UID
|
||||
return
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
log := logf.FromContext(ctx)
|
||||
log.Info(fmt.Sprintf("Observed a panic in webhook: %v", r))
|
||||
panic(r)
|
||||
}
|
||||
}()
|
||||
|
||||
reqLog := wh.getLogger(&req)
|
||||
ctx = logf.IntoContext(ctx, reqLog)
|
||||
@@ -169,7 +181,10 @@ func (wh *Webhook) Handle(ctx context.Context, req Request) (response Response)
|
||||
resp := wh.Handler.Handle(ctx, req)
|
||||
if err := resp.Complete(req); err != nil {
|
||||
reqLog.Error(err, "unable to encode response")
|
||||
return Errored(http.StatusInternalServerError, errUnableToEncodeResponse)
|
||||
resp := Errored(http.StatusInternalServerError, errUnableToEncodeResponse)
|
||||
// Note: We explicitly have to set the response UID. Usually that is done via resp.Complete.
|
||||
resp.UID = req.UID
|
||||
return resp
|
||||
}
|
||||
|
||||
return resp
|
||||
|
||||
2
vendor/sigs.k8s.io/controller-tools/pkg/crd/flatten.go
generated
vendored
2
vendor/sigs.k8s.io/controller-tools/pkg/crd/flatten.go
generated
vendored
@@ -147,6 +147,8 @@ func flattenAllOfInto(dst *apiext.JSONSchemaProps, src apiext.JSONSchemaProps, e
|
||||
dstField.Set(srcField)
|
||||
case "XMapType":
|
||||
dstField.Set(srcField)
|
||||
case "XValidations":
|
||||
dstField.Set(reflect.AppendSlice(srcField, dstField))
|
||||
// NB(directxman12): no need to explicitly handle nullable -- false is considered to be the zero value
|
||||
// TODO(directxman12): src isn't necessarily the field value -- it's just the most recent allOf entry
|
||||
default:
|
||||
|
||||
41
vendor/sigs.k8s.io/controller-tools/pkg/crd/gen.go
generated
vendored
41
vendor/sigs.k8s.io/controller-tools/pkg/crd/gen.go
generated
vendored
@@ -85,6 +85,20 @@ type Generator struct {
|
||||
|
||||
// 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 {
|
||||
@@ -100,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)
|
||||
@@ -146,6 +170,14 @@ func (g Generator) Generate(ctx *genall.GenerationContext) error {
|
||||
}
|
||||
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]
|
||||
@@ -171,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, headerText, []interface{}{crd}, genall.WithTransform(transformRemoveCRDStatus), genall.WithTransform(genall.TransformRemoveCreationTimestamp)); err != nil {
|
||||
if err := ctx.WriteYAML(fileName, headerText, []interface{}{crd}, yamlOpts...); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@@ -194,7 +226,6 @@ func removeDescriptionFromMetadataProps(v *apiext.JSONSchemaProps) {
|
||||
if meta.Description != "" {
|
||||
meta.Description = ""
|
||||
v.Properties["metadata"] = m
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
20
vendor/sigs.k8s.io/controller-tools/pkg/crd/known_types.go
generated
vendored
20
vendor/sigs.k8s.io/controller-tools/pkg/crd/known_types.go
generated
vendored
@@ -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"
|
||||
)
|
||||
@@ -24,15 +25,6 @@ import (
|
||||
// KnownPackages overrides types in some comment packages that have custom validation
|
||||
// but don't have validation markers on them (since they're from core Kubernetes).
|
||||
var KnownPackages = map[string]PackageOverride{
|
||||
"k8s.io/api/core/v1": func(p *Parser, pkg *loader.Package) {
|
||||
// Explicit defaulting for the corev1.Protocol type in lieu of https://github.com/kubernetes/enhancements/pull/1928
|
||||
p.Schemata[TypeIdent{Name: "Protocol", Package: pkg}] = apiext.JSONSchemaProps{
|
||||
Type: "string",
|
||||
Default: &apiext.JSON{Raw: []byte(`"TCP"`)},
|
||||
}
|
||||
p.AddPackage(pkg)
|
||||
},
|
||||
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1": func(p *Parser, pkg *loader.Package) {
|
||||
p.Schemata[TypeIdent{Name: "ObjectMeta", Package: pkg}] = apiext.JSONSchemaProps{
|
||||
Type: "object",
|
||||
@@ -75,7 +67,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 +92,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 +151,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
|
||||
|
||||
32
vendor/sigs.k8s.io/controller-tools/pkg/crd/markers/crd.go
generated
vendored
32
vendor/sigs.k8s.io/controller-tools/pkg/crd/markers/crd.go
generated
vendored
@@ -55,6 +55,9 @@ var CRDMarkers = []*definitionWithHelp{
|
||||
|
||||
must(markers.MakeDefinition("kubebuilder:metadata", markers.DescribesType, Metadata{})).
|
||||
WithHelp(Metadata{}.Help()),
|
||||
|
||||
must(markers.MakeDefinition("kubebuilder:selectablefield", markers.DescribesType, SelectableField{})).
|
||||
WithHelp(SelectableField{}.Help()),
|
||||
}
|
||||
|
||||
// TODO: categories and singular used to be annotations types
|
||||
@@ -388,3 +391,32 @@ func (s Metadata) ApplyToCRD(crd *apiext.CustomResourceDefinition, _ string) err
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// +controllertools:marker:generateHelp:category=CRD
|
||||
|
||||
// SelectableField adds a field that may be used with field selectors.
|
||||
type SelectableField struct {
|
||||
// JSONPath specifies the jsonpath expression which is used to produce a field selector value.
|
||||
JSONPath string `marker:"JSONPath"`
|
||||
}
|
||||
|
||||
func (s SelectableField) ApplyToCRD(crd *apiext.CustomResourceDefinitionSpec, version string) error {
|
||||
var selectableFields *[]apiext.SelectableField
|
||||
for i := range crd.Versions {
|
||||
ver := &crd.Versions[i]
|
||||
if ver.Name != version {
|
||||
continue
|
||||
}
|
||||
selectableFields = &ver.SelectableFields
|
||||
break
|
||||
}
|
||||
if selectableFields == nil {
|
||||
return fmt.Errorf("selectable field applied to version %q not in CRD", version)
|
||||
}
|
||||
|
||||
*selectableFields = append(*selectableFields, apiext.SelectableField{
|
||||
JSONPath: s.JSONPath,
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
17
vendor/sigs.k8s.io/controller-tools/pkg/crd/markers/doc.go
generated
vendored
17
vendor/sigs.k8s.io/controller-tools/pkg/crd/markers/doc.go
generated
vendored
@@ -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.
|
||||
|
||||
2
vendor/sigs.k8s.io/controller-tools/pkg/crd/markers/package.go
generated
vendored
2
vendor/sigs.k8s.io/controller-tools/pkg/crd/markers/package.go
generated
vendored
@@ -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, "")).
|
||||
|
||||
37
vendor/sigs.k8s.io/controller-tools/pkg/crd/markers/priority.go
generated
vendored
Normal file
37
vendor/sigs.k8s.io/controller-tools/pkg/crd/markers/priority.go
generated
vendored
Normal file
@@ -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
|
||||
}
|
||||
24
vendor/sigs.k8s.io/controller-tools/pkg/crd/markers/register.go
generated
vendored
24
vendor/sigs.k8s.io/controller-tools/pkg/crd/markers/register.go
generated
vendored
@@ -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)
|
||||
|
||||
4
vendor/sigs.k8s.io/controller-tools/pkg/crd/markers/topology.go
generated
vendored
4
vendor/sigs.k8s.io/controller-tools/pkg/crd/markers/topology.go
generated
vendored
@@ -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" {
|
||||
|
||||
123
vendor/sigs.k8s.io/controller-tools/pkg/crd/markers/validation.go
generated
vendored
123
vendor/sigs.k8s.io/controller-tools/pkg/crd/markers/validation.go
generated
vendored
@@ -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,21 @@ 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()),
|
||||
@@ -110,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...)
|
||||
@@ -225,6 +243,20 @@ 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.
|
||||
//
|
||||
@@ -266,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{}
|
||||
|
||||
@@ -295,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 {
|
||||
@@ -464,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
|
||||
@@ -484,6 +521,39 @@ func (m Default) ApplyToSchema(schema *apiext.JSONSchemaProps) error {
|
||||
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
|
||||
}
|
||||
schema.Default = &apiext.JSON{Raw: marshalledDefault}
|
||||
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 {
|
||||
@@ -512,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
|
||||
}
|
||||
|
||||
146
vendor/sigs.k8s.io/controller-tools/pkg/crd/markers/zz_generated.markerhelp.go
generated
vendored
146
vendor/sigs.k8s.io/controller-tools/pkg/crd/markers/zz_generated.markerhelp.go
generated
vendored
@@ -28,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": {
|
||||
@@ -71,8 +71,8 @@ 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 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.",
|
||||
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": {
|
||||
@@ -109,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{},
|
||||
}
|
||||
@@ -131,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\nPossible data-structure types of a list are:\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 - \"set\": Fields need to be \"scalar\", and there can be only one\n occurrence of each.\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{},
|
||||
}
|
||||
@@ -142,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\nPossible values:\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 - \"atomic\": all fields are treated as one unit.\n Any changes have to replace the entire map.",
|
||||
},
|
||||
FieldHelp: map[string]markers.DetailedHelp{},
|
||||
}
|
||||
@@ -197,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": {
|
||||
@@ -272,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{},
|
||||
@@ -303,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.",
|
||||
@@ -315,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.",
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -335,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.",
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -362,19 +378,35 @@ 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{},
|
||||
}
|
||||
}
|
||||
|
||||
func (SelectableField) Help() *markers.DefinitionHelp {
|
||||
return &markers.DefinitionHelp{
|
||||
Category: "CRD",
|
||||
DetailedHelp: markers.DetailedHelp{
|
||||
Summary: "adds a field that may be used with field selectors.",
|
||||
Details: "",
|
||||
},
|
||||
FieldHelp: map[string]markers.DetailedHelp{
|
||||
"JSONPath": {
|
||||
Summary: "specifies the jsonpath expression which is used to produce a field selector value.",
|
||||
Details: "",
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
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{},
|
||||
}
|
||||
@@ -384,8 +416,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{},
|
||||
}
|
||||
@@ -395,8 +427,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\nPossible values:\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 - \"atomic\": all fields are treated as one unit.\n Any changes have to replace the entire struct.",
|
||||
},
|
||||
FieldHelp: map[string]markers.DetailedHelp{},
|
||||
}
|
||||
@@ -419,8 +451,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.",
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -441,8 +473,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{},
|
||||
}
|
||||
@@ -463,7 +495,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{},
|
||||
@@ -474,8 +506,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{},
|
||||
}
|
||||
@@ -485,8 +517,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. Known 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{},
|
||||
}
|
||||
@@ -496,8 +528,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\nNB: The kubebuilder:validation:XPreserveUnknownFields variant is deprecated\nin favor of the kubebuilder:pruning:PreserveUnknownFields variant. They function\nidentically.",
|
||||
},
|
||||
FieldHelp: map[string]markers.DetailedHelp{},
|
||||
}
|
||||
@@ -507,8 +539,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\nThis marker may be repeated to specify multiple expressions, all of\nwhich must evaluate to true.",
|
||||
},
|
||||
FieldHelp: map[string]markers.DetailedHelp{
|
||||
"Rule": {
|
||||
@@ -519,6 +551,18 @@ func (XValidation) Help() *markers.DefinitionHelp {
|
||||
Summary: "",
|
||||
Details: "",
|
||||
},
|
||||
"MessageExpression": {
|
||||
Summary: "",
|
||||
Details: "",
|
||||
},
|
||||
"Reason": {
|
||||
Summary: "",
|
||||
Details: "",
|
||||
},
|
||||
"FieldPath": {
|
||||
Summary: "",
|
||||
Details: "",
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
138
vendor/sigs.k8s.io/controller-tools/pkg/crd/schema.go
generated
vendored
138
vendor/sigs.k8s.io/controller-tools/pkg/crd/schema.go
generated
vendored
@@ -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,73 @@ 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.
|
||||
type schemaMarkerWithName struct {
|
||||
SchemaMarker SchemaMarker
|
||||
Name string
|
||||
}
|
||||
|
||||
// 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([]schemaMarkerWithName, 0, len(markerSet))
|
||||
itemsMarkers := make([]schemaMarkerWithName, 0, len(markerSet))
|
||||
|
||||
for markerName, markerValues := range markerSet {
|
||||
for _, markerValue := range markerValues {
|
||||
if _, isApplyFirst := markerValue.(applyFirstMarker); !isApplyFirst {
|
||||
continue
|
||||
}
|
||||
|
||||
schemaMarker, isSchemaMarker := markerValue.(SchemaMarker)
|
||||
if !isSchemaMarker {
|
||||
continue
|
||||
}
|
||||
|
||||
if err := schemaMarker.ApplyToSchema(props); err != nil {
|
||||
ctx.pkg.AddError(loader.ErrFromNode(err /* an okay guess */, node))
|
||||
if schemaMarker, isSchemaMarker := markerValue.(SchemaMarker); isSchemaMarker {
|
||||
if strings.HasPrefix(markerName, crdmarkers.ValidationItemsPrefix) {
|
||||
itemsMarkers = append(itemsMarkers, schemaMarkerWithName{
|
||||
SchemaMarker: schemaMarker,
|
||||
Name: markerName,
|
||||
})
|
||||
} else {
|
||||
markers = append(markers, schemaMarkerWithName{
|
||||
SchemaMarker: schemaMarker,
|
||||
Name: markerName,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ...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
|
||||
}
|
||||
cmpPriority := func(markers []schemaMarkerWithName, i, j int) bool {
|
||||
var iPriority, jPriority crdmarkers.ApplyPriority
|
||||
|
||||
schemaMarker, isSchemaMarker := markerValue.(SchemaMarker)
|
||||
if !isSchemaMarker {
|
||||
continue
|
||||
}
|
||||
if err := schemaMarker.ApplyToSchema(props); err != nil {
|
||||
switch m := markers[i].SchemaMarker.(type) {
|
||||
case crdmarkers.ApplyPriorityMarker:
|
||||
iPriority = m.ApplyPriority()
|
||||
case applyFirstMarker:
|
||||
iPriority = crdmarkers.ApplyPriorityFirst
|
||||
default:
|
||||
iPriority = crdmarkers.ApplyPriorityDefault
|
||||
}
|
||||
|
||||
switch m := markers[j].SchemaMarker.(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) })
|
||||
|
||||
for _, schemaMarker := range markers {
|
||||
if err := schemaMarker.SchemaMarker.ApplyToSchema(props); err != nil {
|
||||
ctx.pkg.AddError(loader.ErrFromNode(err /* an okay guess */, node))
|
||||
}
|
||||
}
|
||||
|
||||
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", schemaMarker.Name, props.Type)
|
||||
ctx.pkg.AddError(loader.ErrFromNode(err, node))
|
||||
} else {
|
||||
itemsSchema := props.Items.Schema
|
||||
if err := schemaMarker.SchemaMarker.ApplyToSchema(itemsSchema); err != nil {
|
||||
ctx.pkg.AddError(loader.ErrFromNode(err /* an okay guess */, node))
|
||||
}
|
||||
}
|
||||
@@ -216,11 +251,30 @@ func localNamedToSchema(ctx *schemaContext, ident *ast.Ident) *apiext.JSONSchema
|
||||
ctx.pkg.AddError(loader.ErrFromNode(fmt.Errorf("unknown type %s", ident.Name), ident))
|
||||
return &apiext.JSONSchemaProps{}
|
||||
}
|
||||
// This reproduces the behavior we had pre gotypesalias=1 (needed if this
|
||||
// project is compiled with default settings and Go >= 1.23).
|
||||
if aliasInfo, isAlias := typeInfo.(*types.Alias); isAlias {
|
||||
typeInfo = aliasInfo.Underlying()
|
||||
}
|
||||
if basicInfo, isBasic := typeInfo.(*types.Basic); isBasic {
|
||||
typ, fmt, err := builtinToType(basicInfo, ctx.allowDangerousTypes)
|
||||
if err != nil {
|
||||
ctx.pkg.AddError(loader.ErrFromNode(err, ident))
|
||||
}
|
||||
// Check for type aliasing to a basic type for gotypesalias=0. See more
|
||||
// in documentation https://pkg.go.dev/go/types#Alias:
|
||||
// > For gotypesalias=1, alias declarations produce an Alias type.
|
||||
// > Otherwise, the alias information is only in the type name, which
|
||||
// > points directly to the actual (aliased) type.
|
||||
if basicInfo.Name() != ident.Name {
|
||||
ctx.requestSchema("", ident.Name)
|
||||
link := TypeRefLink("", ident.Name)
|
||||
return &apiext.JSONSchemaProps{
|
||||
Type: typ,
|
||||
Format: fmt,
|
||||
Ref: &link,
|
||||
}
|
||||
}
|
||||
return &apiext.JSONSchemaProps{
|
||||
Type: typ,
|
||||
Format: fmt,
|
||||
@@ -228,7 +282,7 @@ func localNamedToSchema(ctx *schemaContext, ident *ast.Ident) *apiext.JSONSchema
|
||||
}
|
||||
// NB(directxman12): if there are dot imports, this might be an external reference,
|
||||
// so use typechecking info to get the actual object
|
||||
typeNameInfo := typeInfo.(*types.Named).Obj()
|
||||
typeNameInfo := typeInfo.(interface{ Obj() *types.TypeName }).Obj()
|
||||
pkg := typeNameInfo.Pkg()
|
||||
pkgPath := loader.NonVendorPath(pkg.Path())
|
||||
if pkg == ctx.pkg.Types {
|
||||
@@ -248,7 +302,7 @@ func namedToSchema(ctx *schemaContext, named *ast.SelectorExpr) *apiext.JSONSche
|
||||
ctx.pkg.AddError(loader.ErrFromNode(fmt.Errorf("unknown type %v.%s", named.X, named.Sel.Name), named))
|
||||
return &apiext.JSONSchemaProps{}
|
||||
}
|
||||
typeInfo := typeInfoRaw.(*types.Named)
|
||||
typeInfo := typeInfoRaw.(interface{ Obj() *types.TypeName })
|
||||
typeNameInfo := typeInfo.Obj()
|
||||
nonVendorPath := loader.NonVendorPath(typeNameInfo.Pkg().Path())
|
||||
ctx.requestSchema(nonVendorPath, typeNameInfo.Name())
|
||||
@@ -378,20 +432,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
|
||||
@@ -453,7 +515,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)),
|
||||
|
||||
18
vendor/sigs.k8s.io/controller-tools/pkg/crd/zz_generated.markerhelp.go
generated
vendored
18
vendor/sigs.k8s.io/controller-tools/pkg/crd/zz_generated.markerhelp.go
generated
vendored
@@ -33,20 +33,20 @@ 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\nCurrently the following additional types are allowed when this is true:\nfloat32\nfloat64\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\nCurrently, the only supported value is v1.\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\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",
|
||||
@@ -60,6 +60,10 @@ func (Generator) Help() *markers.DefinitionHelp {
|
||||
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\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\nThe field can be set for compatiblity reasons, although strongly discouraged, resource\nauthors should move to a structural OpenAPI schema instead.\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.",
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
1
vendor/sigs.k8s.io/controller-tools/pkg/deepcopy/gen.go
generated
vendored
1
vendor/sigs.k8s.io/controller-tools/pkg/deepcopy/gen.go
generated
vendored
@@ -191,7 +191,6 @@ import (
|
||||
if err != nil {
|
||||
pkg.AddError(err)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// generateForPackage generates DeepCopy and runtime.Object implementations for
|
||||
|
||||
4
vendor/sigs.k8s.io/controller-tools/pkg/deepcopy/zz_generated.markerhelp.go
generated
vendored
4
vendor/sigs.k8s.io/controller-tools/pkg/deepcopy/zz_generated.markerhelp.go
generated
vendored
@@ -28,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": {
|
||||
|
||||
1
vendor/sigs.k8s.io/controller-tools/pkg/genall/options.go
generated
vendored
1
vendor/sigs.k8s.io/controller-tools/pkg/genall/options.go
generated
vendored
@@ -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
|
||||
|
||||
12
vendor/sigs.k8s.io/controller-tools/pkg/genall/zz_generated.markerhelp.go
generated
vendored
12
vendor/sigs.k8s.io/controller-tools/pkg/genall/zz_generated.markerhelp.go
generated
vendored
@@ -28,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{},
|
||||
@@ -39,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\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": {
|
||||
@@ -59,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{},
|
||||
}
|
||||
@@ -81,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{},
|
||||
|
||||
11
vendor/sigs.k8s.io/controller-tools/pkg/loader/loader.go
generated
vendored
11
vendor/sigs.k8s.io/controller-tools/pkg/loader/loader.go
generated
vendored
@@ -370,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()
|
||||
}
|
||||
@@ -393,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
|
||||
//
|
||||
@@ -489,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
|
||||
}
|
||||
@@ -518,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
|
||||
@@ -548,7 +546,6 @@ func LoadRootsWithConfig(cfg *packages.Config, roots ...string) ([]*Package, err
|
||||
if err := filepath.WalkDir(
|
||||
d,
|
||||
addNestedGoModulesToRoots); err != nil {
|
||||
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
@@ -604,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 {
|
||||
|
||||
3
vendor/sigs.k8s.io/controller-tools/pkg/loader/refs.go
generated
vendored
3
vendor/sigs.k8s.io/controller-tools/pkg/loader/refs.go
generated
vendored
@@ -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)
|
||||
})
|
||||
|
||||
1
vendor/sigs.k8s.io/controller-tools/pkg/markers/collect.go
generated
vendored
1
vendor/sigs.k8s.io/controller-tools/pkg/markers/collect.go
generated
vendored
@@ -388,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
|
||||
|
||||
12
vendor/sigs.k8s.io/controller-tools/pkg/markers/parse.go
generated
vendored
12
vendor/sigs.k8s.io/controller-tools/pkg/markers/parse.go
generated
vendored
@@ -820,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.
|
||||
|
||||
37
vendor/sigs.k8s.io/controller-tools/pkg/markers/zip.go
generated
vendored
37
vendor/sigs.k8s.io/controller-tools/pkg/markers/zip.go
generated
vendored
@@ -69,13 +69,15 @@ func extractDoc(node ast.Node, decl *ast.GenDecl) string {
|
||||
// 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 {
|
||||
var outLines []string
|
||||
var insideCodeBlock bool
|
||||
for i, line := range lines {
|
||||
if isAsteriskComment {
|
||||
// Trim any extranous whitespace,
|
||||
// for handling /*…*/-style comments,
|
||||
@@ -86,10 +88,33 @@ func extractDoc(node ast.Node, decl *ast.GenDecl) string {
|
||||
// Respect that double-newline means
|
||||
// actual newline:
|
||||
if line == "" {
|
||||
outLines[i] = "\n"
|
||||
lines[i] = "\n"
|
||||
} else {
|
||||
outLines[i] = line
|
||||
lines[i] = line
|
||||
}
|
||||
|
||||
// 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")
|
||||
}
|
||||
|
||||
128
vendor/sigs.k8s.io/controller-tools/pkg/rbac/parser.go
generated
vendored
128
vendor/sigs.k8s.io/controller-tools/pkg/rbac/parser.go
generated
vendored
@@ -93,6 +93,24 @@ 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)
|
||||
}
|
||||
|
||||
func (r *Rule) keyWitGroupResourcesResourceNamesVerbs() string {
|
||||
key := r.key()
|
||||
verbs := strings.Join(r.Verbs, "&")
|
||||
return fmt.Sprintf("%s + %s + %s + %s", key.Groups, key.Resources, key.ResourceNames, 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) {
|
||||
@@ -128,12 +146,6 @@ func removeDupAndSort(strs []string) []string {
|
||||
|
||||
// ToRule converts this rule to its Kubernetes API form.
|
||||
func (r *Rule) ToRule() rbacv1.PolicyRule {
|
||||
// fix the group names first, since letting people type "core" is nice
|
||||
for i, group := range r.Groups {
|
||||
if group == "core" {
|
||||
r.Groups[i] = ""
|
||||
}
|
||||
}
|
||||
return rbacv1.PolicyRule{
|
||||
APIGroups: r.Groups,
|
||||
Verbs: r.Verbs,
|
||||
@@ -168,22 +180,42 @@ 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
|
||||
if len(rule.Resources) == 0 {
|
||||
// Add a rule without any resource if Resources is empty.
|
||||
r := Rule{
|
||||
Groups: rule.Groups,
|
||||
Resources: []string{},
|
||||
ResourceNames: rule.ResourceNames,
|
||||
URLs: rule.URLs,
|
||||
Namespace: rule.Namespace,
|
||||
Verbs: rule.Verbs,
|
||||
}
|
||||
namespace := r.Namespace
|
||||
rulesByNSResource[namespace] = append(rulesByNSResource[namespace], &r)
|
||||
continue
|
||||
}
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -192,6 +224,13 @@ func GenerateRoles(ctx *genall.GenerationContext, roleName string) ([]interface{
|
||||
ruleMap := make(map[ruleKey]*Rule)
|
||||
// all the Rules having the same ruleKey will be merged into the first Rule
|
||||
for _, rule := range rules {
|
||||
// fix the group name first, since letting people type "core" is nice
|
||||
for i, name := range rule.Groups {
|
||||
if name == "core" {
|
||||
rule.Groups[i] = ""
|
||||
}
|
||||
}
|
||||
|
||||
key := rule.key()
|
||||
if _, ok := ruleMap[key]; !ok {
|
||||
ruleMap[key] = rule
|
||||
@@ -200,6 +239,64 @@ 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
|
||||
}
|
||||
|
||||
// deduplicate URLs
|
||||
// 1. create map based on key without URLs
|
||||
ruleMapWithoutURLs := make(map[string][]*Rule)
|
||||
for _, rule := range ruleMap {
|
||||
// get key without Group
|
||||
key := rule.keyWitGroupResourcesResourceNamesVerbs()
|
||||
ruleMapWithoutURLs[key] = append(ruleMapWithoutURLs[key], rule)
|
||||
}
|
||||
// 2. merge to ruleMap
|
||||
ruleMap = make(map[ruleKey]*Rule)
|
||||
for _, rules := range ruleMapWithoutURLs {
|
||||
rule := rules[0]
|
||||
for _, mergeRule := range rules[1:] {
|
||||
rule.URLs = append(rule.URLs, mergeRule.URLs...)
|
||||
}
|
||||
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 {
|
||||
@@ -210,14 +307,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)
|
||||
@@ -225,7 +321,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
|
||||
|
||||
8
vendor/sigs.k8s.io/controller-tools/pkg/rbac/zz_generated.markerhelp.go
generated
vendored
8
vendor/sigs.k8s.io/controller-tools/pkg/rbac/zz_generated.markerhelp.go
generated
vendored
@@ -65,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.",
|
||||
@@ -77,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.",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
2
vendor/sigs.k8s.io/controller-tools/pkg/schemapatcher/gen.go
generated
vendored
2
vendor/sigs.k8s.io/controller-tools/pkg/schemapatcher/gen.go
generated
vendored
@@ -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)
|
||||
|
||||
8
vendor/sigs.k8s.io/controller-tools/pkg/schemapatcher/zz_generated.markerhelp.go
generated
vendored
8
vendor/sigs.k8s.io/controller-tools/pkg/schemapatcher/zz_generated.markerhelp.go
generated
vendored
@@ -28,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": {
|
||||
@@ -37,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",
|
||||
|
||||
10
vendor/sigs.k8s.io/controller-tools/pkg/version/version.go
generated
vendored
10
vendor/sigs.k8s.io/controller-tools/pkg/version/version.go
generated
vendored
@@ -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 (
|
||||
@@ -20,8 +22,16 @@ import (
|
||||
"runtime/debug"
|
||||
)
|
||||
|
||||
// version to be set using ldflags:
|
||||
// -ldflags "-X sigs.k8s.io/controller-tools/pkg/version.version=v1.0.0"
|
||||
// falls back to module information is unset
|
||||
var version = ""
|
||||
|
||||
// Version returns the version of the main module
|
||||
func Version() string {
|
||||
if version != "" {
|
||||
return version
|
||||
}
|
||||
info, ok := debug.ReadBuildInfo()
|
||||
if !ok || info == nil || info.Main.Version == "" {
|
||||
// binary has not been built with module support or doesn't contain a version.
|
||||
|
||||
110
vendor/sigs.k8s.io/controller-tools/pkg/webhook/parser.go
generated
vendored
110
vendor/sigs.k8s.io/controller-tools/pkg/webhook/parser.go
generated
vendored
@@ -31,6 +31,7 @@ import (
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"sigs.k8s.io/controller-tools/pkg/genall"
|
||||
"sigs.k8s.io/controller-tools/pkg/markers"
|
||||
)
|
||||
@@ -42,9 +43,11 @@ const (
|
||||
)
|
||||
|
||||
var (
|
||||
// ConfigDefinition s a marker for defining Webhook manifests.
|
||||
// ConfigDefinition is a marker for defining Webhook manifests.
|
||||
// Call ToWebhook on the value to get a Kubernetes Webhook.
|
||||
ConfigDefinition = markers.Must(markers.MakeDefinition("kubebuilder:webhook", markers.DescribesPackage, Config{}))
|
||||
// WebhookConfigDefinition is a marker for defining MutatingWebhookConfiguration or ValidatingWebhookConfiguration manifests.
|
||||
WebhookConfigDefinition = markers.Must(markers.MakeDefinition("kubebuilder:webhookconfiguration", markers.DescribesPackage, WebhookConfig{}))
|
||||
)
|
||||
|
||||
// supportedWebhookVersions returns currently supported API version of {Mutating,Validating}WebhookConfiguration.
|
||||
@@ -52,6 +55,19 @@ func supportedWebhookVersions() []string {
|
||||
return []string{defaultWebhookVersion}
|
||||
}
|
||||
|
||||
// +controllertools:marker:generateHelp
|
||||
|
||||
type WebhookConfig struct {
|
||||
// Mutating marks this as a mutating webhook (it's validating only if false)
|
||||
//
|
||||
// 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.
|
||||
Mutating bool
|
||||
// Name indicates the name of the K8s MutatingWebhookConfiguration or ValidatingWebhookConfiguration object.
|
||||
Name string `marker:"name,optional"`
|
||||
}
|
||||
|
||||
// +controllertools:marker:generateHelp:category=Webhook
|
||||
|
||||
// Config specifies how a webhook should be served.
|
||||
@@ -154,6 +170,32 @@ func verbToAPIVariant(verbRaw string) admissionregv1.OperationType {
|
||||
}
|
||||
}
|
||||
|
||||
// ToMutatingWebhookConfiguration converts this WebhookConfig to its Kubernetes API form.
|
||||
func (c WebhookConfig) ToMutatingWebhookConfiguration() (admissionregv1.MutatingWebhookConfiguration, error) {
|
||||
if !c.Mutating {
|
||||
return admissionregv1.MutatingWebhookConfiguration{}, fmt.Errorf("%s is a validating webhook", c.Name)
|
||||
}
|
||||
|
||||
return admissionregv1.MutatingWebhookConfiguration{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: c.Name,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
// ToValidatingWebhookConfiguration converts this WebhookConfig to its Kubernetes API form.
|
||||
func (c WebhookConfig) ToValidatingWebhookConfiguration() (admissionregv1.ValidatingWebhookConfiguration, error) {
|
||||
if c.Mutating {
|
||||
return admissionregv1.ValidatingWebhookConfiguration{}, fmt.Errorf("%s is a mutating webhook", c.Name)
|
||||
}
|
||||
|
||||
return admissionregv1.ValidatingWebhookConfiguration{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: c.Name,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
// ToMutatingWebhook converts this rule to its Kubernetes API form.
|
||||
func (c Config) ToMutatingWebhook() (admissionregv1.MutatingWebhook, error) {
|
||||
if !c.Mutating {
|
||||
@@ -289,7 +331,6 @@ func (c Config) clientConfig() (admissionregv1.WebhookClientConfig, error) {
|
||||
return admissionregv1.WebhookClientConfig{
|
||||
URL: &url,
|
||||
}, nil
|
||||
|
||||
}
|
||||
|
||||
// sideEffects returns the sideEffects config for a webhook.
|
||||
@@ -363,7 +404,11 @@ func (Generator) RegisterMarkers(into *markers.Registry) error {
|
||||
if err := into.Register(ConfigDefinition); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := into.Register(WebhookConfigDefinition); err != nil {
|
||||
return err
|
||||
}
|
||||
into.AddHelp(ConfigDefinition, Config{}.Help())
|
||||
into.AddHelp(WebhookConfigDefinition, Config{}.Help())
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -371,12 +416,43 @@ 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))
|
||||
var mutatingWebhookCfgs admissionregv1.MutatingWebhookConfiguration
|
||||
var validatingWebhookCfgs admissionregv1.ValidatingWebhookConfiguration
|
||||
|
||||
for _, root := range ctx.Roots {
|
||||
markerSet, err := markers.PackageMarkers(ctx.Collector, root)
|
||||
if err != nil {
|
||||
root.AddError(err)
|
||||
}
|
||||
|
||||
webhookCfgs := markerSet[WebhookConfigDefinition.Name]
|
||||
var hasValidatingWebhookConfig, hasMutatingWebhookConfig bool = false, false
|
||||
for _, webhookCfg := range webhookCfgs {
|
||||
webhookCfg := webhookCfg.(WebhookConfig)
|
||||
|
||||
if webhookCfg.Mutating {
|
||||
if hasMutatingWebhookConfig {
|
||||
return fmt.Errorf("duplicate mutating %s with name %s", WebhookConfigDefinition.Name, webhookCfg.Name)
|
||||
}
|
||||
|
||||
if mutatingWebhookCfgs, err = webhookCfg.ToMutatingWebhookConfiguration(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
hasMutatingWebhookConfig = true
|
||||
} else {
|
||||
if hasValidatingWebhookConfig {
|
||||
return fmt.Errorf("duplicate validating %s with name %s", WebhookConfigDefinition.Name, webhookCfg.Name)
|
||||
}
|
||||
|
||||
if validatingWebhookCfgs, err = webhookCfg.ToValidatingWebhookConfiguration(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
hasValidatingWebhookConfig = true
|
||||
}
|
||||
}
|
||||
|
||||
cfgs := markerSet[ConfigDefinition.Name]
|
||||
sort.SliceStable(cfgs, func(i, j int) bool {
|
||||
return cfgs[i].(Config).Name < cfgs[j].(Config).Name
|
||||
@@ -411,16 +487,22 @@ func (g Generator) Generate(ctx *genall.GenerationContext) error {
|
||||
versionedWebhooks := make(map[string][]interface{}, len(supportedWebhookVersions))
|
||||
for _, version := range supportedWebhookVersions {
|
||||
if cfgs, ok := mutatingCfgs[version]; ok {
|
||||
// The only possible version in supportedWebhookVersions is v1,
|
||||
// so use it for all versioned types in this context.
|
||||
objRaw := &admissionregv1.MutatingWebhookConfiguration{}
|
||||
var objRaw *admissionregv1.MutatingWebhookConfiguration
|
||||
if mutatingWebhookCfgs.Name != "" {
|
||||
objRaw = &mutatingWebhookCfgs
|
||||
} else {
|
||||
// The only possible version in supportedWebhookVersions is v1,
|
||||
// so use it for all versioned types in this context.
|
||||
objRaw = &admissionregv1.MutatingWebhookConfiguration{}
|
||||
objRaw.SetName("mutating-webhook-configuration")
|
||||
}
|
||||
objRaw.SetGroupVersionKind(schema.GroupVersionKind{
|
||||
Group: admissionregv1.SchemeGroupVersion.Group,
|
||||
Version: version,
|
||||
Kind: "MutatingWebhookConfiguration",
|
||||
})
|
||||
objRaw.SetName("mutating-webhook-configuration")
|
||||
objRaw.Webhooks = cfgs
|
||||
|
||||
for i := range objRaw.Webhooks {
|
||||
// SideEffects is required in admissionregistration/v1, if this is not set or set to `Some` or `Known`,
|
||||
// return an error
|
||||
@@ -442,16 +524,22 @@ func (g Generator) Generate(ctx *genall.GenerationContext) error {
|
||||
}
|
||||
|
||||
if cfgs, ok := validatingCfgs[version]; ok {
|
||||
// The only possible version in supportedWebhookVersions is v1,
|
||||
// so use it for all versioned types in this context.
|
||||
objRaw := &admissionregv1.ValidatingWebhookConfiguration{}
|
||||
var objRaw *admissionregv1.ValidatingWebhookConfiguration
|
||||
if validatingWebhookCfgs.Name != "" {
|
||||
objRaw = &validatingWebhookCfgs
|
||||
} else {
|
||||
// The only possible version in supportedWebhookVersions is v1,
|
||||
// so use it for all versioned types in this context.
|
||||
objRaw = &admissionregv1.ValidatingWebhookConfiguration{}
|
||||
objRaw.SetName("validating-webhook-configuration")
|
||||
}
|
||||
objRaw.SetGroupVersionKind(schema.GroupVersionKind{
|
||||
Group: admissionregv1.SchemeGroupVersion.Group,
|
||||
Version: version,
|
||||
Kind: "ValidatingWebhookConfiguration",
|
||||
})
|
||||
objRaw.SetName("validating-webhook-configuration")
|
||||
objRaw.Webhooks = cfgs
|
||||
|
||||
for i := range objRaw.Webhooks {
|
||||
// SideEffects is required in admissionregistration/v1, if this is not set or set to `Some` or `Known`,
|
||||
// return an error
|
||||
@@ -486,7 +574,7 @@ func (g Generator) Generate(ctx *genall.GenerationContext) error {
|
||||
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)
|
||||
}
|
||||
|
||||
68
vendor/sigs.k8s.io/controller-tools/pkg/webhook/zz_generated.markerhelp.go
generated
vendored
68
vendor/sigs.k8s.io/controller-tools/pkg/webhook/zz_generated.markerhelp.go
generated
vendored
@@ -28,29 +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. 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.",
|
||||
Details: "",
|
||||
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.",
|
||||
@@ -61,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.",
|
||||
@@ -73,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.",
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -111,3 +115,23 @@ func (Generator) Help() *markers.DefinitionHelp {
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (WebhookConfig) Help() *markers.DefinitionHelp {
|
||||
return &markers.DefinitionHelp{
|
||||
Category: "",
|
||||
DetailedHelp: markers.DetailedHelp{
|
||||
Summary: "",
|
||||
Details: "",
|
||||
},
|
||||
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,\nand are called *before* all validating webhooks. Mutating webhooks may\nchoose to reject an object, similarly to a validating webhook.",
|
||||
},
|
||||
"Name": {
|
||||
Summary: "indicates the name of the K8s MutatingWebhookConfiguration or ValidatingWebhookConfiguration object.",
|
||||
Details: "",
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
2
vendor/sigs.k8s.io/kustomize/api/filters/imagetag/updater.go
generated
vendored
2
vendor/sigs.k8s.io/kustomize/api/filters/imagetag/updater.go
generated
vendored
@@ -6,7 +6,7 @@ package imagetag
|
||||
import (
|
||||
"sigs.k8s.io/kustomize/api/filters/filtersutil"
|
||||
|
||||
"sigs.k8s.io/kustomize/api/image"
|
||||
"sigs.k8s.io/kustomize/api/internal/image"
|
||||
"sigs.k8s.io/kustomize/api/types"
|
||||
"sigs.k8s.io/kustomize/kyaml/yaml"
|
||||
)
|
||||
|
||||
9
vendor/sigs.k8s.io/kustomize/api/filters/nameref/nameref.go
generated
vendored
9
vendor/sigs.k8s.io/kustomize/api/filters/nameref/nameref.go
generated
vendored
@@ -284,9 +284,9 @@ func (f Filter) roleRefFilter() sieveFunc {
|
||||
return previousIdSelectedByGvk(roleRefGvk)
|
||||
}
|
||||
|
||||
func prefixSuffixEquals(other resource.ResCtx) sieveFunc {
|
||||
func prefixSuffixEquals(other resource.ResCtx, allowEmpty bool) sieveFunc {
|
||||
return func(r *resource.Resource) bool {
|
||||
return r.PrefixesSuffixesEquals(other)
|
||||
return r.PrefixesSuffixesEquals(other, allowEmpty)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -325,7 +325,10 @@ func (f Filter) selectReferral(
|
||||
if len(candidates) == 1 {
|
||||
return candidates[0], nil
|
||||
}
|
||||
candidates = doSieve(candidates, prefixSuffixEquals(f.Referrer))
|
||||
candidates = doSieve(candidates, prefixSuffixEquals(f.Referrer, true))
|
||||
if len(candidates) > 1 {
|
||||
candidates = doSieve(candidates, prefixSuffixEquals(f.Referrer, false))
|
||||
}
|
||||
if len(candidates) == 1 {
|
||||
return candidates[0], nil
|
||||
}
|
||||
|
||||
2
vendor/sigs.k8s.io/kustomize/api/filters/patchjson6902/patchjson6902.go
generated
vendored
2
vendor/sigs.k8s.io/kustomize/api/filters/patchjson6902/patchjson6902.go
generated
vendored
@@ -6,7 +6,7 @@ package patchjson6902
|
||||
import (
|
||||
"strings"
|
||||
|
||||
jsonpatch "github.com/evanphx/json-patch"
|
||||
jsonpatch "gopkg.in/evanphx/json-patch.v4"
|
||||
"sigs.k8s.io/kustomize/kyaml/kio"
|
||||
"sigs.k8s.io/kustomize/kyaml/yaml"
|
||||
k8syaml "sigs.k8s.io/yaml"
|
||||
|
||||
15
vendor/sigs.k8s.io/kustomize/api/filters/replacement/replacement.go
generated
vendored
15
vendor/sigs.k8s.io/kustomize/api/filters/replacement/replacement.go
generated
vendored
@@ -126,8 +126,8 @@ func applyReplacement(nodes []*yaml.RNode, value *yaml.RNode, targetSelectors []
|
||||
}
|
||||
|
||||
// filter targets by matching resource IDs
|
||||
for i, id := range ids {
|
||||
if id.IsSelectedBy(selector.Select.ResId) && !rejectId(selector.Reject, &ids[i]) {
|
||||
for _, id := range ids {
|
||||
if id.IsSelectedBy(selector.Select.ResId) && !containsRejectId(selector.Reject, ids) {
|
||||
err := copyValueToTarget(possibleTarget, value, selector)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -168,10 +168,15 @@ func matchesAnnoAndLabelSelector(n *yaml.RNode, selector *types.Selector) (bool,
|
||||
return annoMatch && labelMatch, nil
|
||||
}
|
||||
|
||||
func rejectId(rejects []*types.Selector, id *resid.ResId) bool {
|
||||
func containsRejectId(rejects []*types.Selector, ids []resid.ResId) bool {
|
||||
for _, r := range rejects {
|
||||
if !r.ResId.IsEmpty() && id.IsSelectedBy(r.ResId) {
|
||||
return true
|
||||
if r.ResId.IsEmpty() {
|
||||
continue
|
||||
}
|
||||
for _, id := range ids {
|
||||
if id.IsSelectedBy(r.ResId) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
|
||||
2
vendor/sigs.k8s.io/kustomize/api/internal/accumulator/loadconfigfromcrds.go
generated
vendored
2
vendor/sigs.k8s.io/kustomize/api/internal/accumulator/loadconfigfromcrds.go
generated
vendored
@@ -144,7 +144,7 @@ func loadCrdIntoConfig(
|
||||
}
|
||||
_, label := property.Extensions.GetString(xLabelSelector)
|
||||
if label {
|
||||
err = theConfig.AddLabelFieldSpec(
|
||||
err = theConfig.AddCommonLabelsFieldSpec(
|
||||
makeFs(theGvk, append(path, propName)))
|
||||
if err != nil {
|
||||
return
|
||||
|
||||
68
vendor/sigs.k8s.io/kustomize/api/internal/builtins/HelmChartInflationGenerator.go
generated
vendored
68
vendor/sigs.k8s.io/kustomize/api/internal/builtins/HelmChartInflationGenerator.go
generated
vendored
@@ -12,11 +12,12 @@ import (
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/imdario/mergo"
|
||||
"sigs.k8s.io/kustomize/api/resmap"
|
||||
"sigs.k8s.io/kustomize/api/types"
|
||||
"sigs.k8s.io/kustomize/kyaml/errors"
|
||||
"sigs.k8s.io/kustomize/kyaml/kio"
|
||||
kyaml "sigs.k8s.io/kustomize/kyaml/yaml"
|
||||
"sigs.k8s.io/kustomize/kyaml/yaml/merge2"
|
||||
"sigs.k8s.io/yaml"
|
||||
)
|
||||
|
||||
@@ -53,6 +54,15 @@ func (p *HelmChartInflationGeneratorPlugin) Config(
|
||||
if h.GeneralConfig().HelmConfig.Command == "" {
|
||||
return fmt.Errorf("must specify --helm-command")
|
||||
}
|
||||
|
||||
// CLI args takes precedence
|
||||
if h.GeneralConfig().HelmConfig.KubeVersion != "" {
|
||||
p.HelmChart.KubeVersion = h.GeneralConfig().HelmConfig.KubeVersion
|
||||
}
|
||||
if len(h.GeneralConfig().HelmConfig.ApiVersions) != 0 {
|
||||
p.HelmChart.ApiVersions = h.GeneralConfig().HelmConfig.ApiVersions
|
||||
}
|
||||
|
||||
p.h = h
|
||||
if err = yaml.Unmarshal(config, p); err != nil {
|
||||
return
|
||||
@@ -91,7 +101,7 @@ func (p *HelmChartInflationGeneratorPlugin) validateArgs() (err error) {
|
||||
// be under the loader root (unless root restrictions are
|
||||
// disabled).
|
||||
if p.ValuesFile == "" {
|
||||
p.ValuesFile = filepath.Join(p.ChartHome, p.Name, "values.yaml")
|
||||
p.ValuesFile = filepath.Join(p.absChartHome(), p.Name, "values.yaml")
|
||||
}
|
||||
for i, file := range p.AdditionalValuesFiles {
|
||||
// use Load() to enforce root restrictions
|
||||
@@ -132,10 +142,17 @@ func (p *HelmChartInflationGeneratorPlugin) errIfIllegalValuesMerge() error {
|
||||
}
|
||||
|
||||
func (p *HelmChartInflationGeneratorPlugin) absChartHome() string {
|
||||
var chartHome string
|
||||
if filepath.IsAbs(p.ChartHome) {
|
||||
return p.ChartHome
|
||||
chartHome = p.ChartHome
|
||||
} else {
|
||||
chartHome = filepath.Join(p.h.Loader().Root(), p.ChartHome)
|
||||
}
|
||||
return filepath.Join(p.h.Loader().Root(), p.ChartHome)
|
||||
|
||||
if p.Version != "" && p.Repo != "" {
|
||||
return filepath.Join(chartHome, fmt.Sprintf("%s-%s", p.Name, p.Version))
|
||||
}
|
||||
return chartHome
|
||||
}
|
||||
|
||||
func (p *HelmChartInflationGeneratorPlugin) runHelmCommand(
|
||||
@@ -185,18 +202,33 @@ func (p *HelmChartInflationGeneratorPlugin) replaceValuesInline() error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
chValues := make(map[string]interface{})
|
||||
if err = yaml.Unmarshal(pValues, &chValues); err != nil {
|
||||
return err
|
||||
chValues, err := kyaml.Parse(string(pValues))
|
||||
if err != nil {
|
||||
return errors.WrapPrefixf(err, "could not parse values file into rnode")
|
||||
}
|
||||
inlineValues, err := kyaml.FromMap(p.ValuesInline)
|
||||
if err != nil {
|
||||
return errors.WrapPrefixf(err, "could not parse values inline into rnode")
|
||||
}
|
||||
var outValues *kyaml.RNode
|
||||
switch p.ValuesMerge {
|
||||
// Function `merge2.Merge` overrides values in dest with values from src.
|
||||
// To achieve override or merge behavior, we pass parameters in different order.
|
||||
// Object passed as dest will be modified, so we copy it just in case someone
|
||||
// decides to use it after this is called.
|
||||
case valuesMergeOptionOverride:
|
||||
err = mergo.Merge(
|
||||
&chValues, p.ValuesInline, mergo.WithOverride)
|
||||
outValues, err = merge2.Merge(inlineValues, chValues.Copy(), kyaml.MergeOptions{})
|
||||
case valuesMergeOptionMerge:
|
||||
err = mergo.Merge(&chValues, p.ValuesInline)
|
||||
outValues, err = merge2.Merge(chValues, inlineValues.Copy(), kyaml.MergeOptions{})
|
||||
}
|
||||
p.ValuesInline = chValues
|
||||
if err != nil {
|
||||
return errors.WrapPrefixf(err, "could not merge values")
|
||||
}
|
||||
mapValues, err := outValues.Map()
|
||||
if err != nil {
|
||||
return errors.WrapPrefixf(err, "could not parse merged values into map")
|
||||
}
|
||||
p.ValuesInline = mapValues
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -281,8 +313,18 @@ func (p *HelmChartInflationGeneratorPlugin) pullCommand() []string {
|
||||
"pull",
|
||||
"--untar",
|
||||
"--untardir", p.absChartHome(),
|
||||
"--repo", p.Repo,
|
||||
p.Name}
|
||||
}
|
||||
|
||||
switch {
|
||||
case strings.HasPrefix(p.Repo, "oci://"):
|
||||
args = append(args, strings.TrimSuffix(p.Repo, "/")+"/"+p.Name)
|
||||
case p.Repo != "":
|
||||
args = append(args, "--repo", p.Repo)
|
||||
fallthrough
|
||||
default:
|
||||
args = append(args, p.Name)
|
||||
}
|
||||
|
||||
if p.Version != "" {
|
||||
args = append(args, "--version", p.Version)
|
||||
}
|
||||
|
||||
2
vendor/sigs.k8s.io/kustomize/api/internal/builtins/PatchJson6902Transformer.go
generated
vendored
2
vendor/sigs.k8s.io/kustomize/api/internal/builtins/PatchJson6902Transformer.go
generated
vendored
@@ -6,7 +6,7 @@ package builtins
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
jsonpatch "github.com/evanphx/json-patch"
|
||||
jsonpatch "gopkg.in/evanphx/json-patch.v4"
|
||||
"sigs.k8s.io/kustomize/api/filters/patchjson6902"
|
||||
"sigs.k8s.io/kustomize/api/ifc"
|
||||
"sigs.k8s.io/kustomize/api/resmap"
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user