mirror of
https://github.com/ceph/ceph-csi.git
synced 2024-11-22 14:20:19 +00:00
rebase: update sigs.k8s.io/controller-runtime to current version
There is no release for sigs.k8s.io/controller-runtime that supports Kubernetes v1.27. The main branch has all the required modifications, so we can use that for the time being. Signed-off-by: Niels de Vos <ndevos@ibm.com>
This commit is contained in:
parent
2551a0b05f
commit
b1a4590967
6
go.mod
6
go.mod
@ -44,7 +44,7 @@ require (
|
|||||||
k8s.io/mount-utils v0.27.2
|
k8s.io/mount-utils v0.27.2
|
||||||
k8s.io/pod-security-admission v0.0.0
|
k8s.io/pod-security-admission v0.0.0
|
||||||
k8s.io/utils v0.0.0-20230209194617-a36077c30491
|
k8s.io/utils v0.0.0-20230209194617-a36077c30491
|
||||||
sigs.k8s.io/controller-runtime v0.14.6
|
sigs.k8s.io/controller-runtime v0.15.1-0.20230524200249-30eae58f1b98
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
@ -128,7 +128,7 @@ require (
|
|||||||
github.com/pierrec/lz4 v2.6.1+incompatible // indirect
|
github.com/pierrec/lz4 v2.6.1+incompatible // indirect
|
||||||
github.com/pkg/errors v0.9.1 // indirect
|
github.com/pkg/errors v0.9.1 // indirect
|
||||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
|
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
|
||||||
github.com/prometheus/client_model v0.3.0 // indirect
|
github.com/prometheus/client_model v0.4.0 // indirect
|
||||||
github.com/prometheus/common v0.42.0 // indirect
|
github.com/prometheus/common v0.42.0 // indirect
|
||||||
github.com/prometheus/procfs v0.9.0 // indirect
|
github.com/prometheus/procfs v0.9.0 // indirect
|
||||||
github.com/ryanuber/go-glob v1.0.0 // indirect
|
github.com/ryanuber/go-glob v1.0.0 // indirect
|
||||||
@ -156,7 +156,7 @@ require (
|
|||||||
golang.org/x/term v0.8.0 // indirect
|
golang.org/x/term v0.8.0 // indirect
|
||||||
golang.org/x/text v0.9.0 // indirect
|
golang.org/x/text v0.9.0 // indirect
|
||||||
golang.org/x/time v0.3.0 // indirect
|
golang.org/x/time v0.3.0 // indirect
|
||||||
gomodules.xyz/jsonpatch/v2 v2.2.0 // indirect
|
gomodules.xyz/jsonpatch/v2 v2.3.0 // indirect
|
||||||
google.golang.org/api v0.110.0 // indirect
|
google.golang.org/api v0.110.0 // indirect
|
||||||
google.golang.org/appengine v1.6.7 // indirect
|
google.golang.org/appengine v1.6.7 // indirect
|
||||||
google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 // indirect
|
google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 // indirect
|
||||||
|
9
go.sum
9
go.sum
@ -366,8 +366,8 @@ github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbV
|
|||||||
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
||||||
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
||||||
github.com/go-logr/zapr v0.1.0/go.mod h1:tabnROwaDl0UNxkVeFRbY8bwB37GwRv0P8lg6aAiEnk=
|
github.com/go-logr/zapr v0.1.0/go.mod h1:tabnROwaDl0UNxkVeFRbY8bwB37GwRv0P8lg6aAiEnk=
|
||||||
github.com/go-logr/zapr v1.2.3 h1:a9vnzlIBPQBBkeaR9IuMUfmVOrQlkoC4YfPoFkX3T7A=
|
|
||||||
github.com/go-logr/zapr v1.2.3/go.mod h1:eIauM6P8qSvTw5o2ez6UEAfGjQKrxQTl5EoK+Qa2oG4=
|
github.com/go-logr/zapr v1.2.3/go.mod h1:eIauM6P8qSvTw5o2ez6UEAfGjQKrxQTl5EoK+Qa2oG4=
|
||||||
|
github.com/go-logr/zapr v1.2.4 h1:QHVo+6stLbfJmYGkQ7uGHUCu5hnAFAj6mDe6Ea0SeOo=
|
||||||
github.com/go-martini/martini v0.0.0-20170121215854-22fa46961aab/go.mod h1:/P9AEU963A2AYjv4d1V5eVL1CQbEJq6aCNHDDjibzu8=
|
github.com/go-martini/martini v0.0.0-20170121215854-22fa46961aab/go.mod h1:/P9AEU963A2AYjv4d1V5eVL1CQbEJq6aCNHDDjibzu8=
|
||||||
github.com/go-ole/go-ole v1.2.1/go.mod h1:7FAglXiTm7HKlQRDeOQ6ZNUHidzCWXuZWq/1dTyBNF8=
|
github.com/go-ole/go-ole v1.2.1/go.mod h1:7FAglXiTm7HKlQRDeOQ6ZNUHidzCWXuZWq/1dTyBNF8=
|
||||||
github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
|
github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
|
||||||
@ -987,8 +987,9 @@ github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:
|
|||||||
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||||
github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||||
github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4=
|
|
||||||
github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w=
|
github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w=
|
||||||
|
github.com/prometheus/client_model v0.4.0 h1:5lQXD3cAg1OXBf4Wq03gTrXHeaV0TQvGfUooCfx1yqY=
|
||||||
|
github.com/prometheus/client_model v0.4.0/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU=
|
||||||
github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
|
github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
|
||||||
github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
|
github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
|
||||||
github.com/prometheus/common v0.0.0-20181126121408-4724e9255275/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
|
github.com/prometheus/common v0.0.0-20181126121408-4724e9255275/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
|
||||||
@ -1868,8 +1869,8 @@ rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
|
|||||||
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.1.2 h1:trsWhjU5jZrx6UvFu4WzQDrN7Pga4a7Qg+zcfcj64PA=
|
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.1.2 h1:trsWhjU5jZrx6UvFu4WzQDrN7Pga4a7Qg+zcfcj64PA=
|
||||||
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.1.2/go.mod h1:+qG7ISXqCDVVcyO8hLn12AKVYYUjM7ftlqsqmrhMZE0=
|
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.1.2/go.mod h1:+qG7ISXqCDVVcyO8hLn12AKVYYUjM7ftlqsqmrhMZE0=
|
||||||
sigs.k8s.io/controller-runtime v0.2.2/go.mod h1:9dyohw3ZtoXQuV1e766PHUn+cmrRCIcBh6XIMFNMZ+I=
|
sigs.k8s.io/controller-runtime v0.2.2/go.mod h1:9dyohw3ZtoXQuV1e766PHUn+cmrRCIcBh6XIMFNMZ+I=
|
||||||
sigs.k8s.io/controller-runtime v0.14.6 h1:oxstGVvXGNnMvY7TAESYk+lzr6S3V5VFxQ6d92KcwQA=
|
sigs.k8s.io/controller-runtime v0.15.1-0.20230524200249-30eae58f1b98 h1:g/rUFhTxYK9gaf9sIzuZhp8Hc0dc1mTIOAEtrAlBYgc=
|
||||||
sigs.k8s.io/controller-runtime v0.14.6/go.mod h1:WqIdsAY6JBsjfc/CqO0CORmNtoCtE4S6qbPc9s68h+0=
|
sigs.k8s.io/controller-runtime v0.15.1-0.20230524200249-30eae58f1b98/go.mod h1:fnVc7My+0bTh/Y9bft09N4Fqom6WiMQMdCaayy4l/oM=
|
||||||
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo=
|
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo=
|
||||||
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0=
|
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0=
|
||||||
sigs.k8s.io/structured-merge-diff/v4 v4.2.3 h1:PRbqxJClWWYMNV1dhaG4NsibJbArud9kFxnAMREiWFE=
|
sigs.k8s.io/structured-merge-diff/v4 v4.2.3 h1:PRbqxJClWWYMNV1dhaG4NsibJbArud9kFxnAMREiWFE=
|
||||||
|
@ -82,7 +82,7 @@ func add(mgr manager.Manager, r reconcile.Reconciler) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Watch for changes to PersistentVolumes
|
// Watch for changes to PersistentVolumes
|
||||||
err = c.Watch(&source.Kind{Type: &corev1.PersistentVolume{}}, &handler.EnqueueRequestForObject{})
|
err = c.Watch(source.Kind(mgr.GetCache(), &corev1.PersistentVolume{}), &handler.EnqueueRequestForObject{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to watch the changes: %w", err)
|
return fmt.Errorf("failed to watch the changes: %w", err)
|
||||||
}
|
}
|
||||||
|
1586
vendor/github.com/prometheus/client_model/go/metrics.pb.go
generated
vendored
1586
vendor/github.com/prometheus/client_model/go/metrics.pb.go
generated
vendored
File diff suppressed because it is too large
Load Diff
14
vendor/modules.txt
vendored
14
vendor/modules.txt
vendored
@ -498,8 +498,8 @@ github.com/prometheus/client_golang/prometheus/internal
|
|||||||
github.com/prometheus/client_golang/prometheus/promhttp
|
github.com/prometheus/client_golang/prometheus/promhttp
|
||||||
github.com/prometheus/client_golang/prometheus/testutil
|
github.com/prometheus/client_golang/prometheus/testutil
|
||||||
github.com/prometheus/client_golang/prometheus/testutil/promlint
|
github.com/prometheus/client_golang/prometheus/testutil/promlint
|
||||||
# github.com/prometheus/client_model v0.3.0
|
# github.com/prometheus/client_model v0.4.0
|
||||||
## explicit; go 1.9
|
## explicit; go 1.18
|
||||||
github.com/prometheus/client_model/go
|
github.com/prometheus/client_model/go
|
||||||
# github.com/prometheus/common v0.42.0
|
# github.com/prometheus/common v0.42.0
|
||||||
## explicit; go 1.18
|
## explicit; go 1.18
|
||||||
@ -705,7 +705,7 @@ golang.org/x/text/width
|
|||||||
# golang.org/x/time v0.3.0
|
# golang.org/x/time v0.3.0
|
||||||
## explicit
|
## explicit
|
||||||
golang.org/x/time/rate
|
golang.org/x/time/rate
|
||||||
# gomodules.xyz/jsonpatch/v2 v2.2.0 => github.com/gomodules/jsonpatch/v2 v2.2.0
|
# gomodules.xyz/jsonpatch/v2 v2.3.0 => github.com/gomodules/jsonpatch/v2 v2.2.0
|
||||||
## explicit; go 1.12
|
## explicit; go 1.12
|
||||||
gomodules.xyz/jsonpatch/v2
|
gomodules.xyz/jsonpatch/v2
|
||||||
# google.golang.org/api v0.110.0
|
# google.golang.org/api v0.110.0
|
||||||
@ -1560,8 +1560,8 @@ sigs.k8s.io/apiserver-network-proxy/konnectivity-client/pkg/client
|
|||||||
sigs.k8s.io/apiserver-network-proxy/konnectivity-client/pkg/client/metrics
|
sigs.k8s.io/apiserver-network-proxy/konnectivity-client/pkg/client/metrics
|
||||||
sigs.k8s.io/apiserver-network-proxy/konnectivity-client/pkg/common/metrics
|
sigs.k8s.io/apiserver-network-proxy/konnectivity-client/pkg/common/metrics
|
||||||
sigs.k8s.io/apiserver-network-proxy/konnectivity-client/proto/client
|
sigs.k8s.io/apiserver-network-proxy/konnectivity-client/proto/client
|
||||||
# sigs.k8s.io/controller-runtime v0.14.6
|
# sigs.k8s.io/controller-runtime v0.15.1-0.20230524200249-30eae58f1b98
|
||||||
## explicit; go 1.19
|
## explicit; go 1.20
|
||||||
sigs.k8s.io/controller-runtime/pkg/cache
|
sigs.k8s.io/controller-runtime/pkg/cache
|
||||||
sigs.k8s.io/controller-runtime/pkg/cache/internal
|
sigs.k8s.io/controller-runtime/pkg/cache/internal
|
||||||
sigs.k8s.io/controller-runtime/pkg/certwatcher
|
sigs.k8s.io/controller-runtime/pkg/certwatcher
|
||||||
@ -1581,8 +1581,8 @@ sigs.k8s.io/controller-runtime/pkg/internal/controller/metrics
|
|||||||
sigs.k8s.io/controller-runtime/pkg/internal/field/selector
|
sigs.k8s.io/controller-runtime/pkg/internal/field/selector
|
||||||
sigs.k8s.io/controller-runtime/pkg/internal/httpserver
|
sigs.k8s.io/controller-runtime/pkg/internal/httpserver
|
||||||
sigs.k8s.io/controller-runtime/pkg/internal/log
|
sigs.k8s.io/controller-runtime/pkg/internal/log
|
||||||
sigs.k8s.io/controller-runtime/pkg/internal/objectutil
|
|
||||||
sigs.k8s.io/controller-runtime/pkg/internal/recorder
|
sigs.k8s.io/controller-runtime/pkg/internal/recorder
|
||||||
|
sigs.k8s.io/controller-runtime/pkg/internal/source
|
||||||
sigs.k8s.io/controller-runtime/pkg/leaderelection
|
sigs.k8s.io/controller-runtime/pkg/leaderelection
|
||||||
sigs.k8s.io/controller-runtime/pkg/log
|
sigs.k8s.io/controller-runtime/pkg/log
|
||||||
sigs.k8s.io/controller-runtime/pkg/manager
|
sigs.k8s.io/controller-runtime/pkg/manager
|
||||||
@ -1592,10 +1592,8 @@ sigs.k8s.io/controller-runtime/pkg/predicate
|
|||||||
sigs.k8s.io/controller-runtime/pkg/ratelimiter
|
sigs.k8s.io/controller-runtime/pkg/ratelimiter
|
||||||
sigs.k8s.io/controller-runtime/pkg/reconcile
|
sigs.k8s.io/controller-runtime/pkg/reconcile
|
||||||
sigs.k8s.io/controller-runtime/pkg/recorder
|
sigs.k8s.io/controller-runtime/pkg/recorder
|
||||||
sigs.k8s.io/controller-runtime/pkg/runtime/inject
|
|
||||||
sigs.k8s.io/controller-runtime/pkg/scheme
|
sigs.k8s.io/controller-runtime/pkg/scheme
|
||||||
sigs.k8s.io/controller-runtime/pkg/source
|
sigs.k8s.io/controller-runtime/pkg/source
|
||||||
sigs.k8s.io/controller-runtime/pkg/source/internal
|
|
||||||
sigs.k8s.io/controller-runtime/pkg/webhook
|
sigs.k8s.io/controller-runtime/pkg/webhook
|
||||||
sigs.k8s.io/controller-runtime/pkg/webhook/admission
|
sigs.k8s.io/controller-runtime/pkg/webhook/admission
|
||||||
sigs.k8s.io/controller-runtime/pkg/webhook/internal/metrics
|
sigs.k8s.io/controller-runtime/pkg/webhook/internal/metrics
|
||||||
|
488
vendor/sigs.k8s.io/controller-runtime/pkg/cache/cache.go
generated
vendored
488
vendor/sigs.k8s.io/controller-runtime/pkg/cache/cache.go
generated
vendored
@ -19,10 +19,11 @@ package cache
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"reflect"
|
"net/http"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"k8s.io/apimachinery/pkg/api/meta"
|
"k8s.io/apimachinery/pkg/api/meta"
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/fields"
|
"k8s.io/apimachinery/pkg/fields"
|
||||||
"k8s.io/apimachinery/pkg/labels"
|
"k8s.io/apimachinery/pkg/labels"
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
@ -37,7 +38,10 @@ import (
|
|||||||
logf "sigs.k8s.io/controller-runtime/pkg/internal/log"
|
logf "sigs.k8s.io/controller-runtime/pkg/internal/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
var log = logf.RuntimeLog.WithName("object-cache")
|
var (
|
||||||
|
log = logf.RuntimeLog.WithName("object-cache")
|
||||||
|
defaultSyncPeriod = 10 * time.Hour
|
||||||
|
)
|
||||||
|
|
||||||
// Cache knows how to load Kubernetes objects, fetch informers to request
|
// Cache knows how to load Kubernetes objects, fetch informers to request
|
||||||
// to receive events for Kubernetes objects (at a low-level),
|
// to receive events for Kubernetes objects (at a low-level),
|
||||||
@ -98,310 +102,152 @@ type Informer interface {
|
|||||||
HasSynced() bool
|
HasSynced() bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// ObjectSelector is an alias name of internal.Selector.
|
|
||||||
type ObjectSelector internal.Selector
|
|
||||||
|
|
||||||
// SelectorsByObject associate a client.Object's GVK to a field/label selector.
|
|
||||||
// There is also `DefaultSelector` to set a global default (which will be overridden by
|
|
||||||
// a more specific setting here, if any).
|
|
||||||
type SelectorsByObject map[client.Object]ObjectSelector
|
|
||||||
|
|
||||||
// Options are the optional arguments for creating a new InformersMap object.
|
// Options are the optional arguments for creating a new InformersMap object.
|
||||||
type Options struct {
|
type Options struct {
|
||||||
|
// HTTPClient is the http client to use for the REST client
|
||||||
|
HTTPClient *http.Client
|
||||||
|
|
||||||
// Scheme is the scheme to use for mapping objects to GroupVersionKinds
|
// Scheme is the scheme to use for mapping objects to GroupVersionKinds
|
||||||
Scheme *runtime.Scheme
|
Scheme *runtime.Scheme
|
||||||
|
|
||||||
// Mapper is the RESTMapper to use for mapping GroupVersionKinds to Resources
|
// Mapper is the RESTMapper to use for mapping GroupVersionKinds to Resources
|
||||||
Mapper meta.RESTMapper
|
Mapper meta.RESTMapper
|
||||||
|
|
||||||
// Resync is the base frequency the informers are resynced.
|
// SyncPeriod determines the minimum frequency at which watched resources are
|
||||||
// Defaults to defaultResyncTime.
|
// reconciled. A lower period will correct entropy more quickly, but reduce
|
||||||
// A 10 percent jitter will be added to the Resync period between informers
|
// responsiveness to change if there are many watched resources. Change this
|
||||||
// So that all informers will not send list requests simultaneously.
|
// value only if you know what you are doing. Defaults to 10 hours if unset.
|
||||||
Resync *time.Duration
|
// there will a 10 percent jitter between the SyncPeriod of all controllers
|
||||||
|
// so that all controllers will not send list requests simultaneously.
|
||||||
|
//
|
||||||
|
// This applies to all controllers.
|
||||||
|
//
|
||||||
|
// A period sync happens for two reasons:
|
||||||
|
// 1. To insure against a bug in the controller that causes an object to not
|
||||||
|
// be requeued, when it otherwise should be requeued.
|
||||||
|
// 2. To insure against an unknown bug in controller-runtime, or its dependencies,
|
||||||
|
// that causes an object to not be requeued, when it otherwise should be
|
||||||
|
// requeued, or to be removed from the queue, when it otherwise should not
|
||||||
|
// be removed.
|
||||||
|
//
|
||||||
|
// If you want
|
||||||
|
// 1. to insure against missed watch events, or
|
||||||
|
// 2. to poll services that cannot be watched,
|
||||||
|
// then we recommend that, instead of changing the default period, the
|
||||||
|
// controller requeue, with a constant duration `t`, whenever the controller
|
||||||
|
// is "done" with an object, and would otherwise not requeue it, i.e., we
|
||||||
|
// recommend the `Reconcile` function return `reconcile.Result{RequeueAfter: t}`,
|
||||||
|
// instead of `reconcile.Result{}`.
|
||||||
|
SyncPeriod *time.Duration
|
||||||
|
|
||||||
// Namespace restricts the cache's ListWatch to the desired namespace
|
// Namespaces restricts the cache's ListWatch to the desired namespaces
|
||||||
// Default watches all namespaces
|
// Default watches all namespaces
|
||||||
Namespace string
|
Namespaces []string
|
||||||
|
|
||||||
// SelectorsByObject restricts the cache's ListWatch to the desired
|
// DefaultLabelSelector will be used as a label selectors for all object types
|
||||||
// fields per GVK at the specified object, the map's value must implement
|
// unless they have a more specific selector set in ByObject.
|
||||||
// Selector [1] using for example a Set [2]
|
DefaultLabelSelector labels.Selector
|
||||||
// [1] https://pkg.go.dev/k8s.io/apimachinery/pkg/fields#Selector
|
|
||||||
// [2] https://pkg.go.dev/k8s.io/apimachinery/pkg/fields#Set
|
|
||||||
SelectorsByObject SelectorsByObject
|
|
||||||
|
|
||||||
// DefaultSelector will be used as selectors for all object types
|
// DefaultFieldSelector will be used as a field selectors for all object types
|
||||||
// that do not have a selector in SelectorsByObject defined.
|
// unless they have a more specific selector set in ByObject.
|
||||||
DefaultSelector ObjectSelector
|
DefaultFieldSelector fields.Selector
|
||||||
|
|
||||||
// UnsafeDisableDeepCopyByObject indicates not to deep copy objects during get or
|
// DefaultTransform will be used as transform for all object types
|
||||||
// list objects per GVK at the specified object.
|
// unless they have a more specific transform set in ByObject.
|
||||||
|
DefaultTransform toolscache.TransformFunc
|
||||||
|
|
||||||
|
// ByObject restricts the cache's ListWatch to the desired fields per GVK at the specified object.
|
||||||
|
ByObject map[client.Object]ByObject
|
||||||
|
|
||||||
|
// UnsafeDisableDeepCopy indicates not to deep copy objects during get or
|
||||||
|
// list objects for EVERY object.
|
||||||
// Be very careful with this, when enabled you must DeepCopy any object before mutating it,
|
// Be very careful with this, when enabled you must DeepCopy any object before mutating it,
|
||||||
// otherwise you will mutate the object in the cache.
|
// otherwise you will mutate the object in the cache.
|
||||||
UnsafeDisableDeepCopyByObject DisableDeepCopyByObject
|
//
|
||||||
|
// This is a global setting for all objects, and can be overridden by the ByObject setting.
|
||||||
|
UnsafeDisableDeepCopy *bool
|
||||||
|
}
|
||||||
|
|
||||||
// TransformByObject is a map from GVKs to transformer functions which
|
// ByObject offers more fine-grained control over the cache's ListWatch by object.
|
||||||
|
type ByObject struct {
|
||||||
|
// Label represents a label selector for the object.
|
||||||
|
Label labels.Selector
|
||||||
|
|
||||||
|
// Field represents a field selector for the object.
|
||||||
|
Field fields.Selector
|
||||||
|
|
||||||
|
// Transform is a map from objects to transformer functions which
|
||||||
// get applied when objects of the transformation are about to be committed
|
// get applied when objects of the transformation are about to be committed
|
||||||
// to cache.
|
// to cache.
|
||||||
//
|
//
|
||||||
// This function is called both for new objects to enter the cache,
|
// This function is called both for new objects to enter the cache,
|
||||||
// and for updated objects.
|
// and for updated objects.
|
||||||
TransformByObject TransformByObject
|
Transform toolscache.TransformFunc
|
||||||
|
|
||||||
// DefaultTransform is the transform used for all GVKs which do
|
// UnsafeDisableDeepCopy indicates not to deep copy objects during get or
|
||||||
// not have an explicit transform func set in TransformByObject
|
// list objects per GVK at the specified object.
|
||||||
DefaultTransform toolscache.TransformFunc
|
// Be very careful with this, when enabled you must DeepCopy any object before mutating it,
|
||||||
|
// otherwise you will mutate the object in the cache.
|
||||||
|
UnsafeDisableDeepCopy *bool
|
||||||
}
|
}
|
||||||
|
|
||||||
var defaultResyncTime = 10 * time.Hour
|
// NewCacheFunc - Function for creating a new cache from the options and a rest config.
|
||||||
|
type NewCacheFunc func(config *rest.Config, opts Options) (Cache, error)
|
||||||
|
|
||||||
// New initializes and returns a new Cache.
|
// New initializes and returns a new Cache.
|
||||||
func New(config *rest.Config, opts Options) (Cache, error) {
|
func New(config *rest.Config, opts Options) (Cache, error) {
|
||||||
|
if len(opts.Namespaces) == 0 {
|
||||||
|
opts.Namespaces = []string{metav1.NamespaceAll}
|
||||||
|
}
|
||||||
|
if len(opts.Namespaces) > 1 {
|
||||||
|
return newMultiNamespaceCache(config, opts)
|
||||||
|
}
|
||||||
|
|
||||||
opts, err := defaultOpts(config, opts)
|
opts, err := defaultOpts(config, opts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
selectorsByGVK, err := convertToByGVK(opts.SelectorsByObject, opts.DefaultSelector, opts.Scheme)
|
|
||||||
|
byGVK, err := convertToInformerOptsByGVK(opts.ByObject, opts.Scheme)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
disableDeepCopyByGVK, err := convertToDisableDeepCopyByGVK(opts.UnsafeDisableDeepCopyByObject, opts.Scheme)
|
// Set the default selector and transform.
|
||||||
if err != nil {
|
byGVK[schema.GroupVersionKind{}] = internal.InformersOptsByGVK{
|
||||||
return nil, err
|
Selector: internal.Selector{
|
||||||
}
|
Label: opts.DefaultLabelSelector,
|
||||||
transformByGVK, err := convertToByGVK(opts.TransformByObject, opts.DefaultTransform, opts.Scheme)
|
Field: opts.DefaultFieldSelector,
|
||||||
if err != nil {
|
},
|
||||||
return nil, err
|
Transform: opts.DefaultTransform,
|
||||||
}
|
UnsafeDisableDeepCopy: opts.UnsafeDisableDeepCopy,
|
||||||
transformByObj := internal.TransformFuncByObjectFromMap(transformByGVK)
|
|
||||||
|
|
||||||
internalSelectorsByGVK := internal.SelectorsByGVK{}
|
|
||||||
for gvk, selector := range selectorsByGVK {
|
|
||||||
internalSelectorsByGVK[gvk] = internal.Selector(selector)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
im := internal.NewInformersMap(config, opts.Scheme, opts.Mapper, *opts.Resync, opts.Namespace, internalSelectorsByGVK, disableDeepCopyByGVK, transformByObj)
|
return &informerCache{
|
||||||
return &informerCache{InformersMap: im}, nil
|
scheme: opts.Scheme,
|
||||||
}
|
Informers: internal.NewInformers(config, &internal.InformersOpts{
|
||||||
|
HTTPClient: opts.HTTPClient,
|
||||||
// BuilderWithOptions returns a Cache constructor that will build a cache
|
Scheme: opts.Scheme,
|
||||||
// honoring the options argument, this is useful to specify options like
|
Mapper: opts.Mapper,
|
||||||
// SelectorsByObject
|
ResyncPeriod: *opts.SyncPeriod,
|
||||||
// WARNING: If SelectorsByObject is specified, filtered out resources are not
|
Namespace: opts.Namespaces[0],
|
||||||
// returned.
|
ByGVK: byGVK,
|
||||||
// WARNING: If UnsafeDisableDeepCopy is enabled, you must DeepCopy any object
|
}),
|
||||||
// returned from cache get/list before mutating it.
|
}, nil
|
||||||
func BuilderWithOptions(options Options) NewCacheFunc {
|
|
||||||
return func(config *rest.Config, inherited Options) (Cache, error) {
|
|
||||||
var err error
|
|
||||||
inherited, err = defaultOpts(config, inherited)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
options, err = defaultOpts(config, options)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
combined, err := options.inheritFrom(inherited)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return New(config, *combined)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (options Options) inheritFrom(inherited Options) (*Options, error) {
|
|
||||||
var (
|
|
||||||
combined Options
|
|
||||||
err error
|
|
||||||
)
|
|
||||||
combined.Scheme = combineScheme(inherited.Scheme, options.Scheme)
|
|
||||||
combined.Mapper = selectMapper(inherited.Mapper, options.Mapper)
|
|
||||||
combined.Resync = selectResync(inherited.Resync, options.Resync)
|
|
||||||
combined.Namespace = selectNamespace(inherited.Namespace, options.Namespace)
|
|
||||||
combined.SelectorsByObject, combined.DefaultSelector, err = combineSelectors(inherited, options, combined.Scheme)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
combined.UnsafeDisableDeepCopyByObject, err = combineUnsafeDeepCopy(inherited, options, combined.Scheme)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
combined.TransformByObject, combined.DefaultTransform, err = combineTransforms(inherited, options, combined.Scheme)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return &combined, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func combineScheme(schemes ...*runtime.Scheme) *runtime.Scheme {
|
|
||||||
var out *runtime.Scheme
|
|
||||||
for _, sch := range schemes {
|
|
||||||
if sch == nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
for gvk, t := range sch.AllKnownTypes() {
|
|
||||||
if out == nil {
|
|
||||||
out = runtime.NewScheme()
|
|
||||||
}
|
|
||||||
out.AddKnownTypeWithName(gvk, reflect.New(t).Interface().(runtime.Object))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return out
|
|
||||||
}
|
|
||||||
|
|
||||||
func selectMapper(def, override meta.RESTMapper) meta.RESTMapper {
|
|
||||||
if override != nil {
|
|
||||||
return override
|
|
||||||
}
|
|
||||||
return def
|
|
||||||
}
|
|
||||||
|
|
||||||
func selectResync(def, override *time.Duration) *time.Duration {
|
|
||||||
if override != nil {
|
|
||||||
return override
|
|
||||||
}
|
|
||||||
return def
|
|
||||||
}
|
|
||||||
|
|
||||||
func selectNamespace(def, override string) string {
|
|
||||||
if override != "" {
|
|
||||||
return override
|
|
||||||
}
|
|
||||||
return def
|
|
||||||
}
|
|
||||||
|
|
||||||
func combineSelectors(inherited, options Options, scheme *runtime.Scheme) (SelectorsByObject, ObjectSelector, error) {
|
|
||||||
// Selectors are combined via logical AND.
|
|
||||||
// - Combined label selector is a union of the selectors requirements from both sets of options.
|
|
||||||
// - Combined field selector uses fields.AndSelectors with the combined list of non-nil field selectors
|
|
||||||
// defined in both sets of options.
|
|
||||||
//
|
|
||||||
// There is a bunch of complexity here because we need to convert to SelectorsByGVK
|
|
||||||
// to be able to match keys between options and inherited and then convert back to SelectorsByObject
|
|
||||||
optionsSelectorsByGVK, err := convertToByGVK(options.SelectorsByObject, options.DefaultSelector, scheme)
|
|
||||||
if err != nil {
|
|
||||||
return nil, ObjectSelector{}, err
|
|
||||||
}
|
|
||||||
inheritedSelectorsByGVK, err := convertToByGVK(inherited.SelectorsByObject, inherited.DefaultSelector, inherited.Scheme)
|
|
||||||
if err != nil {
|
|
||||||
return nil, ObjectSelector{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
for gvk, inheritedSelector := range inheritedSelectorsByGVK {
|
|
||||||
optionsSelectorsByGVK[gvk] = combineSelector(inheritedSelector, optionsSelectorsByGVK[gvk])
|
|
||||||
}
|
|
||||||
return convertToByObject(optionsSelectorsByGVK, scheme)
|
|
||||||
}
|
|
||||||
|
|
||||||
func combineSelector(selectors ...ObjectSelector) ObjectSelector {
|
|
||||||
ls := make([]labels.Selector, 0, len(selectors))
|
|
||||||
fs := make([]fields.Selector, 0, len(selectors))
|
|
||||||
for _, s := range selectors {
|
|
||||||
ls = append(ls, s.Label)
|
|
||||||
fs = append(fs, s.Field)
|
|
||||||
}
|
|
||||||
return ObjectSelector{
|
|
||||||
Label: combineLabelSelectors(ls...),
|
|
||||||
Field: combineFieldSelectors(fs...),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func combineLabelSelectors(ls ...labels.Selector) labels.Selector {
|
|
||||||
var combined labels.Selector
|
|
||||||
for _, l := range ls {
|
|
||||||
if l == nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if combined == nil {
|
|
||||||
combined = labels.NewSelector()
|
|
||||||
}
|
|
||||||
reqs, _ := l.Requirements()
|
|
||||||
combined = combined.Add(reqs...)
|
|
||||||
}
|
|
||||||
return combined
|
|
||||||
}
|
|
||||||
|
|
||||||
func combineFieldSelectors(fs ...fields.Selector) fields.Selector {
|
|
||||||
nonNil := fs[:0]
|
|
||||||
for _, f := range fs {
|
|
||||||
if f == nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
nonNil = append(nonNil, f)
|
|
||||||
}
|
|
||||||
if len(nonNil) == 0 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
if len(nonNil) == 1 {
|
|
||||||
return nonNil[0]
|
|
||||||
}
|
|
||||||
return fields.AndSelectors(nonNil...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func combineUnsafeDeepCopy(inherited, options Options, scheme *runtime.Scheme) (DisableDeepCopyByObject, error) {
|
|
||||||
// UnsafeDisableDeepCopyByObject is combined via precedence. Only if a value for a particular GVK is unset
|
|
||||||
// in options will a value from inherited be used.
|
|
||||||
optionsDisableDeepCopyByGVK, err := convertToDisableDeepCopyByGVK(options.UnsafeDisableDeepCopyByObject, options.Scheme)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
inheritedDisableDeepCopyByGVK, err := convertToDisableDeepCopyByGVK(inherited.UnsafeDisableDeepCopyByObject, inherited.Scheme)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
for gvk, inheritedDeepCopy := range inheritedDisableDeepCopyByGVK {
|
|
||||||
if _, ok := optionsDisableDeepCopyByGVK[gvk]; !ok {
|
|
||||||
if optionsDisableDeepCopyByGVK == nil {
|
|
||||||
optionsDisableDeepCopyByGVK = map[schema.GroupVersionKind]bool{}
|
|
||||||
}
|
|
||||||
optionsDisableDeepCopyByGVK[gvk] = inheritedDeepCopy
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return convertToDisableDeepCopyByObject(optionsDisableDeepCopyByGVK, scheme)
|
|
||||||
}
|
|
||||||
|
|
||||||
func combineTransforms(inherited, options Options, scheme *runtime.Scheme) (TransformByObject, toolscache.TransformFunc, error) {
|
|
||||||
// Transform functions are combined via chaining. If both inherited and options define a transform
|
|
||||||
// function, the transform function from inherited will be called first, and the transform function from
|
|
||||||
// options will be called second.
|
|
||||||
optionsTransformByGVK, err := convertToByGVK(options.TransformByObject, options.DefaultTransform, options.Scheme)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
inheritedTransformByGVK, err := convertToByGVK(inherited.TransformByObject, inherited.DefaultTransform, inherited.Scheme)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
for gvk, inheritedTransform := range inheritedTransformByGVK {
|
|
||||||
if optionsTransformByGVK == nil {
|
|
||||||
optionsTransformByGVK = map[schema.GroupVersionKind]toolscache.TransformFunc{}
|
|
||||||
}
|
|
||||||
optionsTransformByGVK[gvk] = combineTransform(inheritedTransform, optionsTransformByGVK[gvk])
|
|
||||||
}
|
|
||||||
return convertToByObject(optionsTransformByGVK, scheme)
|
|
||||||
}
|
|
||||||
|
|
||||||
func combineTransform(inherited, current toolscache.TransformFunc) toolscache.TransformFunc {
|
|
||||||
if inherited == nil {
|
|
||||||
return current
|
|
||||||
}
|
|
||||||
if current == nil {
|
|
||||||
return inherited
|
|
||||||
}
|
|
||||||
return func(in interface{}) (interface{}, error) {
|
|
||||||
mid, err := inherited(in)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return current(mid)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func defaultOpts(config *rest.Config, opts Options) (Options, error) {
|
func defaultOpts(config *rest.Config, opts Options) (Options, error) {
|
||||||
|
logger := log.WithName("setup")
|
||||||
|
|
||||||
|
// Use the rest HTTP client for the provided config if unset
|
||||||
|
if opts.HTTPClient == nil {
|
||||||
|
var err error
|
||||||
|
opts.HTTPClient, err = rest.HTTPClientFor(config)
|
||||||
|
if err != nil {
|
||||||
|
logger.Error(err, "Failed to get HTTP client")
|
||||||
|
return opts, fmt.Errorf("could not create HTTP client from config: %w", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Use the default Kubernetes Scheme if unset
|
// Use the default Kubernetes Scheme if unset
|
||||||
if opts.Scheme == nil {
|
if opts.Scheme == nil {
|
||||||
opts.Scheme = scheme.Scheme
|
opts.Scheme = scheme.Scheme
|
||||||
@ -410,108 +256,38 @@ func defaultOpts(config *rest.Config, opts Options) (Options, error) {
|
|||||||
// Construct a new Mapper if unset
|
// Construct a new Mapper if unset
|
||||||
if opts.Mapper == nil {
|
if opts.Mapper == nil {
|
||||||
var err error
|
var err error
|
||||||
opts.Mapper, err = apiutil.NewDiscoveryRESTMapper(config)
|
opts.Mapper, err = apiutil.NewDiscoveryRESTMapper(config, opts.HTTPClient)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.WithName("setup").Error(err, "Failed to get API Group-Resources")
|
logger.Error(err, "Failed to get API Group-Resources")
|
||||||
return opts, fmt.Errorf("could not create RESTMapper from config")
|
return opts, fmt.Errorf("could not create RESTMapper from config: %w", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Default the resync period to 10 hours if unset
|
// Default the resync period to 10 hours if unset
|
||||||
if opts.Resync == nil {
|
if opts.SyncPeriod == nil {
|
||||||
opts.Resync = &defaultResyncTime
|
opts.SyncPeriod = &defaultSyncPeriod
|
||||||
}
|
}
|
||||||
return opts, nil
|
return opts, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func convertToByGVK[T any](byObject map[client.Object]T, def T, scheme *runtime.Scheme) (map[schema.GroupVersionKind]T, error) {
|
func convertToInformerOptsByGVK(in map[client.Object]ByObject, scheme *runtime.Scheme) (map[schema.GroupVersionKind]internal.InformersOptsByGVK, error) {
|
||||||
byGVK := map[schema.GroupVersionKind]T{}
|
out := map[schema.GroupVersionKind]internal.InformersOptsByGVK{}
|
||||||
for object, value := range byObject {
|
for object, byObject := range in {
|
||||||
gvk, err := apiutil.GVKForObject(object, scheme)
|
gvk, err := apiutil.GVKForObject(object, scheme)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
byGVK[gvk] = value
|
if _, ok := out[gvk]; ok {
|
||||||
}
|
return nil, fmt.Errorf("duplicate cache options for GVK %v, cache.Options.ByObject has multiple types with the same GroupVersionKind", gvk)
|
||||||
byGVK[schema.GroupVersionKind{}] = def
|
|
||||||
return byGVK, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func convertToByObject[T any](byGVK map[schema.GroupVersionKind]T, scheme *runtime.Scheme) (map[client.Object]T, T, error) {
|
|
||||||
var byObject map[client.Object]T
|
|
||||||
def := byGVK[schema.GroupVersionKind{}]
|
|
||||||
for gvk, value := range byGVK {
|
|
||||||
if gvk == (schema.GroupVersionKind{}) {
|
|
||||||
continue
|
|
||||||
}
|
}
|
||||||
obj, err := scheme.New(gvk)
|
out[gvk] = internal.InformersOptsByGVK{
|
||||||
if err != nil {
|
Selector: internal.Selector{
|
||||||
return nil, def, err
|
Field: byObject.Field,
|
||||||
}
|
Label: byObject.Label,
|
||||||
cObj, ok := obj.(client.Object)
|
},
|
||||||
if !ok {
|
Transform: byObject.Transform,
|
||||||
return nil, def, fmt.Errorf("object %T for GVK %q does not implement client.Object", obj, gvk)
|
UnsafeDisableDeepCopy: byObject.UnsafeDisableDeepCopy,
|
||||||
}
|
|
||||||
cObj.GetObjectKind().SetGroupVersionKind(gvk)
|
|
||||||
if byObject == nil {
|
|
||||||
byObject = map[client.Object]T{}
|
|
||||||
}
|
|
||||||
byObject[cObj] = value
|
|
||||||
}
|
|
||||||
return byObject, def, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// DisableDeepCopyByObject associate a client.Object's GVK to disable DeepCopy during get or list from cache.
|
|
||||||
type DisableDeepCopyByObject map[client.Object]bool
|
|
||||||
|
|
||||||
var _ client.Object = &ObjectAll{}
|
|
||||||
|
|
||||||
// ObjectAll is the argument to represent all objects' types.
|
|
||||||
type ObjectAll struct {
|
|
||||||
client.Object
|
|
||||||
}
|
|
||||||
|
|
||||||
func convertToDisableDeepCopyByGVK(disableDeepCopyByObject DisableDeepCopyByObject, scheme *runtime.Scheme) (internal.DisableDeepCopyByGVK, error) {
|
|
||||||
disableDeepCopyByGVK := internal.DisableDeepCopyByGVK{}
|
|
||||||
for obj, disable := range disableDeepCopyByObject {
|
|
||||||
switch obj.(type) {
|
|
||||||
case ObjectAll, *ObjectAll:
|
|
||||||
disableDeepCopyByGVK[internal.GroupVersionKindAll] = disable
|
|
||||||
default:
|
|
||||||
gvk, err := apiutil.GVKForObject(obj, scheme)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
disableDeepCopyByGVK[gvk] = disable
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return disableDeepCopyByGVK, nil
|
return out, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func convertToDisableDeepCopyByObject(byGVK internal.DisableDeepCopyByGVK, scheme *runtime.Scheme) (DisableDeepCopyByObject, error) {
|
|
||||||
var byObject DisableDeepCopyByObject
|
|
||||||
for gvk, value := range byGVK {
|
|
||||||
if byObject == nil {
|
|
||||||
byObject = DisableDeepCopyByObject{}
|
|
||||||
}
|
|
||||||
if gvk == (schema.GroupVersionKind{}) {
|
|
||||||
byObject[ObjectAll{}] = value
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
obj, err := scheme.New(gvk)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
cObj, ok := obj.(client.Object)
|
|
||||||
if !ok {
|
|
||||||
return nil, fmt.Errorf("object %T for GVK %q does not implement client.Object", obj, gvk)
|
|
||||||
}
|
|
||||||
|
|
||||||
byObject[cObj] = value
|
|
||||||
}
|
|
||||||
return byObject, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// TransformByObject associate a client.Object's GVK to a transformer function
|
|
||||||
// to be applied when storing the object into the cache.
|
|
||||||
type TransformByObject map[client.Object]toolscache.TransformFunc
|
|
||||||
|
84
vendor/sigs.k8s.io/controller-runtime/pkg/cache/informer_cache.go
generated
vendored
84
vendor/sigs.k8s.io/controller-runtime/pkg/cache/informer_cache.go
generated
vendored
@ -19,10 +19,10 @@ package cache
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"reflect"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
apimeta "k8s.io/apimachinery/pkg/api/meta"
|
apimeta "k8s.io/apimachinery/pkg/api/meta"
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||||
@ -45,19 +45,21 @@ func (*ErrCacheNotStarted) Error() string {
|
|||||||
return "the cache is not started, can not read objects"
|
return "the cache is not started, can not read objects"
|
||||||
}
|
}
|
||||||
|
|
||||||
// informerCache is a Kubernetes Object cache populated from InformersMap. informerCache wraps an InformersMap.
|
// informerCache is a Kubernetes Object cache populated from internal.Informers.
|
||||||
|
// informerCache wraps internal.Informers.
|
||||||
type informerCache struct {
|
type informerCache struct {
|
||||||
*internal.InformersMap
|
scheme *runtime.Scheme
|
||||||
|
*internal.Informers
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get implements Reader.
|
// Get implements Reader.
|
||||||
func (ip *informerCache) Get(ctx context.Context, key client.ObjectKey, out client.Object, opts ...client.GetOption) error {
|
func (ic *informerCache) Get(ctx context.Context, key client.ObjectKey, out client.Object, opts ...client.GetOption) error {
|
||||||
gvk, err := apiutil.GVKForObject(out, ip.Scheme)
|
gvk, err := apiutil.GVKForObject(out, ic.scheme)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
started, cache, err := ip.InformersMap.Get(ctx, gvk, out)
|
started, cache, err := ic.Informers.Get(ctx, gvk, out)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -69,13 +71,13 @@ func (ip *informerCache) Get(ctx context.Context, key client.ObjectKey, out clie
|
|||||||
}
|
}
|
||||||
|
|
||||||
// List implements Reader.
|
// List implements Reader.
|
||||||
func (ip *informerCache) List(ctx context.Context, out client.ObjectList, opts ...client.ListOption) error {
|
func (ic *informerCache) List(ctx context.Context, out client.ObjectList, opts ...client.ListOption) error {
|
||||||
gvk, cacheTypeObj, err := ip.objectTypeForListObject(out)
|
gvk, cacheTypeObj, err := ic.objectTypeForListObject(out)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
started, cache, err := ip.InformersMap.Get(ctx, *gvk, cacheTypeObj)
|
started, cache, err := ic.Informers.Get(ctx, *gvk, cacheTypeObj)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -90,54 +92,46 @@ func (ip *informerCache) List(ctx context.Context, out client.ObjectList, opts .
|
|||||||
// objectTypeForListObject tries to find the runtime.Object and associated GVK
|
// objectTypeForListObject tries to find the runtime.Object and associated GVK
|
||||||
// for a single object corresponding to the passed-in list type. We need them
|
// for a single object corresponding to the passed-in list type. We need them
|
||||||
// because they are used as cache map key.
|
// because they are used as cache map key.
|
||||||
func (ip *informerCache) objectTypeForListObject(list client.ObjectList) (*schema.GroupVersionKind, runtime.Object, error) {
|
func (ic *informerCache) objectTypeForListObject(list client.ObjectList) (*schema.GroupVersionKind, runtime.Object, error) {
|
||||||
gvk, err := apiutil.GVKForObject(list, ip.Scheme)
|
gvk, err := apiutil.GVKForObject(list, ic.scheme)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// we need the non-list GVK, so chop off the "List" from the end of the kind
|
// We need the non-list GVK, so chop off the "List" from the end of the kind.
|
||||||
if strings.HasSuffix(gvk.Kind, "List") && apimeta.IsListType(list) {
|
gvk.Kind = strings.TrimSuffix(gvk.Kind, "List")
|
||||||
gvk.Kind = gvk.Kind[:len(gvk.Kind)-4]
|
|
||||||
}
|
|
||||||
|
|
||||||
_, isUnstructured := list.(*unstructured.UnstructuredList)
|
// Handle unstructured.UnstructuredList.
|
||||||
var cacheTypeObj runtime.Object
|
if _, isUnstructured := list.(runtime.Unstructured); isUnstructured {
|
||||||
if isUnstructured {
|
|
||||||
u := &unstructured.Unstructured{}
|
u := &unstructured.Unstructured{}
|
||||||
u.SetGroupVersionKind(gvk)
|
u.SetGroupVersionKind(gvk)
|
||||||
cacheTypeObj = u
|
return &gvk, u, nil
|
||||||
} else {
|
}
|
||||||
itemsPtr, err := apimeta.GetItemsPtr(list)
|
// Handle metav1.PartialObjectMetadataList.
|
||||||
if err != nil {
|
if _, isPartialObjectMetadata := list.(*metav1.PartialObjectMetadataList); isPartialObjectMetadata {
|
||||||
return nil, nil, err
|
pom := &metav1.PartialObjectMetadata{}
|
||||||
}
|
pom.SetGroupVersionKind(gvk)
|
||||||
// http://knowyourmeme.com/memes/this-is-fine
|
return &gvk, pom, nil
|
||||||
elemType := reflect.Indirect(reflect.ValueOf(itemsPtr)).Type().Elem()
|
|
||||||
if elemType.Kind() != reflect.Ptr {
|
|
||||||
elemType = reflect.PtrTo(elemType)
|
|
||||||
}
|
|
||||||
|
|
||||||
cacheTypeValue := reflect.Zero(elemType)
|
|
||||||
var ok bool
|
|
||||||
cacheTypeObj, ok = cacheTypeValue.Interface().(runtime.Object)
|
|
||||||
if !ok {
|
|
||||||
return nil, nil, fmt.Errorf("cannot get cache for %T, its element %T is not a runtime.Object", list, cacheTypeValue.Interface())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Any other list type should have a corresponding non-list type registered
|
||||||
|
// in the scheme. Use that to create a new instance of the non-list type.
|
||||||
|
cacheTypeObj, err := ic.scheme.New(gvk)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
return &gvk, cacheTypeObj, nil
|
return &gvk, cacheTypeObj, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetInformerForKind returns the informer for the GroupVersionKind.
|
// GetInformerForKind returns the informer for the GroupVersionKind.
|
||||||
func (ip *informerCache) GetInformerForKind(ctx context.Context, gvk schema.GroupVersionKind) (Informer, error) {
|
func (ic *informerCache) GetInformerForKind(ctx context.Context, gvk schema.GroupVersionKind) (Informer, error) {
|
||||||
// Map the gvk to an object
|
// Map the gvk to an object
|
||||||
obj, err := ip.Scheme.New(gvk)
|
obj, err := ic.scheme.New(gvk)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
_, i, err := ip.InformersMap.Get(ctx, gvk, obj)
|
_, i, err := ic.Informers.Get(ctx, gvk, obj)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -145,13 +139,13 @@ func (ip *informerCache) GetInformerForKind(ctx context.Context, gvk schema.Grou
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GetInformer returns the informer for the obj.
|
// GetInformer returns the informer for the obj.
|
||||||
func (ip *informerCache) GetInformer(ctx context.Context, obj client.Object) (Informer, error) {
|
func (ic *informerCache) GetInformer(ctx context.Context, obj client.Object) (Informer, error) {
|
||||||
gvk, err := apiutil.GVKForObject(obj, ip.Scheme)
|
gvk, err := apiutil.GVKForObject(obj, ic.scheme)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
_, i, err := ip.InformersMap.Get(ctx, gvk, obj)
|
_, i, err := ic.Informers.Get(ctx, gvk, obj)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -160,7 +154,7 @@ func (ip *informerCache) GetInformer(ctx context.Context, obj client.Object) (In
|
|||||||
|
|
||||||
// NeedLeaderElection implements the LeaderElectionRunnable interface
|
// NeedLeaderElection implements the LeaderElectionRunnable interface
|
||||||
// to indicate that this can be started without requiring the leader lock.
|
// to indicate that this can be started without requiring the leader lock.
|
||||||
func (ip *informerCache) NeedLeaderElection() bool {
|
func (ic *informerCache) NeedLeaderElection() bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -169,8 +163,8 @@ func (ip *informerCache) NeedLeaderElection() bool {
|
|||||||
// to List. For one-to-one compatibility with "normal" field selectors, only return one value.
|
// to List. For one-to-one compatibility with "normal" field selectors, only return one value.
|
||||||
// The values may be anything. They will automatically be prefixed with the namespace of the
|
// The values may be anything. They will automatically be prefixed with the namespace of the
|
||||||
// given object, if present. The objects passed are guaranteed to be objects of the correct type.
|
// given object, if present. The objects passed are guaranteed to be objects of the correct type.
|
||||||
func (ip *informerCache) IndexField(ctx context.Context, obj client.Object, field string, extractValue client.IndexerFunc) error {
|
func (ic *informerCache) IndexField(ctx context.Context, obj client.Object, field string, extractValue client.IndexerFunc) error {
|
||||||
informer, err := ip.GetInformer(ctx, obj)
|
informer, err := ic.GetInformer(ctx, obj)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
4
vendor/sigs.k8s.io/controller-runtime/pkg/cache/internal/cache_reader.go
generated
vendored
4
vendor/sigs.k8s.io/controller-runtime/pkg/cache/internal/cache_reader.go
generated
vendored
@ -27,9 +27,9 @@ import (
|
|||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||||
"k8s.io/client-go/tools/cache"
|
"k8s.io/client-go/tools/cache"
|
||||||
"sigs.k8s.io/controller-runtime/pkg/internal/field/selector"
|
|
||||||
|
|
||||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||||
|
"sigs.k8s.io/controller-runtime/pkg/internal/field/selector"
|
||||||
)
|
)
|
||||||
|
|
||||||
// CacheReader is a client.Reader.
|
// CacheReader is a client.Reader.
|
||||||
@ -147,7 +147,7 @@ func (c *CacheReader) List(_ context.Context, out client.ObjectList, opts ...cli
|
|||||||
}
|
}
|
||||||
obj, isObj := item.(runtime.Object)
|
obj, isObj := item.(runtime.Object)
|
||||||
if !isObj {
|
if !isObj {
|
||||||
return fmt.Errorf("cache contained %T, which is not an Object", obj)
|
return fmt.Errorf("cache contained %T, which is not an Object", item)
|
||||||
}
|
}
|
||||||
meta, err := apimeta.Accessor(obj)
|
meta, err := apimeta.Accessor(obj)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
126
vendor/sigs.k8s.io/controller-runtime/pkg/cache/internal/deleg_map.go
generated
vendored
126
vendor/sigs.k8s.io/controller-runtime/pkg/cache/internal/deleg_map.go
generated
vendored
@ -1,126 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright 2018 The Kubernetes Authors.
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package internal
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"k8s.io/apimachinery/pkg/api/meta"
|
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
||||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
|
||||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
|
||||||
"k8s.io/client-go/rest"
|
|
||||||
"k8s.io/client-go/tools/cache"
|
|
||||||
)
|
|
||||||
|
|
||||||
// InformersMap create and caches Informers for (runtime.Object, schema.GroupVersionKind) pairs.
|
|
||||||
// It uses a standard parameter codec constructed based on the given generated Scheme.
|
|
||||||
type InformersMap struct {
|
|
||||||
// we abstract over the details of structured/unstructured/metadata with the specificInformerMaps
|
|
||||||
// TODO(directxman12): genericize this over different projections now that we have 3 different maps
|
|
||||||
|
|
||||||
structured *specificInformersMap
|
|
||||||
unstructured *specificInformersMap
|
|
||||||
metadata *specificInformersMap
|
|
||||||
|
|
||||||
// Scheme maps runtime.Objects to GroupVersionKinds
|
|
||||||
Scheme *runtime.Scheme
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewInformersMap creates a new InformersMap that can create informers for
|
|
||||||
// both structured and unstructured objects.
|
|
||||||
func NewInformersMap(config *rest.Config,
|
|
||||||
scheme *runtime.Scheme,
|
|
||||||
mapper meta.RESTMapper,
|
|
||||||
resync time.Duration,
|
|
||||||
namespace string,
|
|
||||||
selectors SelectorsByGVK,
|
|
||||||
disableDeepCopy DisableDeepCopyByGVK,
|
|
||||||
transformers TransformFuncByObject,
|
|
||||||
) *InformersMap {
|
|
||||||
return &InformersMap{
|
|
||||||
structured: newStructuredInformersMap(config, scheme, mapper, resync, namespace, selectors, disableDeepCopy, transformers),
|
|
||||||
unstructured: newUnstructuredInformersMap(config, scheme, mapper, resync, namespace, selectors, disableDeepCopy, transformers),
|
|
||||||
metadata: newMetadataInformersMap(config, scheme, mapper, resync, namespace, selectors, disableDeepCopy, transformers),
|
|
||||||
|
|
||||||
Scheme: scheme,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Start calls Run on each of the informers and sets started to true. Blocks on the context.
|
|
||||||
func (m *InformersMap) Start(ctx context.Context) error {
|
|
||||||
go m.structured.Start(ctx)
|
|
||||||
go m.unstructured.Start(ctx)
|
|
||||||
go m.metadata.Start(ctx)
|
|
||||||
<-ctx.Done()
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// WaitForCacheSync waits until all the caches have been started and synced.
|
|
||||||
func (m *InformersMap) WaitForCacheSync(ctx context.Context) bool {
|
|
||||||
syncedFuncs := append([]cache.InformerSynced(nil), m.structured.HasSyncedFuncs()...)
|
|
||||||
syncedFuncs = append(syncedFuncs, m.unstructured.HasSyncedFuncs()...)
|
|
||||||
syncedFuncs = append(syncedFuncs, m.metadata.HasSyncedFuncs()...)
|
|
||||||
|
|
||||||
if !m.structured.waitForStarted(ctx) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
if !m.unstructured.waitForStarted(ctx) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
if !m.metadata.waitForStarted(ctx) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return cache.WaitForCacheSync(ctx.Done(), syncedFuncs...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get will create a new Informer and add it to the map of InformersMap if none exists. Returns
|
|
||||||
// the Informer from the map.
|
|
||||||
func (m *InformersMap) Get(ctx context.Context, gvk schema.GroupVersionKind, obj runtime.Object) (bool, *MapEntry, error) {
|
|
||||||
switch obj.(type) {
|
|
||||||
case *unstructured.Unstructured:
|
|
||||||
return m.unstructured.Get(ctx, gvk, obj)
|
|
||||||
case *unstructured.UnstructuredList:
|
|
||||||
return m.unstructured.Get(ctx, gvk, obj)
|
|
||||||
case *metav1.PartialObjectMetadata:
|
|
||||||
return m.metadata.Get(ctx, gvk, obj)
|
|
||||||
case *metav1.PartialObjectMetadataList:
|
|
||||||
return m.metadata.Get(ctx, gvk, obj)
|
|
||||||
default:
|
|
||||||
return m.structured.Get(ctx, gvk, obj)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// newStructuredInformersMap creates a new InformersMap for structured objects.
|
|
||||||
func newStructuredInformersMap(config *rest.Config, scheme *runtime.Scheme, mapper meta.RESTMapper, resync time.Duration,
|
|
||||||
namespace string, selectors SelectorsByGVK, disableDeepCopy DisableDeepCopyByGVK, transformers TransformFuncByObject) *specificInformersMap {
|
|
||||||
return newSpecificInformersMap(config, scheme, mapper, resync, namespace, selectors, disableDeepCopy, transformers, createStructuredListWatch)
|
|
||||||
}
|
|
||||||
|
|
||||||
// newUnstructuredInformersMap creates a new InformersMap for unstructured objects.
|
|
||||||
func newUnstructuredInformersMap(config *rest.Config, scheme *runtime.Scheme, mapper meta.RESTMapper, resync time.Duration,
|
|
||||||
namespace string, selectors SelectorsByGVK, disableDeepCopy DisableDeepCopyByGVK, transformers TransformFuncByObject) *specificInformersMap {
|
|
||||||
return newSpecificInformersMap(config, scheme, mapper, resync, namespace, selectors, disableDeepCopy, transformers, createUnstructuredListWatch)
|
|
||||||
}
|
|
||||||
|
|
||||||
// newMetadataInformersMap creates a new InformersMap for metadata-only objects.
|
|
||||||
func newMetadataInformersMap(config *rest.Config, scheme *runtime.Scheme, mapper meta.RESTMapper, resync time.Duration,
|
|
||||||
namespace string, selectors SelectorsByGVK, disableDeepCopy DisableDeepCopyByGVK, transformers TransformFuncByObject) *specificInformersMap {
|
|
||||||
return newSpecificInformersMap(config, scheme, mapper, resync, namespace, selectors, disableDeepCopy, transformers, createMetadataListWatch)
|
|
||||||
}
|
|
35
vendor/sigs.k8s.io/controller-runtime/pkg/cache/internal/disabledeepcopy.go
generated
vendored
35
vendor/sigs.k8s.io/controller-runtime/pkg/cache/internal/disabledeepcopy.go
generated
vendored
@ -1,35 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright 2021 The Kubernetes Authors.
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package internal
|
|
||||||
|
|
||||||
import "k8s.io/apimachinery/pkg/runtime/schema"
|
|
||||||
|
|
||||||
// GroupVersionKindAll is the argument to represent all GroupVersionKind types.
|
|
||||||
var GroupVersionKindAll = schema.GroupVersionKind{}
|
|
||||||
|
|
||||||
// DisableDeepCopyByGVK associate a GroupVersionKind to disable DeepCopy during get or list from cache.
|
|
||||||
type DisableDeepCopyByGVK map[schema.GroupVersionKind]bool
|
|
||||||
|
|
||||||
// IsDisabled returns whether a GroupVersionKind is disabled DeepCopy.
|
|
||||||
func (disableByGVK DisableDeepCopyByGVK) IsDisabled(gvk schema.GroupVersionKind) bool {
|
|
||||||
if d, ok := disableByGVK[gvk]; ok {
|
|
||||||
return d
|
|
||||||
} else if d, ok = disableByGVK[GroupVersionKindAll]; ok {
|
|
||||||
return d
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
560
vendor/sigs.k8s.io/controller-runtime/pkg/cache/internal/informers.go
generated
vendored
Normal file
560
vendor/sigs.k8s.io/controller-runtime/pkg/cache/internal/informers.go
generated
vendored
Normal file
@ -0,0 +1,560 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2018 The Kubernetes Authors.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package internal
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"math/rand"
|
||||||
|
"net/http"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||||
|
"k8s.io/apimachinery/pkg/api/meta"
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||||
|
"k8s.io/apimachinery/pkg/runtime/serializer"
|
||||||
|
"k8s.io/apimachinery/pkg/watch"
|
||||||
|
"k8s.io/client-go/dynamic"
|
||||||
|
"k8s.io/client-go/metadata"
|
||||||
|
"k8s.io/client-go/rest"
|
||||||
|
"k8s.io/client-go/tools/cache"
|
||||||
|
"sigs.k8s.io/controller-runtime/pkg/client/apiutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
// InformersOpts configures an InformerMap.
|
||||||
|
type InformersOpts struct {
|
||||||
|
HTTPClient *http.Client
|
||||||
|
Scheme *runtime.Scheme
|
||||||
|
Mapper meta.RESTMapper
|
||||||
|
ResyncPeriod time.Duration
|
||||||
|
Namespace string
|
||||||
|
ByGVK map[schema.GroupVersionKind]InformersOptsByGVK
|
||||||
|
}
|
||||||
|
|
||||||
|
// InformersOptsByGVK configured additional by group version kind (or object)
|
||||||
|
// in an InformerMap.
|
||||||
|
type InformersOptsByGVK struct {
|
||||||
|
Selector Selector
|
||||||
|
Transform cache.TransformFunc
|
||||||
|
UnsafeDisableDeepCopy *bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewInformers creates a new InformersMap that can create informers under the hood.
|
||||||
|
func NewInformers(config *rest.Config, options *InformersOpts) *Informers {
|
||||||
|
return &Informers{
|
||||||
|
config: config,
|
||||||
|
httpClient: options.HTTPClient,
|
||||||
|
scheme: options.Scheme,
|
||||||
|
mapper: options.Mapper,
|
||||||
|
tracker: tracker{
|
||||||
|
Structured: make(map[schema.GroupVersionKind]*Cache),
|
||||||
|
Unstructured: make(map[schema.GroupVersionKind]*Cache),
|
||||||
|
Metadata: make(map[schema.GroupVersionKind]*Cache),
|
||||||
|
},
|
||||||
|
codecs: serializer.NewCodecFactory(options.Scheme),
|
||||||
|
paramCodec: runtime.NewParameterCodec(options.Scheme),
|
||||||
|
resync: options.ResyncPeriod,
|
||||||
|
startWait: make(chan struct{}),
|
||||||
|
namespace: options.Namespace,
|
||||||
|
byGVK: options.ByGVK,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cache contains the cached data for an Cache.
|
||||||
|
type Cache struct {
|
||||||
|
// Informer is the cached informer
|
||||||
|
Informer cache.SharedIndexInformer
|
||||||
|
|
||||||
|
// CacheReader wraps Informer and implements the CacheReader interface for a single type
|
||||||
|
Reader CacheReader
|
||||||
|
}
|
||||||
|
|
||||||
|
type tracker struct {
|
||||||
|
Structured map[schema.GroupVersionKind]*Cache
|
||||||
|
Unstructured map[schema.GroupVersionKind]*Cache
|
||||||
|
Metadata map[schema.GroupVersionKind]*Cache
|
||||||
|
}
|
||||||
|
|
||||||
|
// Informers create and caches Informers for (runtime.Object, schema.GroupVersionKind) pairs.
|
||||||
|
// It uses a standard parameter codec constructed based on the given generated Scheme.
|
||||||
|
type Informers struct {
|
||||||
|
// httpClient is used to create a new REST client
|
||||||
|
httpClient *http.Client
|
||||||
|
|
||||||
|
// scheme maps runtime.Objects to GroupVersionKinds
|
||||||
|
scheme *runtime.Scheme
|
||||||
|
|
||||||
|
// config is used to talk to the apiserver
|
||||||
|
config *rest.Config
|
||||||
|
|
||||||
|
// mapper maps GroupVersionKinds to Resources
|
||||||
|
mapper meta.RESTMapper
|
||||||
|
|
||||||
|
// tracker tracks informers keyed by their type and groupVersionKind
|
||||||
|
tracker tracker
|
||||||
|
|
||||||
|
// codecs is used to create a new REST client
|
||||||
|
codecs serializer.CodecFactory
|
||||||
|
|
||||||
|
// paramCodec is used by list and watch
|
||||||
|
paramCodec runtime.ParameterCodec
|
||||||
|
|
||||||
|
// resync is the base frequency the informers are resynced
|
||||||
|
// a 10 percent jitter will be added to the resync period between informers
|
||||||
|
// so that all informers will not send list requests simultaneously.
|
||||||
|
resync time.Duration
|
||||||
|
|
||||||
|
// mu guards access to the map
|
||||||
|
mu sync.RWMutex
|
||||||
|
|
||||||
|
// started is true if the informers have been started
|
||||||
|
started bool
|
||||||
|
|
||||||
|
// startWait is a channel that is closed after the
|
||||||
|
// informer has been started.
|
||||||
|
startWait chan struct{}
|
||||||
|
|
||||||
|
// waitGroup is the wait group that is used to wait for all informers to stop
|
||||||
|
waitGroup sync.WaitGroup
|
||||||
|
|
||||||
|
// stopped is true if the informers have been stopped
|
||||||
|
stopped bool
|
||||||
|
|
||||||
|
// ctx is the context to stop informers
|
||||||
|
ctx context.Context
|
||||||
|
|
||||||
|
// namespace is the namespace that all ListWatches are restricted to
|
||||||
|
// default or empty string means all namespaces
|
||||||
|
namespace string
|
||||||
|
|
||||||
|
byGVK map[schema.GroupVersionKind]InformersOptsByGVK
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ip *Informers) getSelector(gvk schema.GroupVersionKind) Selector {
|
||||||
|
if ip.byGVK == nil {
|
||||||
|
return Selector{}
|
||||||
|
}
|
||||||
|
if res, ok := ip.byGVK[gvk]; ok {
|
||||||
|
return res.Selector
|
||||||
|
}
|
||||||
|
if res, ok := ip.byGVK[schema.GroupVersionKind{}]; ok {
|
||||||
|
return res.Selector
|
||||||
|
}
|
||||||
|
return Selector{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ip *Informers) getTransform(gvk schema.GroupVersionKind) cache.TransformFunc {
|
||||||
|
if ip.byGVK == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if res, ok := ip.byGVK[gvk]; ok {
|
||||||
|
return res.Transform
|
||||||
|
}
|
||||||
|
if res, ok := ip.byGVK[schema.GroupVersionKind{}]; ok {
|
||||||
|
return res.Transform
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ip *Informers) getDisableDeepCopy(gvk schema.GroupVersionKind) bool {
|
||||||
|
if ip.byGVK == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if res, ok := ip.byGVK[gvk]; ok && res.UnsafeDisableDeepCopy != nil {
|
||||||
|
return *res.UnsafeDisableDeepCopy
|
||||||
|
}
|
||||||
|
if res, ok := ip.byGVK[schema.GroupVersionKind{}]; ok && res.UnsafeDisableDeepCopy != nil {
|
||||||
|
return *res.UnsafeDisableDeepCopy
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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() {
|
||||||
|
ip.mu.Lock()
|
||||||
|
defer ip.mu.Unlock()
|
||||||
|
|
||||||
|
// Set the context so it can be passed to informers that are added later
|
||||||
|
ip.ctx = ctx
|
||||||
|
|
||||||
|
// Start each informer
|
||||||
|
for _, i := range ip.tracker.Structured {
|
||||||
|
ip.startInformerLocked(i.Informer)
|
||||||
|
}
|
||||||
|
for _, i := range ip.tracker.Unstructured {
|
||||||
|
ip.startInformerLocked(i.Informer)
|
||||||
|
}
|
||||||
|
for _, i := range ip.tracker.Metadata {
|
||||||
|
ip.startInformerLocked(i.Informer)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set started to true so we immediately start any informers added later.
|
||||||
|
ip.started = true
|
||||||
|
close(ip.startWait)
|
||||||
|
}()
|
||||||
|
<-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
|
||||||
|
ip.mu.Unlock()
|
||||||
|
ip.waitGroup.Wait() // Block until all informers have stopped
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ip *Informers) startInformerLocked(informer cache.SharedIndexInformer) {
|
||||||
|
// Don't start the informer in case we are already waiting for the items in
|
||||||
|
// the waitGroup to finish, since waitGroups don't support waiting and adding
|
||||||
|
// at the same time.
|
||||||
|
if ip.stopped {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ip.waitGroup.Add(1)
|
||||||
|
go func() {
|
||||||
|
defer ip.waitGroup.Done()
|
||||||
|
informer.Run(ip.ctx.Done())
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ip *Informers) waitForStarted(ctx context.Context) bool {
|
||||||
|
select {
|
||||||
|
case <-ip.startWait:
|
||||||
|
return true
|
||||||
|
case <-ctx.Done():
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// getHasSyncedFuncs returns all the HasSynced functions for the informers in this map.
|
||||||
|
func (ip *Informers) getHasSyncedFuncs() []cache.InformerSynced {
|
||||||
|
ip.mu.RLock()
|
||||||
|
defer ip.mu.RUnlock()
|
||||||
|
|
||||||
|
res := make([]cache.InformerSynced, 0,
|
||||||
|
len(ip.tracker.Structured)+len(ip.tracker.Unstructured)+len(ip.tracker.Metadata),
|
||||||
|
)
|
||||||
|
for _, i := range ip.tracker.Structured {
|
||||||
|
res = append(res, i.Informer.HasSynced)
|
||||||
|
}
|
||||||
|
for _, i := range ip.tracker.Unstructured {
|
||||||
|
res = append(res, i.Informer.HasSynced)
|
||||||
|
}
|
||||||
|
for _, i := range ip.tracker.Metadata {
|
||||||
|
res = append(res, i.Informer.HasSynced)
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
// WaitForCacheSync waits until all the caches have been started and synced.
|
||||||
|
func (ip *Informers) WaitForCacheSync(ctx context.Context) bool {
|
||||||
|
if !ip.waitForStarted(ctx) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return cache.WaitForCacheSync(ctx.Done(), ip.getHasSyncedFuncs()...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ip *Informers) get(gvk schema.GroupVersionKind, obj runtime.Object) (res *Cache, started bool, ok bool) {
|
||||||
|
ip.mu.RLock()
|
||||||
|
defer ip.mu.RUnlock()
|
||||||
|
i, ok := ip.informersByType(obj)[gvk]
|
||||||
|
return i, ip.started, ok
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get will create a new Informer and add it to the map of specificInformersMap if none exists. Returns
|
||||||
|
// the Informer from the map.
|
||||||
|
func (ip *Informers) Get(ctx context.Context, gvk schema.GroupVersionKind, obj runtime.Object) (bool, *Cache, error) {
|
||||||
|
// Return the informer if it is found
|
||||||
|
i, started, ok := ip.get(gvk, obj)
|
||||||
|
if !ok {
|
||||||
|
var err error
|
||||||
|
if i, started, err = ip.addInformerToMap(gvk, obj); err != nil {
|
||||||
|
return started, nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if started && !i.Informer.HasSynced() {
|
||||||
|
// Wait for it to sync before returning the Informer so that folks don't read from a stale cache.
|
||||||
|
if !cache.WaitForCacheSync(ctx.Done(), i.Informer.HasSynced) {
|
||||||
|
return started, nil, apierrors.NewTimeoutError(fmt.Sprintf("failed waiting for %T Informer to sync", obj), 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return started, i, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ip *Informers) informersByType(obj runtime.Object) map[schema.GroupVersionKind]*Cache {
|
||||||
|
switch obj.(type) {
|
||||||
|
case runtime.Unstructured:
|
||||||
|
return ip.tracker.Unstructured
|
||||||
|
case *metav1.PartialObjectMetadata, *metav1.PartialObjectMetadataList:
|
||||||
|
return ip.tracker.Metadata
|
||||||
|
default:
|
||||||
|
return ip.tracker.Structured
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ip *Informers) addInformerToMap(gvk schema.GroupVersionKind, obj runtime.Object) (*Cache, bool, error) {
|
||||||
|
ip.mu.Lock()
|
||||||
|
defer ip.mu.Unlock()
|
||||||
|
|
||||||
|
// Check the cache to see if we already have an Informer. If we do, return the Informer.
|
||||||
|
// This is for the case where 2 routines tried to get the informer when it wasn't in the map
|
||||||
|
// so neither returned early, but the first one created it.
|
||||||
|
if i, ok := ip.informersByType(obj)[gvk]; ok {
|
||||||
|
return i, ip.started, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a NewSharedIndexInformer and add it to the map.
|
||||||
|
listWatcher, err := ip.makeListWatcher(gvk, obj)
|
||||||
|
if err != nil {
|
||||||
|
return nil, false, err
|
||||||
|
}
|
||||||
|
sharedIndexInformer := cache.NewSharedIndexInformer(&cache.ListWatch{
|
||||||
|
ListFunc: func(opts metav1.ListOptions) (runtime.Object, error) {
|
||||||
|
ip.getSelector(gvk).ApplyToList(&opts)
|
||||||
|
return listWatcher.ListFunc(opts)
|
||||||
|
},
|
||||||
|
WatchFunc: func(opts metav1.ListOptions) (watch.Interface, error) {
|
||||||
|
ip.getSelector(gvk).ApplyToList(&opts)
|
||||||
|
opts.Watch = true // Watch needs to be set to true separately
|
||||||
|
return listWatcher.WatchFunc(opts)
|
||||||
|
},
|
||||||
|
}, obj, calculateResyncPeriod(ip.resync), cache.Indexers{
|
||||||
|
cache.NamespaceIndex: cache.MetaNamespaceIndexFunc,
|
||||||
|
})
|
||||||
|
|
||||||
|
// Check to see if there is a transformer for this gvk
|
||||||
|
if err := sharedIndexInformer.SetTransform(ip.getTransform(gvk)); err != nil {
|
||||||
|
return nil, false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
mapping, err := ip.mapper.RESTMapping(gvk.GroupKind(), gvk.Version)
|
||||||
|
if err != nil {
|
||||||
|
return nil, false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the new entry and set it in the map.
|
||||||
|
i := &Cache{
|
||||||
|
Informer: sharedIndexInformer,
|
||||||
|
Reader: CacheReader{
|
||||||
|
indexer: sharedIndexInformer.GetIndexer(),
|
||||||
|
groupVersionKind: gvk,
|
||||||
|
scopeName: mapping.Scope.Name(),
|
||||||
|
disableDeepCopy: ip.getDisableDeepCopy(gvk),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
ip.informersByType(obj)[gvk] = i
|
||||||
|
|
||||||
|
// Start the informer in case the InformersMap has started, otherwise it will be
|
||||||
|
// started when the InformersMap starts.
|
||||||
|
if ip.started {
|
||||||
|
ip.startInformerLocked(i.Informer)
|
||||||
|
}
|
||||||
|
return i, ip.started, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ip *Informers) makeListWatcher(gvk schema.GroupVersionKind, obj runtime.Object) (*cache.ListWatch, error) {
|
||||||
|
// Kubernetes APIs work against Resources, not GroupVersionKinds. Map the
|
||||||
|
// groupVersionKind to the Resource API we will use.
|
||||||
|
mapping, err := ip.mapper.RESTMapping(gvk.GroupKind(), gvk.Version)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Figure out if the GVK we're dealing with is global, or namespace scoped.
|
||||||
|
var namespace string
|
||||||
|
if mapping.Scope.Name() == meta.RESTScopeNameNamespace {
|
||||||
|
namespace = restrictNamespaceBySelector(ip.namespace, ip.getSelector(gvk))
|
||||||
|
}
|
||||||
|
|
||||||
|
switch obj.(type) {
|
||||||
|
//
|
||||||
|
// Unstructured
|
||||||
|
//
|
||||||
|
case runtime.Unstructured:
|
||||||
|
// If the rest configuration has a negotiated serializer passed in,
|
||||||
|
// we should remove it and use the one that the dynamic client sets for us.
|
||||||
|
cfg := rest.CopyConfig(ip.config)
|
||||||
|
cfg.NegotiatedSerializer = nil
|
||||||
|
dynamicClient, err := dynamic.NewForConfigAndClient(cfg, ip.httpClient)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
resources := dynamicClient.Resource(mapping.Resource)
|
||||||
|
return &cache.ListWatch{
|
||||||
|
ListFunc: func(opts metav1.ListOptions) (runtime.Object, error) {
|
||||||
|
if namespace != "" {
|
||||||
|
return resources.Namespace(namespace).List(ip.ctx, opts)
|
||||||
|
}
|
||||||
|
return resources.List(ip.ctx, opts)
|
||||||
|
},
|
||||||
|
// Setup the watch function
|
||||||
|
WatchFunc: func(opts metav1.ListOptions) (watch.Interface, error) {
|
||||||
|
if namespace != "" {
|
||||||
|
return resources.Namespace(namespace).Watch(ip.ctx, opts)
|
||||||
|
}
|
||||||
|
return resources.Watch(ip.ctx, opts)
|
||||||
|
},
|
||||||
|
}, nil
|
||||||
|
//
|
||||||
|
// Metadata
|
||||||
|
//
|
||||||
|
case *metav1.PartialObjectMetadata, *metav1.PartialObjectMetadataList:
|
||||||
|
// Always clear the negotiated serializer and use the one
|
||||||
|
// set from the metadata client.
|
||||||
|
cfg := rest.CopyConfig(ip.config)
|
||||||
|
cfg.NegotiatedSerializer = nil
|
||||||
|
|
||||||
|
// Grab the metadata metadataClient.
|
||||||
|
metadataClient, err := metadata.NewForConfigAndClient(cfg, ip.httpClient)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
resources := metadataClient.Resource(mapping.Resource)
|
||||||
|
|
||||||
|
return &cache.ListWatch{
|
||||||
|
ListFunc: func(opts metav1.ListOptions) (runtime.Object, error) {
|
||||||
|
var (
|
||||||
|
list *metav1.PartialObjectMetadataList
|
||||||
|
err error
|
||||||
|
)
|
||||||
|
if namespace != "" {
|
||||||
|
list, err = resources.Namespace(namespace).List(ip.ctx, opts)
|
||||||
|
} else {
|
||||||
|
list, err = resources.List(ip.ctx, opts)
|
||||||
|
}
|
||||||
|
if list != nil {
|
||||||
|
for i := range list.Items {
|
||||||
|
list.Items[i].SetGroupVersionKind(gvk)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return list, err
|
||||||
|
},
|
||||||
|
// Setup the watch function
|
||||||
|
WatchFunc: func(opts metav1.ListOptions) (watcher watch.Interface, err error) {
|
||||||
|
if namespace != "" {
|
||||||
|
watcher, err = resources.Namespace(namespace).Watch(ip.ctx, opts)
|
||||||
|
} else {
|
||||||
|
watcher, err = resources.Watch(ip.ctx, opts)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return newGVKFixupWatcher(gvk, watcher), nil
|
||||||
|
},
|
||||||
|
}, nil
|
||||||
|
//
|
||||||
|
// Structured.
|
||||||
|
//
|
||||||
|
default:
|
||||||
|
client, err := apiutil.RESTClientForGVK(gvk, false, ip.config, ip.codecs, ip.httpClient)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
listGVK := gvk.GroupVersion().WithKind(gvk.Kind + "List")
|
||||||
|
listObj, err := ip.scheme.New(listGVK)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &cache.ListWatch{
|
||||||
|
ListFunc: func(opts metav1.ListOptions) (runtime.Object, error) {
|
||||||
|
// Build the request.
|
||||||
|
req := client.Get().Resource(mapping.Resource.Resource).VersionedParams(&opts, ip.paramCodec)
|
||||||
|
if namespace != "" {
|
||||||
|
req.Namespace(namespace)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the resulting object, and execute the request.
|
||||||
|
res := listObj.DeepCopyObject()
|
||||||
|
if err := req.Do(ip.ctx).Into(res); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return res, nil
|
||||||
|
},
|
||||||
|
// Setup the watch function
|
||||||
|
WatchFunc: func(opts metav1.ListOptions) (watch.Interface, error) {
|
||||||
|
// Build the request.
|
||||||
|
req := client.Get().Resource(mapping.Resource.Resource).VersionedParams(&opts, ip.paramCodec)
|
||||||
|
if namespace != "" {
|
||||||
|
req.Namespace(namespace)
|
||||||
|
}
|
||||||
|
// Call the watch.
|
||||||
|
return req.Watch(ip.ctx)
|
||||||
|
},
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// newGVKFixupWatcher adds a wrapper that preserves the GVK information when
|
||||||
|
// events come in.
|
||||||
|
//
|
||||||
|
// This works around a bug where GVK information is not passed into mapping
|
||||||
|
// functions when using the OnlyMetadata option in the builder.
|
||||||
|
// This issue is most likely caused by kubernetes/kubernetes#80609.
|
||||||
|
// See kubernetes-sigs/controller-runtime#1484.
|
||||||
|
//
|
||||||
|
// This was originally implemented as a cache.ResourceEventHandler wrapper but
|
||||||
|
// that contained a data race which was resolved by setting the GVK in a watch
|
||||||
|
// wrapper, before the objects are written to the cache.
|
||||||
|
// See kubernetes-sigs/controller-runtime#1650.
|
||||||
|
//
|
||||||
|
// The original watch wrapper was found to be incompatible with
|
||||||
|
// k8s.io/client-go/tools/cache.Reflector so it has been re-implemented as a
|
||||||
|
// watch.Filter which is compatible.
|
||||||
|
// See kubernetes-sigs/controller-runtime#1789.
|
||||||
|
func newGVKFixupWatcher(gvk schema.GroupVersionKind, watcher watch.Interface) watch.Interface {
|
||||||
|
return watch.Filter(
|
||||||
|
watcher,
|
||||||
|
func(in watch.Event) (watch.Event, bool) {
|
||||||
|
in.Object.GetObjectKind().SetGroupVersionKind(gvk)
|
||||||
|
return in, true
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// calculateResyncPeriod returns a duration based on the desired input
|
||||||
|
// this is so that multiple controllers don't get into lock-step and all
|
||||||
|
// hammer the apiserver with list requests simultaneously.
|
||||||
|
func calculateResyncPeriod(resync time.Duration) time.Duration {
|
||||||
|
// the factor will fall into [0.9, 1.1)
|
||||||
|
factor := rand.Float64()/5.0 + 0.9 //nolint:gosec
|
||||||
|
return time.Duration(float64(resync.Nanoseconds()) * factor)
|
||||||
|
}
|
||||||
|
|
||||||
|
// restrictNamespaceBySelector returns either a global restriction for all ListWatches
|
||||||
|
// if not default/empty, or the namespace that a ListWatch for the specific resource
|
||||||
|
// is restricted to, based on a specified field selector for metadata.namespace field.
|
||||||
|
func restrictNamespaceBySelector(namespaceOpt string, s Selector) string {
|
||||||
|
if namespaceOpt != "" {
|
||||||
|
// namespace is already restricted
|
||||||
|
return namespaceOpt
|
||||||
|
}
|
||||||
|
fieldSelector := s.Field
|
||||||
|
if fieldSelector == nil || fieldSelector.Empty() {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
// check whether a selector includes the namespace field
|
||||||
|
value, found := fieldSelector.RequiresExactMatch("metadata.namespace")
|
||||||
|
if found {
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
480
vendor/sigs.k8s.io/controller-runtime/pkg/cache/internal/informers_map.go
generated
vendored
480
vendor/sigs.k8s.io/controller-runtime/pkg/cache/internal/informers_map.go
generated
vendored
@ -1,480 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright 2018 The Kubernetes Authors.
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package internal
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
"math/rand"
|
|
||||||
"sync"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
|
||||||
"k8s.io/apimachinery/pkg/api/meta"
|
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
|
||||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
|
||||||
"k8s.io/apimachinery/pkg/runtime/serializer"
|
|
||||||
"k8s.io/apimachinery/pkg/watch"
|
|
||||||
"k8s.io/client-go/dynamic"
|
|
||||||
"k8s.io/client-go/metadata"
|
|
||||||
"k8s.io/client-go/rest"
|
|
||||||
"k8s.io/client-go/tools/cache"
|
|
||||||
|
|
||||||
"sigs.k8s.io/controller-runtime/pkg/client/apiutil"
|
|
||||||
)
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
rand.Seed(time.Now().UnixNano())
|
|
||||||
}
|
|
||||||
|
|
||||||
// clientListWatcherFunc knows how to create a ListWatcher.
|
|
||||||
type createListWatcherFunc func(gvk schema.GroupVersionKind, ip *specificInformersMap) (*cache.ListWatch, error)
|
|
||||||
|
|
||||||
// newSpecificInformersMap returns a new specificInformersMap (like
|
|
||||||
// the generical InformersMap, except that it doesn't implement WaitForCacheSync).
|
|
||||||
func newSpecificInformersMap(config *rest.Config,
|
|
||||||
scheme *runtime.Scheme,
|
|
||||||
mapper meta.RESTMapper,
|
|
||||||
resync time.Duration,
|
|
||||||
namespace string,
|
|
||||||
selectors SelectorsByGVK,
|
|
||||||
disableDeepCopy DisableDeepCopyByGVK,
|
|
||||||
transformers TransformFuncByObject,
|
|
||||||
createListWatcher createListWatcherFunc,
|
|
||||||
) *specificInformersMap {
|
|
||||||
ip := &specificInformersMap{
|
|
||||||
config: config,
|
|
||||||
Scheme: scheme,
|
|
||||||
mapper: mapper,
|
|
||||||
informersByGVK: make(map[schema.GroupVersionKind]*MapEntry),
|
|
||||||
codecs: serializer.NewCodecFactory(scheme),
|
|
||||||
paramCodec: runtime.NewParameterCodec(scheme),
|
|
||||||
resync: resync,
|
|
||||||
startWait: make(chan struct{}),
|
|
||||||
createListWatcher: createListWatcher,
|
|
||||||
namespace: namespace,
|
|
||||||
selectors: selectors.forGVK,
|
|
||||||
disableDeepCopy: disableDeepCopy,
|
|
||||||
transformers: transformers,
|
|
||||||
}
|
|
||||||
return ip
|
|
||||||
}
|
|
||||||
|
|
||||||
// MapEntry contains the cached data for an Informer.
|
|
||||||
type MapEntry struct {
|
|
||||||
// Informer is the cached informer
|
|
||||||
Informer cache.SharedIndexInformer
|
|
||||||
|
|
||||||
// CacheReader wraps Informer and implements the CacheReader interface for a single type
|
|
||||||
Reader CacheReader
|
|
||||||
}
|
|
||||||
|
|
||||||
// specificInformersMap create and caches Informers for (runtime.Object, schema.GroupVersionKind) pairs.
|
|
||||||
// It uses a standard parameter codec constructed based on the given generated Scheme.
|
|
||||||
type specificInformersMap struct {
|
|
||||||
// Scheme maps runtime.Objects to GroupVersionKinds
|
|
||||||
Scheme *runtime.Scheme
|
|
||||||
|
|
||||||
// config is used to talk to the apiserver
|
|
||||||
config *rest.Config
|
|
||||||
|
|
||||||
// mapper maps GroupVersionKinds to Resources
|
|
||||||
mapper meta.RESTMapper
|
|
||||||
|
|
||||||
// informersByGVK is the cache of informers keyed by groupVersionKind
|
|
||||||
informersByGVK map[schema.GroupVersionKind]*MapEntry
|
|
||||||
|
|
||||||
// codecs is used to create a new REST client
|
|
||||||
codecs serializer.CodecFactory
|
|
||||||
|
|
||||||
// paramCodec is used by list and watch
|
|
||||||
paramCodec runtime.ParameterCodec
|
|
||||||
|
|
||||||
// stop is the stop channel to stop informers
|
|
||||||
stop <-chan struct{}
|
|
||||||
|
|
||||||
// resync is the base frequency the informers are resynced
|
|
||||||
// a 10 percent jitter will be added to the resync period between informers
|
|
||||||
// so that all informers will not send list requests simultaneously.
|
|
||||||
resync time.Duration
|
|
||||||
|
|
||||||
// mu guards access to the map
|
|
||||||
mu sync.RWMutex
|
|
||||||
|
|
||||||
// start is true if the informers have been started
|
|
||||||
started bool
|
|
||||||
|
|
||||||
// startWait is a channel that is closed after the
|
|
||||||
// informer has been started.
|
|
||||||
startWait chan struct{}
|
|
||||||
|
|
||||||
// createClient knows how to create a client and a list object,
|
|
||||||
// and allows for abstracting over the particulars of structured vs
|
|
||||||
// unstructured objects.
|
|
||||||
createListWatcher createListWatcherFunc
|
|
||||||
|
|
||||||
// namespace is the namespace that all ListWatches are restricted to
|
|
||||||
// default or empty string means all namespaces
|
|
||||||
namespace string
|
|
||||||
|
|
||||||
// selectors are the label or field selectors that will be added to the
|
|
||||||
// ListWatch ListOptions.
|
|
||||||
selectors func(gvk schema.GroupVersionKind) Selector
|
|
||||||
|
|
||||||
// disableDeepCopy indicates not to deep copy objects during get or list objects.
|
|
||||||
disableDeepCopy DisableDeepCopyByGVK
|
|
||||||
|
|
||||||
// transform funcs are applied to objects before they are committed to the cache
|
|
||||||
transformers TransformFuncByObject
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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 *specificInformersMap) Start(ctx context.Context) {
|
|
||||||
func() {
|
|
||||||
ip.mu.Lock()
|
|
||||||
defer ip.mu.Unlock()
|
|
||||||
|
|
||||||
// Set the stop channel so it can be passed to informers that are added later
|
|
||||||
ip.stop = ctx.Done()
|
|
||||||
|
|
||||||
// Start each informer
|
|
||||||
for _, informer := range ip.informersByGVK {
|
|
||||||
go informer.Informer.Run(ctx.Done())
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set started to true so we immediately start any informers added later.
|
|
||||||
ip.started = true
|
|
||||||
close(ip.startWait)
|
|
||||||
}()
|
|
||||||
<-ctx.Done()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ip *specificInformersMap) waitForStarted(ctx context.Context) bool {
|
|
||||||
select {
|
|
||||||
case <-ip.startWait:
|
|
||||||
return true
|
|
||||||
case <-ctx.Done():
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// HasSyncedFuncs returns all the HasSynced functions for the informers in this map.
|
|
||||||
func (ip *specificInformersMap) HasSyncedFuncs() []cache.InformerSynced {
|
|
||||||
ip.mu.RLock()
|
|
||||||
defer ip.mu.RUnlock()
|
|
||||||
syncedFuncs := make([]cache.InformerSynced, 0, len(ip.informersByGVK))
|
|
||||||
for _, informer := range ip.informersByGVK {
|
|
||||||
syncedFuncs = append(syncedFuncs, informer.Informer.HasSynced)
|
|
||||||
}
|
|
||||||
return syncedFuncs
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get will create a new Informer and add it to the map of specificInformersMap if none exists. Returns
|
|
||||||
// the Informer from the map.
|
|
||||||
func (ip *specificInformersMap) Get(ctx context.Context, gvk schema.GroupVersionKind, obj runtime.Object) (bool, *MapEntry, error) {
|
|
||||||
// Return the informer if it is found
|
|
||||||
i, started, ok := func() (*MapEntry, bool, bool) {
|
|
||||||
ip.mu.RLock()
|
|
||||||
defer ip.mu.RUnlock()
|
|
||||||
i, ok := ip.informersByGVK[gvk]
|
|
||||||
return i, ip.started, ok
|
|
||||||
}()
|
|
||||||
|
|
||||||
if !ok {
|
|
||||||
var err error
|
|
||||||
if i, started, err = ip.addInformerToMap(gvk, obj); err != nil {
|
|
||||||
return started, nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if started && !i.Informer.HasSynced() {
|
|
||||||
// Wait for it to sync before returning the Informer so that folks don't read from a stale cache.
|
|
||||||
if !cache.WaitForCacheSync(ctx.Done(), i.Informer.HasSynced) {
|
|
||||||
return started, nil, apierrors.NewTimeoutError(fmt.Sprintf("failed waiting for %T Informer to sync", obj), 0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return started, i, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ip *specificInformersMap) addInformerToMap(gvk schema.GroupVersionKind, obj runtime.Object) (*MapEntry, bool, error) {
|
|
||||||
ip.mu.Lock()
|
|
||||||
defer ip.mu.Unlock()
|
|
||||||
|
|
||||||
// Check the cache to see if we already have an Informer. If we do, return the Informer.
|
|
||||||
// This is for the case where 2 routines tried to get the informer when it wasn't in the map
|
|
||||||
// so neither returned early, but the first one created it.
|
|
||||||
if i, ok := ip.informersByGVK[gvk]; ok {
|
|
||||||
return i, ip.started, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create a NewSharedIndexInformer and add it to the map.
|
|
||||||
var lw *cache.ListWatch
|
|
||||||
lw, err := ip.createListWatcher(gvk, ip)
|
|
||||||
if err != nil {
|
|
||||||
return nil, false, err
|
|
||||||
}
|
|
||||||
ni := cache.NewSharedIndexInformer(lw, obj, resyncPeriod(ip.resync)(), cache.Indexers{
|
|
||||||
cache.NamespaceIndex: cache.MetaNamespaceIndexFunc,
|
|
||||||
})
|
|
||||||
|
|
||||||
// Check to see if there is a transformer for this gvk
|
|
||||||
if err := ni.SetTransform(ip.transformers.Get(gvk)); err != nil {
|
|
||||||
return nil, false, err
|
|
||||||
}
|
|
||||||
|
|
||||||
rm, err := ip.mapper.RESTMapping(gvk.GroupKind(), gvk.Version)
|
|
||||||
if err != nil {
|
|
||||||
return nil, false, err
|
|
||||||
}
|
|
||||||
|
|
||||||
i := &MapEntry{
|
|
||||||
Informer: ni,
|
|
||||||
Reader: CacheReader{
|
|
||||||
indexer: ni.GetIndexer(),
|
|
||||||
groupVersionKind: gvk,
|
|
||||||
scopeName: rm.Scope.Name(),
|
|
||||||
disableDeepCopy: ip.disableDeepCopy.IsDisabled(gvk),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
ip.informersByGVK[gvk] = i
|
|
||||||
|
|
||||||
// Start the Informer if need by
|
|
||||||
// TODO(seans): write thorough tests and document what happens here - can you add indexers?
|
|
||||||
// can you add eventhandlers?
|
|
||||||
if ip.started {
|
|
||||||
go i.Informer.Run(ip.stop)
|
|
||||||
}
|
|
||||||
return i, ip.started, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// newListWatch returns a new ListWatch object that can be used to create a SharedIndexInformer.
|
|
||||||
func createStructuredListWatch(gvk schema.GroupVersionKind, ip *specificInformersMap) (*cache.ListWatch, error) {
|
|
||||||
// Kubernetes APIs work against Resources, not GroupVersionKinds. Map the
|
|
||||||
// groupVersionKind to the Resource API we will use.
|
|
||||||
mapping, err := ip.mapper.RESTMapping(gvk.GroupKind(), gvk.Version)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
client, err := apiutil.RESTClientForGVK(gvk, false, ip.config, ip.codecs)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
listGVK := gvk.GroupVersion().WithKind(gvk.Kind + "List")
|
|
||||||
listObj, err := ip.Scheme.New(listGVK)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: the functions that make use of this ListWatch should be adapted to
|
|
||||||
// pass in their own contexts instead of relying on this fixed one here.
|
|
||||||
ctx := context.TODO()
|
|
||||||
// Create a new ListWatch for the obj
|
|
||||||
return &cache.ListWatch{
|
|
||||||
ListFunc: func(opts metav1.ListOptions) (runtime.Object, error) {
|
|
||||||
ip.selectors(gvk).ApplyToList(&opts)
|
|
||||||
res := listObj.DeepCopyObject()
|
|
||||||
namespace := restrictNamespaceBySelector(ip.namespace, ip.selectors(gvk))
|
|
||||||
isNamespaceScoped := namespace != "" && mapping.Scope.Name() != meta.RESTScopeNameRoot
|
|
||||||
err := client.Get().NamespaceIfScoped(namespace, isNamespaceScoped).Resource(mapping.Resource.Resource).VersionedParams(&opts, ip.paramCodec).Do(ctx).Into(res)
|
|
||||||
return res, err
|
|
||||||
},
|
|
||||||
// Setup the watch function
|
|
||||||
WatchFunc: func(opts metav1.ListOptions) (watch.Interface, error) {
|
|
||||||
ip.selectors(gvk).ApplyToList(&opts)
|
|
||||||
// Watch needs to be set to true separately
|
|
||||||
opts.Watch = true
|
|
||||||
namespace := restrictNamespaceBySelector(ip.namespace, ip.selectors(gvk))
|
|
||||||
isNamespaceScoped := namespace != "" && mapping.Scope.Name() != meta.RESTScopeNameRoot
|
|
||||||
return client.Get().NamespaceIfScoped(namespace, isNamespaceScoped).Resource(mapping.Resource.Resource).VersionedParams(&opts, ip.paramCodec).Watch(ctx)
|
|
||||||
},
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func createUnstructuredListWatch(gvk schema.GroupVersionKind, ip *specificInformersMap) (*cache.ListWatch, error) {
|
|
||||||
// Kubernetes APIs work against Resources, not GroupVersionKinds. Map the
|
|
||||||
// groupVersionKind to the Resource API we will use.
|
|
||||||
mapping, err := ip.mapper.RESTMapping(gvk.GroupKind(), gvk.Version)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the rest configuration has a negotiated serializer passed in,
|
|
||||||
// we should remove it and use the one that the dynamic client sets for us.
|
|
||||||
cfg := rest.CopyConfig(ip.config)
|
|
||||||
cfg.NegotiatedSerializer = nil
|
|
||||||
dynamicClient, err := dynamic.NewForConfig(cfg)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: the functions that make use of this ListWatch should be adapted to
|
|
||||||
// pass in their own contexts instead of relying on this fixed one here.
|
|
||||||
ctx := context.TODO()
|
|
||||||
// Create a new ListWatch for the obj
|
|
||||||
return &cache.ListWatch{
|
|
||||||
ListFunc: func(opts metav1.ListOptions) (runtime.Object, error) {
|
|
||||||
ip.selectors(gvk).ApplyToList(&opts)
|
|
||||||
namespace := restrictNamespaceBySelector(ip.namespace, ip.selectors(gvk))
|
|
||||||
if namespace != "" && mapping.Scope.Name() != meta.RESTScopeNameRoot {
|
|
||||||
return dynamicClient.Resource(mapping.Resource).Namespace(namespace).List(ctx, opts)
|
|
||||||
}
|
|
||||||
return dynamicClient.Resource(mapping.Resource).List(ctx, opts)
|
|
||||||
},
|
|
||||||
// Setup the watch function
|
|
||||||
WatchFunc: func(opts metav1.ListOptions) (watch.Interface, error) {
|
|
||||||
ip.selectors(gvk).ApplyToList(&opts)
|
|
||||||
// Watch needs to be set to true separately
|
|
||||||
opts.Watch = true
|
|
||||||
namespace := restrictNamespaceBySelector(ip.namespace, ip.selectors(gvk))
|
|
||||||
if namespace != "" && mapping.Scope.Name() != meta.RESTScopeNameRoot {
|
|
||||||
return dynamicClient.Resource(mapping.Resource).Namespace(namespace).Watch(ctx, opts)
|
|
||||||
}
|
|
||||||
return dynamicClient.Resource(mapping.Resource).Watch(ctx, opts)
|
|
||||||
},
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func createMetadataListWatch(gvk schema.GroupVersionKind, ip *specificInformersMap) (*cache.ListWatch, error) {
|
|
||||||
// Kubernetes APIs work against Resources, not GroupVersionKinds. Map the
|
|
||||||
// groupVersionKind to the Resource API we will use.
|
|
||||||
mapping, err := ip.mapper.RESTMapping(gvk.GroupKind(), gvk.Version)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Always clear the negotiated serializer and use the one
|
|
||||||
// set from the metadata client.
|
|
||||||
cfg := rest.CopyConfig(ip.config)
|
|
||||||
cfg.NegotiatedSerializer = nil
|
|
||||||
|
|
||||||
// grab the metadata client
|
|
||||||
client, err := metadata.NewForConfig(cfg)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: the functions that make use of this ListWatch should be adapted to
|
|
||||||
// pass in their own contexts instead of relying on this fixed one here.
|
|
||||||
ctx := context.TODO()
|
|
||||||
|
|
||||||
// create the relevant listwatch
|
|
||||||
return &cache.ListWatch{
|
|
||||||
ListFunc: func(opts metav1.ListOptions) (runtime.Object, error) {
|
|
||||||
ip.selectors(gvk).ApplyToList(&opts)
|
|
||||||
|
|
||||||
var (
|
|
||||||
list *metav1.PartialObjectMetadataList
|
|
||||||
err error
|
|
||||||
)
|
|
||||||
namespace := restrictNamespaceBySelector(ip.namespace, ip.selectors(gvk))
|
|
||||||
if namespace != "" && mapping.Scope.Name() != meta.RESTScopeNameRoot {
|
|
||||||
list, err = client.Resource(mapping.Resource).Namespace(namespace).List(ctx, opts)
|
|
||||||
} else {
|
|
||||||
list, err = client.Resource(mapping.Resource).List(ctx, opts)
|
|
||||||
}
|
|
||||||
if list != nil {
|
|
||||||
for i := range list.Items {
|
|
||||||
list.Items[i].SetGroupVersionKind(gvk)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return list, err
|
|
||||||
},
|
|
||||||
// Setup the watch function
|
|
||||||
WatchFunc: func(opts metav1.ListOptions) (watch.Interface, error) {
|
|
||||||
ip.selectors(gvk).ApplyToList(&opts)
|
|
||||||
// Watch needs to be set to true separately
|
|
||||||
opts.Watch = true
|
|
||||||
|
|
||||||
var (
|
|
||||||
watcher watch.Interface
|
|
||||||
err error
|
|
||||||
)
|
|
||||||
namespace := restrictNamespaceBySelector(ip.namespace, ip.selectors(gvk))
|
|
||||||
if namespace != "" && mapping.Scope.Name() != meta.RESTScopeNameRoot {
|
|
||||||
watcher, err = client.Resource(mapping.Resource).Namespace(namespace).Watch(ctx, opts)
|
|
||||||
} else {
|
|
||||||
watcher, err = client.Resource(mapping.Resource).Watch(ctx, opts)
|
|
||||||
}
|
|
||||||
if watcher != nil {
|
|
||||||
watcher = newGVKFixupWatcher(gvk, watcher)
|
|
||||||
}
|
|
||||||
return watcher, err
|
|
||||||
},
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// newGVKFixupWatcher adds a wrapper that preserves the GVK information when
|
|
||||||
// events come in.
|
|
||||||
//
|
|
||||||
// This works around a bug where GVK information is not passed into mapping
|
|
||||||
// functions when using the OnlyMetadata option in the builder.
|
|
||||||
// This issue is most likely caused by kubernetes/kubernetes#80609.
|
|
||||||
// See kubernetes-sigs/controller-runtime#1484.
|
|
||||||
//
|
|
||||||
// This was originally implemented as a cache.ResourceEventHandler wrapper but
|
|
||||||
// that contained a data race which was resolved by setting the GVK in a watch
|
|
||||||
// wrapper, before the objects are written to the cache.
|
|
||||||
// See kubernetes-sigs/controller-runtime#1650.
|
|
||||||
//
|
|
||||||
// The original watch wrapper was found to be incompatible with
|
|
||||||
// k8s.io/client-go/tools/cache.Reflector so it has been re-implemented as a
|
|
||||||
// watch.Filter which is compatible.
|
|
||||||
// See kubernetes-sigs/controller-runtime#1789.
|
|
||||||
func newGVKFixupWatcher(gvk schema.GroupVersionKind, watcher watch.Interface) watch.Interface {
|
|
||||||
return watch.Filter(
|
|
||||||
watcher,
|
|
||||||
func(in watch.Event) (watch.Event, bool) {
|
|
||||||
in.Object.GetObjectKind().SetGroupVersionKind(gvk)
|
|
||||||
return in, true
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// resyncPeriod returns a function which generates a duration each time it is
|
|
||||||
// invoked; this is so that multiple controllers don't get into lock-step and all
|
|
||||||
// hammer the apiserver with list requests simultaneously.
|
|
||||||
func resyncPeriod(resync time.Duration) func() time.Duration {
|
|
||||||
return func() time.Duration {
|
|
||||||
// the factor will fall into [0.9, 1.1)
|
|
||||||
factor := rand.Float64()/5.0 + 0.9 //nolint:gosec
|
|
||||||
return time.Duration(float64(resync.Nanoseconds()) * factor)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// restrictNamespaceBySelector returns either a global restriction for all ListWatches
|
|
||||||
// if not default/empty, or the namespace that a ListWatch for the specific resource
|
|
||||||
// is restricted to, based on a specified field selector for metadata.namespace field.
|
|
||||||
func restrictNamespaceBySelector(namespaceOpt string, s Selector) string {
|
|
||||||
if namespaceOpt != "" {
|
|
||||||
// namespace is already restricted
|
|
||||||
return namespaceOpt
|
|
||||||
}
|
|
||||||
fieldSelector := s.Field
|
|
||||||
if fieldSelector == nil || fieldSelector.Empty() {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
// check whether a selector includes the namespace field
|
|
||||||
value, found := fieldSelector.RequiresExactMatch("metadata.namespace")
|
|
||||||
if found {
|
|
||||||
return value
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
15
vendor/sigs.k8s.io/controller-runtime/pkg/cache/internal/selector.go
generated
vendored
15
vendor/sigs.k8s.io/controller-runtime/pkg/cache/internal/selector.go
generated
vendored
@ -20,23 +20,8 @@ import (
|
|||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/fields"
|
"k8s.io/apimachinery/pkg/fields"
|
||||||
"k8s.io/apimachinery/pkg/labels"
|
"k8s.io/apimachinery/pkg/labels"
|
||||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// SelectorsByGVK associate a GroupVersionKind to a field/label selector.
|
|
||||||
type SelectorsByGVK map[schema.GroupVersionKind]Selector
|
|
||||||
|
|
||||||
func (s SelectorsByGVK) forGVK(gvk schema.GroupVersionKind) Selector {
|
|
||||||
if specific, found := s[gvk]; found {
|
|
||||||
return specific
|
|
||||||
}
|
|
||||||
if defaultSelector, found := s[schema.GroupVersionKind{}]; found {
|
|
||||||
return defaultSelector
|
|
||||||
}
|
|
||||||
|
|
||||||
return Selector{}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Selector specify the label/field selector to fill in ListOptions.
|
// Selector specify the label/field selector to fill in ListOptions.
|
||||||
type Selector struct {
|
type Selector struct {
|
||||||
Label labels.Selector
|
Label labels.Selector
|
||||||
|
8
vendor/sigs.k8s.io/controller-runtime/pkg/cache/internal/transformers.go
generated
vendored
8
vendor/sigs.k8s.io/controller-runtime/pkg/cache/internal/transformers.go
generated
vendored
@ -8,9 +8,9 @@ import (
|
|||||||
"sigs.k8s.io/controller-runtime/pkg/client/apiutil"
|
"sigs.k8s.io/controller-runtime/pkg/client/apiutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TransformFuncByObject provides access to the correct transform function for
|
// TransformFuncByGVK provides access to the correct transform function for
|
||||||
// any given GVK.
|
// any given GVK.
|
||||||
type TransformFuncByObject interface {
|
type TransformFuncByGVK interface {
|
||||||
Set(runtime.Object, *runtime.Scheme, cache.TransformFunc) error
|
Set(runtime.Object, *runtime.Scheme, cache.TransformFunc) error
|
||||||
Get(schema.GroupVersionKind) cache.TransformFunc
|
Get(schema.GroupVersionKind) cache.TransformFunc
|
||||||
SetDefault(transformer cache.TransformFunc)
|
SetDefault(transformer cache.TransformFunc)
|
||||||
@ -21,9 +21,9 @@ type transformFuncByGVK struct {
|
|||||||
transformers map[schema.GroupVersionKind]cache.TransformFunc
|
transformers map[schema.GroupVersionKind]cache.TransformFunc
|
||||||
}
|
}
|
||||||
|
|
||||||
// TransformFuncByObjectFromMap creates a TransformFuncByObject from a map that
|
// TransformFuncByGVKFromMap creates a TransformFuncByGVK from a map that
|
||||||
// maps GVKs to TransformFuncs.
|
// maps GVKs to TransformFuncs.
|
||||||
func TransformFuncByObjectFromMap(in map[schema.GroupVersionKind]cache.TransformFunc) TransformFuncByObject {
|
func TransformFuncByGVKFromMap(in map[schema.GroupVersionKind]cache.TransformFunc) TransformFuncByGVK {
|
||||||
byGVK := &transformFuncByGVK{}
|
byGVK := &transformFuncByGVK{}
|
||||||
if defaultFunc, hasDefault := in[schema.GroupVersionKind{}]; hasDefault {
|
if defaultFunc, hasDefault := in[schema.GroupVersionKind{}]; hasDefault {
|
||||||
byGVK.defaultTransform = defaultFunc
|
byGVK.defaultTransform = defaultFunc
|
||||||
|
100
vendor/sigs.k8s.io/controller-runtime/pkg/cache/multi_namespace_cache.go
generated
vendored
100
vendor/sigs.k8s.io/controller-runtime/pkg/cache/multi_namespace_cache.go
generated
vendored
@ -28,12 +28,9 @@ import (
|
|||||||
"k8s.io/client-go/rest"
|
"k8s.io/client-go/rest"
|
||||||
toolscache "k8s.io/client-go/tools/cache"
|
toolscache "k8s.io/client-go/tools/cache"
|
||||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||||
"sigs.k8s.io/controller-runtime/pkg/internal/objectutil"
|
"sigs.k8s.io/controller-runtime/pkg/client/apiutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewCacheFunc - Function for creating a new cache from the options and a rest config.
|
|
||||||
type NewCacheFunc func(config *rest.Config, opts Options) (Cache, error)
|
|
||||||
|
|
||||||
// a new global namespaced cache to handle cluster scoped resources.
|
// a new global namespaced cache to handle cluster scoped resources.
|
||||||
const globalCache = "_cluster-scope"
|
const globalCache = "_cluster-scope"
|
||||||
|
|
||||||
@ -43,31 +40,43 @@ const globalCache = "_cluster-scope"
|
|||||||
// a global cache for cluster scoped resource. Note that this is not intended
|
// a global cache for cluster scoped resource. Note that this is not intended
|
||||||
// to be used for excluding namespaces, this is better done via a Predicate. Also note that
|
// to be used for excluding namespaces, this is better done via a Predicate. Also note that
|
||||||
// you may face performance issues when using this with a high number of namespaces.
|
// you may face performance issues when using this with a high number of namespaces.
|
||||||
|
//
|
||||||
|
// Deprecated: Use cache.Options.Namespaces instead.
|
||||||
func MultiNamespacedCacheBuilder(namespaces []string) NewCacheFunc {
|
func MultiNamespacedCacheBuilder(namespaces []string) NewCacheFunc {
|
||||||
return func(config *rest.Config, opts Options) (Cache, error) {
|
return func(config *rest.Config, opts Options) (Cache, error) {
|
||||||
opts, err := defaultOpts(config, opts)
|
opts.Namespaces = namespaces
|
||||||
|
return newMultiNamespaceCache(config, opts)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func newMultiNamespaceCache(config *rest.Config, opts Options) (Cache, error) {
|
||||||
|
if len(opts.Namespaces) < 2 {
|
||||||
|
return nil, fmt.Errorf("must specify more than one namespace to use multi-namespace cache")
|
||||||
|
}
|
||||||
|
opts, err := defaultOpts(config, opts)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create every namespace cache.
|
||||||
|
caches := map[string]Cache{}
|
||||||
|
for _, ns := range opts.Namespaces {
|
||||||
|
opts.Namespaces = []string{ns}
|
||||||
|
c, err := New(config, opts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
caches[ns] = c
|
||||||
caches := map[string]Cache{}
|
|
||||||
|
|
||||||
// create a cache for cluster scoped resources
|
|
||||||
gCache, err := New(config, opts)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("error creating global cache: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, ns := range namespaces {
|
|
||||||
opts.Namespace = ns
|
|
||||||
c, err := New(config, opts)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
caches[ns] = c
|
|
||||||
}
|
|
||||||
return &multiNamespaceCache{namespaceToCache: caches, Scheme: opts.Scheme, RESTMapper: opts.Mapper, clusterCache: gCache}, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Create a cache for cluster scoped resources.
|
||||||
|
opts.Namespaces = []string{}
|
||||||
|
gCache, err := New(config, opts)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("error creating global cache: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &multiNamespaceCache{namespaceToCache: caches, Scheme: opts.Scheme, RESTMapper: opts.Mapper, clusterCache: gCache}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// multiNamespaceCache knows how to handle multiple namespaced caches
|
// multiNamespaceCache knows how to handle multiple namespaced caches
|
||||||
@ -89,7 +98,7 @@ func (c *multiNamespaceCache) GetInformer(ctx context.Context, obj client.Object
|
|||||||
|
|
||||||
// If the object is clusterscoped, get the informer from clusterCache,
|
// If the object is clusterscoped, get the informer from clusterCache,
|
||||||
// if not use the namespaced caches.
|
// if not use the namespaced caches.
|
||||||
isNamespaced, err := objectutil.IsAPINamespaced(obj, c.Scheme, c.RESTMapper)
|
isNamespaced, err := apiutil.IsObjectNamespaced(obj, c.Scheme, c.RESTMapper)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -119,7 +128,7 @@ func (c *multiNamespaceCache) GetInformerForKind(ctx context.Context, gvk schema
|
|||||||
|
|
||||||
// If the object is clusterscoped, get the informer from clusterCache,
|
// If the object is clusterscoped, get the informer from clusterCache,
|
||||||
// if not use the namespaced caches.
|
// if not use the namespaced caches.
|
||||||
isNamespaced, err := objectutil.IsAPINamespacedWithGVK(gvk, c.Scheme, c.RESTMapper)
|
isNamespaced, err := apiutil.IsGVKNamespaced(gvk, c.RESTMapper)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -183,9 +192,9 @@ func (c *multiNamespaceCache) WaitForCacheSync(ctx context.Context) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *multiNamespaceCache) IndexField(ctx context.Context, obj client.Object, field string, extractValue client.IndexerFunc) error {
|
func (c *multiNamespaceCache) IndexField(ctx context.Context, obj client.Object, field string, extractValue client.IndexerFunc) error {
|
||||||
isNamespaced, err := objectutil.IsAPINamespaced(obj, c.Scheme, c.RESTMapper)
|
isNamespaced, err := apiutil.IsObjectNamespaced(obj, c.Scheme, c.RESTMapper)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil //nolint:nilerr
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if !isNamespaced {
|
if !isNamespaced {
|
||||||
@ -201,7 +210,7 @@ func (c *multiNamespaceCache) IndexField(ctx context.Context, obj client.Object,
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *multiNamespaceCache) Get(ctx context.Context, key client.ObjectKey, obj client.Object, opts ...client.GetOption) error {
|
func (c *multiNamespaceCache) Get(ctx context.Context, key client.ObjectKey, obj client.Object, opts ...client.GetOption) error {
|
||||||
isNamespaced, err := objectutil.IsAPINamespaced(obj, c.Scheme, c.RESTMapper)
|
isNamespaced, err := apiutil.IsObjectNamespaced(obj, c.Scheme, c.RESTMapper)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -223,7 +232,7 @@ func (c *multiNamespaceCache) List(ctx context.Context, list client.ObjectList,
|
|||||||
listOpts := client.ListOptions{}
|
listOpts := client.ListOptions{}
|
||||||
listOpts.ApplyOptions(opts)
|
listOpts.ApplyOptions(opts)
|
||||||
|
|
||||||
isNamespaced, err := objectutil.IsAPINamespaced(list, c.Scheme, c.RESTMapper)
|
isNamespaced, err := apiutil.IsObjectNamespaced(list, c.Scheme, c.RESTMapper)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -293,42 +302,63 @@ type multiNamespaceInformer struct {
|
|||||||
namespaceToInformer map[string]Informer
|
namespaceToInformer map[string]Informer
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type handlerRegistration struct {
|
||||||
|
handles map[string]toolscache.ResourceEventHandlerRegistration
|
||||||
|
}
|
||||||
|
|
||||||
|
type syncer interface {
|
||||||
|
HasSynced() bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// HasSynced asserts that the handler has been called for the full initial state of the informer.
|
||||||
|
// This uses syncer to be compatible between client-go 1.27+ and older versions when the interface changed.
|
||||||
|
func (h handlerRegistration) HasSynced() bool {
|
||||||
|
for _, reg := range h.handles {
|
||||||
|
if s, ok := reg.(syncer); ok {
|
||||||
|
if !s.HasSynced() {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
var _ Informer = &multiNamespaceInformer{}
|
var _ Informer = &multiNamespaceInformer{}
|
||||||
|
|
||||||
// AddEventHandler adds the handler to each namespaced informer.
|
// AddEventHandler adds the handler to each namespaced informer.
|
||||||
func (i *multiNamespaceInformer) AddEventHandler(handler toolscache.ResourceEventHandler) (toolscache.ResourceEventHandlerRegistration, error) {
|
func (i *multiNamespaceInformer) AddEventHandler(handler toolscache.ResourceEventHandler) (toolscache.ResourceEventHandlerRegistration, error) {
|
||||||
handles := make(map[string]toolscache.ResourceEventHandlerRegistration, len(i.namespaceToInformer))
|
handles := handlerRegistration{handles: make(map[string]toolscache.ResourceEventHandlerRegistration, len(i.namespaceToInformer))}
|
||||||
for ns, informer := range i.namespaceToInformer {
|
for ns, informer := range i.namespaceToInformer {
|
||||||
registration, err := informer.AddEventHandler(handler)
|
registration, err := informer.AddEventHandler(handler)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
handles[ns] = registration
|
handles.handles[ns] = registration
|
||||||
}
|
}
|
||||||
return handles, nil
|
return handles, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddEventHandlerWithResyncPeriod adds the handler with a resync period to each namespaced informer.
|
// AddEventHandlerWithResyncPeriod adds the handler with a resync period to each namespaced informer.
|
||||||
func (i *multiNamespaceInformer) AddEventHandlerWithResyncPeriod(handler toolscache.ResourceEventHandler, resyncPeriod time.Duration) (toolscache.ResourceEventHandlerRegistration, error) {
|
func (i *multiNamespaceInformer) AddEventHandlerWithResyncPeriod(handler toolscache.ResourceEventHandler, resyncPeriod time.Duration) (toolscache.ResourceEventHandlerRegistration, error) {
|
||||||
handles := make(map[string]toolscache.ResourceEventHandlerRegistration, len(i.namespaceToInformer))
|
handles := handlerRegistration{handles: make(map[string]toolscache.ResourceEventHandlerRegistration, len(i.namespaceToInformer))}
|
||||||
for ns, informer := range i.namespaceToInformer {
|
for ns, informer := range i.namespaceToInformer {
|
||||||
registration, err := informer.AddEventHandlerWithResyncPeriod(handler, resyncPeriod)
|
registration, err := informer.AddEventHandlerWithResyncPeriod(handler, resyncPeriod)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
handles[ns] = registration
|
handles.handles[ns] = registration
|
||||||
}
|
}
|
||||||
return handles, nil
|
return handles, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// RemoveEventHandler removes a formerly added event handler given by its registration handle.
|
// RemoveEventHandler removes a formerly added event handler given by its registration handle.
|
||||||
func (i *multiNamespaceInformer) RemoveEventHandler(h toolscache.ResourceEventHandlerRegistration) error {
|
func (i *multiNamespaceInformer) RemoveEventHandler(h toolscache.ResourceEventHandlerRegistration) error {
|
||||||
handles, ok := h.(map[string]toolscache.ResourceEventHandlerRegistration)
|
handles, ok := h.(handlerRegistration)
|
||||||
if !ok {
|
if !ok {
|
||||||
return fmt.Errorf("it is not the registration returned by multiNamespaceInformer")
|
return fmt.Errorf("it is not the registration returned by multiNamespaceInformer")
|
||||||
}
|
}
|
||||||
for ns, informer := range i.namespaceToInformer {
|
for ns, informer := range i.namespaceToInformer {
|
||||||
registration, ok := handles[ns]
|
registration, ok := handles.handles[ns]
|
||||||
if !ok {
|
if !ok {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
52
vendor/sigs.k8s.io/controller-runtime/pkg/certwatcher/certwatcher.go
generated
vendored
52
vendor/sigs.k8s.io/controller-runtime/pkg/certwatcher/certwatcher.go
generated
vendored
@ -19,9 +19,14 @@ package certwatcher
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
|
"fmt"
|
||||||
"sync"
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/fsnotify/fsnotify"
|
"github.com/fsnotify/fsnotify"
|
||||||
|
kerrors "k8s.io/apimachinery/pkg/util/errors"
|
||||||
|
"k8s.io/apimachinery/pkg/util/sets"
|
||||||
|
"k8s.io/apimachinery/pkg/util/wait"
|
||||||
"sigs.k8s.io/controller-runtime/pkg/certwatcher/metrics"
|
"sigs.k8s.io/controller-runtime/pkg/certwatcher/metrics"
|
||||||
logf "sigs.k8s.io/controller-runtime/pkg/internal/log"
|
logf "sigs.k8s.io/controller-runtime/pkg/internal/log"
|
||||||
)
|
)
|
||||||
@ -39,6 +44,9 @@ type CertWatcher struct {
|
|||||||
|
|
||||||
certPath string
|
certPath string
|
||||||
keyPath string
|
keyPath string
|
||||||
|
|
||||||
|
// callback is a function to be invoked when the certificate changes.
|
||||||
|
callback func(tls.Certificate)
|
||||||
}
|
}
|
||||||
|
|
||||||
// New returns a new CertWatcher watching the given certificate and key.
|
// New returns a new CertWatcher watching the given certificate and key.
|
||||||
@ -63,6 +71,17 @@ func New(certPath, keyPath string) (*CertWatcher, error) {
|
|||||||
return cw, nil
|
return cw, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RegisterCallback registers a callback to be invoked when the certificate changes.
|
||||||
|
func (cw *CertWatcher) RegisterCallback(callback func(tls.Certificate)) {
|
||||||
|
cw.Lock()
|
||||||
|
defer cw.Unlock()
|
||||||
|
// If the current certificate is not nil, invoke the callback immediately.
|
||||||
|
if cw.currentCert != nil {
|
||||||
|
callback(*cw.currentCert)
|
||||||
|
}
|
||||||
|
cw.callback = callback
|
||||||
|
}
|
||||||
|
|
||||||
// GetCertificate fetches the currently loaded certificate, which may be nil.
|
// GetCertificate fetches the currently loaded certificate, which may be nil.
|
||||||
func (cw *CertWatcher) GetCertificate(_ *tls.ClientHelloInfo) (*tls.Certificate, error) {
|
func (cw *CertWatcher) GetCertificate(_ *tls.ClientHelloInfo) (*tls.Certificate, error) {
|
||||||
cw.RLock()
|
cw.RLock()
|
||||||
@ -72,11 +91,22 @@ func (cw *CertWatcher) GetCertificate(_ *tls.ClientHelloInfo) (*tls.Certificate,
|
|||||||
|
|
||||||
// Start starts the watch on the certificate and key files.
|
// Start starts the watch on the certificate and key files.
|
||||||
func (cw *CertWatcher) Start(ctx context.Context) error {
|
func (cw *CertWatcher) Start(ctx context.Context) error {
|
||||||
files := []string{cw.certPath, cw.keyPath}
|
files := sets.New(cw.certPath, cw.keyPath)
|
||||||
|
|
||||||
for _, f := range files {
|
{
|
||||||
if err := cw.watcher.Add(f); err != nil {
|
var watchErr error
|
||||||
return err
|
if err := wait.PollUntilContextTimeout(ctx, 1*time.Second, 10*time.Second, true, func(ctx context.Context) (done bool, err error) {
|
||||||
|
for _, f := range files.UnsortedList() {
|
||||||
|
if err := cw.watcher.Add(f); err != nil {
|
||||||
|
watchErr = err
|
||||||
|
return false, nil //nolint:nilerr // We want to keep trying.
|
||||||
|
}
|
||||||
|
// We've added the watch, remove it from the set.
|
||||||
|
files.Delete(f)
|
||||||
|
}
|
||||||
|
return true, nil
|
||||||
|
}); err != nil {
|
||||||
|
return fmt.Errorf("failed to add watches: %w", kerrors.NewAggregate([]error{err, watchErr}))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -130,6 +160,14 @@ func (cw *CertWatcher) ReadCertificate() error {
|
|||||||
|
|
||||||
log.Info("Updated current TLS certificate")
|
log.Info("Updated current TLS certificate")
|
||||||
|
|
||||||
|
// If a callback is registered, invoke it with the new certificate.
|
||||||
|
cw.RLock()
|
||||||
|
defer cw.RUnlock()
|
||||||
|
if cw.callback != nil {
|
||||||
|
go func() {
|
||||||
|
cw.callback(cert)
|
||||||
|
}()
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -154,13 +192,13 @@ func (cw *CertWatcher) handleEvent(event fsnotify.Event) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func isWrite(event fsnotify.Event) bool {
|
func isWrite(event fsnotify.Event) bool {
|
||||||
return event.Op&fsnotify.Write == fsnotify.Write
|
return event.Op.Has(fsnotify.Write)
|
||||||
}
|
}
|
||||||
|
|
||||||
func isCreate(event fsnotify.Event) bool {
|
func isCreate(event fsnotify.Event) bool {
|
||||||
return event.Op&fsnotify.Create == fsnotify.Create
|
return event.Op.Has(fsnotify.Create)
|
||||||
}
|
}
|
||||||
|
|
||||||
func isRemove(event fsnotify.Event) bool {
|
func isRemove(event fsnotify.Event) bool {
|
||||||
return event.Op&fsnotify.Remove == fsnotify.Remove
|
return event.Op.Has(fsnotify.Remove)
|
||||||
}
|
}
|
||||||
|
66
vendor/sigs.k8s.io/controller-runtime/pkg/client/apiutil/apimachinery.go
generated
vendored
66
vendor/sigs.k8s.io/controller-runtime/pkg/client/apiutil/apimachinery.go
generated
vendored
@ -20,7 +20,9 @@ limitations under the License.
|
|||||||
package apiutil
|
package apiutil
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"net/http"
|
||||||
"reflect"
|
"reflect"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
@ -30,6 +32,7 @@ import (
|
|||||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||||
"k8s.io/apimachinery/pkg/runtime/serializer"
|
"k8s.io/apimachinery/pkg/runtime/serializer"
|
||||||
"k8s.io/client-go/discovery"
|
"k8s.io/client-go/discovery"
|
||||||
|
"k8s.io/client-go/dynamic"
|
||||||
clientgoscheme "k8s.io/client-go/kubernetes/scheme"
|
clientgoscheme "k8s.io/client-go/kubernetes/scheme"
|
||||||
"k8s.io/client-go/rest"
|
"k8s.io/client-go/rest"
|
||||||
"k8s.io/client-go/restmapper"
|
"k8s.io/client-go/restmapper"
|
||||||
@ -59,9 +62,13 @@ func AddToProtobufScheme(addToScheme func(*runtime.Scheme) error) error {
|
|||||||
|
|
||||||
// NewDiscoveryRESTMapper constructs a new RESTMapper based on discovery
|
// NewDiscoveryRESTMapper constructs a new RESTMapper based on discovery
|
||||||
// information fetched by a new client with the given config.
|
// information fetched by a new client with the given config.
|
||||||
func NewDiscoveryRESTMapper(c *rest.Config) (meta.RESTMapper, error) {
|
func NewDiscoveryRESTMapper(c *rest.Config, httpClient *http.Client) (meta.RESTMapper, error) {
|
||||||
|
if httpClient == nil {
|
||||||
|
return nil, fmt.Errorf("httpClient must not be nil, consider using rest.HTTPClientFor(c) to create a client")
|
||||||
|
}
|
||||||
|
|
||||||
// Get a mapper
|
// Get a mapper
|
||||||
dc, err := discovery.NewDiscoveryClientForConfig(c)
|
dc, err := discovery.NewDiscoveryClientForConfigAndClient(c, httpClient)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -72,6 +79,36 @@ func NewDiscoveryRESTMapper(c *rest.Config) (meta.RESTMapper, error) {
|
|||||||
return restmapper.NewDiscoveryRESTMapper(gr), nil
|
return restmapper.NewDiscoveryRESTMapper(gr), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IsObjectNamespaced returns true if the object is namespace scoped.
|
||||||
|
// For unstructured objects the gvk is found from the object itself.
|
||||||
|
func IsObjectNamespaced(obj runtime.Object, scheme *runtime.Scheme, restmapper meta.RESTMapper) (bool, error) {
|
||||||
|
gvk, err := GVKForObject(obj, scheme)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return IsGVKNamespaced(gvk, restmapper)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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})
|
||||||
|
if err != nil {
|
||||||
|
return false, fmt.Errorf("failed to get restmapping: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
scope := restmapping.Scope.Name()
|
||||||
|
if scope == "" {
|
||||||
|
return false, errors.New("scope cannot be identified, empty scope returned")
|
||||||
|
}
|
||||||
|
|
||||||
|
if scope != meta.RESTScopeNameRoot {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
// GVKForObject finds the GroupVersionKind associated with the given object, if there is only a single such GVK.
|
// GVKForObject finds the GroupVersionKind associated with the given object, if there is only a single such GVK.
|
||||||
func GVKForObject(obj runtime.Object, scheme *runtime.Scheme) (schema.GroupVersionKind, error) {
|
func GVKForObject(obj runtime.Object, scheme *runtime.Scheme) (schema.GroupVersionKind, error) {
|
||||||
// TODO(directxman12): do we want to generalize this to arbitrary container types?
|
// TODO(directxman12): do we want to generalize this to arbitrary container types?
|
||||||
@ -142,21 +179,11 @@ func GVKForObject(obj runtime.Object, scheme *runtime.Scheme) (schema.GroupVersi
|
|||||||
// RESTClientForGVK constructs a new rest.Interface capable of accessing the resource associated
|
// RESTClientForGVK constructs a new rest.Interface capable of accessing the resource associated
|
||||||
// with the given GroupVersionKind. The REST client will be configured to use the negotiated serializer from
|
// with the given GroupVersionKind. The REST client will be configured to use the negotiated serializer from
|
||||||
// baseConfig, if set, otherwise a default serializer will be set.
|
// baseConfig, if set, otherwise a default serializer will be set.
|
||||||
func RESTClientForGVK(gvk schema.GroupVersionKind, isUnstructured bool, baseConfig *rest.Config, codecs serializer.CodecFactory) (rest.Interface, error) {
|
func RESTClientForGVK(gvk schema.GroupVersionKind, isUnstructured bool, baseConfig *rest.Config, codecs serializer.CodecFactory, httpClient *http.Client) (rest.Interface, error) {
|
||||||
return rest.RESTClientFor(createRestConfig(gvk, isUnstructured, baseConfig, codecs))
|
if httpClient == nil {
|
||||||
}
|
return nil, fmt.Errorf("httpClient must not be nil, consider using rest.HTTPClientFor(c) to create a client")
|
||||||
|
}
|
||||||
// serializerWithDecodedGVK is a CodecFactory that overrides the DecoderToVersion of a WithoutConversionCodecFactory
|
return rest.RESTClientForConfigAndClient(createRestConfig(gvk, isUnstructured, baseConfig, codecs), httpClient)
|
||||||
// in order to avoid clearing the GVK from the decoded object.
|
|
||||||
//
|
|
||||||
// See https://github.com/kubernetes/kubernetes/issues/80609.
|
|
||||||
type serializerWithDecodedGVK struct {
|
|
||||||
serializer.WithoutConversionCodecFactory
|
|
||||||
}
|
|
||||||
|
|
||||||
// DecoderToVersion returns an decoder that does not do conversion.
|
|
||||||
func (f serializerWithDecodedGVK) DecoderToVersion(serializer runtime.Decoder, _ runtime.GroupVersioner) runtime.Decoder {
|
|
||||||
return serializer
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// createRestConfig copies the base config and updates needed fields for a new rest config.
|
// createRestConfig copies the base config and updates needed fields for a new rest config.
|
||||||
@ -183,9 +210,8 @@ func createRestConfig(gvk schema.GroupVersionKind, isUnstructured bool, baseConf
|
|||||||
}
|
}
|
||||||
|
|
||||||
if isUnstructured {
|
if isUnstructured {
|
||||||
// If the object is unstructured, we need to preserve the GVK information.
|
// If the object is unstructured, we use the client-go dynamic serializer.
|
||||||
// Use our own custom serializer.
|
cfg = dynamic.ConfigFor(cfg)
|
||||||
cfg.NegotiatedSerializer = serializerWithDecodedGVK{serializer.WithoutConversionCodecFactory{CodecFactory: codecs}}
|
|
||||||
} else {
|
} else {
|
||||||
cfg.NegotiatedSerializer = serializerWithTargetZeroingDecode{NegotiatedSerializer: serializer.WithoutConversionCodecFactory{CodecFactory: codecs}}
|
cfg.NegotiatedSerializer = serializerWithTargetZeroingDecode{NegotiatedSerializer: serializer.WithoutConversionCodecFactory{CodecFactory: codecs}}
|
||||||
}
|
}
|
||||||
|
301
vendor/sigs.k8s.io/controller-runtime/pkg/client/apiutil/dynamicrestmapper.go
generated
vendored
301
vendor/sigs.k8s.io/controller-runtime/pkg/client/apiutil/dynamicrestmapper.go
generated
vendored
@ -1,301 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright 2019 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 apiutil
|
|
||||||
|
|
||||||
import (
|
|
||||||
"sync"
|
|
||||||
"sync/atomic"
|
|
||||||
|
|
||||||
"golang.org/x/time/rate"
|
|
||||||
"k8s.io/apimachinery/pkg/api/meta"
|
|
||||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
|
||||||
"k8s.io/client-go/discovery"
|
|
||||||
"k8s.io/client-go/rest"
|
|
||||||
"k8s.io/client-go/restmapper"
|
|
||||||
)
|
|
||||||
|
|
||||||
// dynamicRESTMapper is a RESTMapper that dynamically discovers resource
|
|
||||||
// types at runtime.
|
|
||||||
type dynamicRESTMapper struct {
|
|
||||||
mu sync.RWMutex // protects the following fields
|
|
||||||
staticMapper meta.RESTMapper
|
|
||||||
limiter *rate.Limiter
|
|
||||||
newMapper func() (meta.RESTMapper, error)
|
|
||||||
|
|
||||||
lazy bool
|
|
||||||
// Used for lazy init.
|
|
||||||
inited uint32
|
|
||||||
initMtx sync.Mutex
|
|
||||||
|
|
||||||
useLazyRestmapper bool
|
|
||||||
}
|
|
||||||
|
|
||||||
// DynamicRESTMapperOption is a functional option on the dynamicRESTMapper.
|
|
||||||
type DynamicRESTMapperOption func(*dynamicRESTMapper) error
|
|
||||||
|
|
||||||
// WithLimiter sets the RESTMapper's underlying limiter to lim.
|
|
||||||
func WithLimiter(lim *rate.Limiter) DynamicRESTMapperOption {
|
|
||||||
return func(drm *dynamicRESTMapper) error {
|
|
||||||
drm.limiter = lim
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// WithLazyDiscovery prevents the RESTMapper from discovering REST mappings
|
|
||||||
// until an API call is made.
|
|
||||||
var WithLazyDiscovery DynamicRESTMapperOption = func(drm *dynamicRESTMapper) error {
|
|
||||||
drm.lazy = true
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// WithExperimentalLazyMapper enables experimental more advanced Lazy Restmapping mechanism.
|
|
||||||
var WithExperimentalLazyMapper DynamicRESTMapperOption = func(drm *dynamicRESTMapper) error {
|
|
||||||
drm.useLazyRestmapper = true
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// WithCustomMapper supports setting a custom RESTMapper refresher instead of
|
|
||||||
// the default method, which uses a discovery client.
|
|
||||||
//
|
|
||||||
// This exists mainly for testing, but can be useful if you need tighter control
|
|
||||||
// over how discovery is performed, which discovery endpoints are queried, etc.
|
|
||||||
func WithCustomMapper(newMapper func() (meta.RESTMapper, error)) DynamicRESTMapperOption {
|
|
||||||
return func(drm *dynamicRESTMapper) error {
|
|
||||||
drm.newMapper = newMapper
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewDynamicRESTMapper returns a dynamic RESTMapper for cfg. The dynamic
|
|
||||||
// RESTMapper dynamically discovers resource types at runtime. opts
|
|
||||||
// configure the RESTMapper.
|
|
||||||
func NewDynamicRESTMapper(cfg *rest.Config, opts ...DynamicRESTMapperOption) (meta.RESTMapper, error) {
|
|
||||||
client, err := discovery.NewDiscoveryClientForConfig(cfg)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
drm := &dynamicRESTMapper{
|
|
||||||
limiter: rate.NewLimiter(rate.Limit(defaultRefillRate), defaultLimitSize),
|
|
||||||
newMapper: func() (meta.RESTMapper, error) {
|
|
||||||
groupResources, err := restmapper.GetAPIGroupResources(client)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return restmapper.NewDiscoveryRESTMapper(groupResources), nil
|
|
||||||
},
|
|
||||||
}
|
|
||||||
for _, opt := range opts {
|
|
||||||
if err = opt(drm); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if drm.useLazyRestmapper {
|
|
||||||
return newLazyRESTMapperWithClient(client)
|
|
||||||
}
|
|
||||||
if !drm.lazy {
|
|
||||||
if err := drm.setStaticMapper(); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return drm, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
// defaultRefilRate is the default rate at which potential calls are
|
|
||||||
// added back to the "bucket" of allowed calls.
|
|
||||||
defaultRefillRate = 5
|
|
||||||
// defaultLimitSize is the default starting/max number of potential calls
|
|
||||||
// per second. Once a call is used, it's added back to the bucket at a rate
|
|
||||||
// of defaultRefillRate per second.
|
|
||||||
defaultLimitSize = 5
|
|
||||||
)
|
|
||||||
|
|
||||||
// setStaticMapper sets drm's staticMapper by querying its client, regardless
|
|
||||||
// of reload backoff.
|
|
||||||
func (drm *dynamicRESTMapper) setStaticMapper() error {
|
|
||||||
newMapper, err := drm.newMapper()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
drm.staticMapper = newMapper
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// init initializes drm only once if drm is lazy.
|
|
||||||
func (drm *dynamicRESTMapper) init() (err error) {
|
|
||||||
// skip init if drm is not lazy or has initialized
|
|
||||||
if !drm.lazy || atomic.LoadUint32(&drm.inited) != 0 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
drm.initMtx.Lock()
|
|
||||||
defer drm.initMtx.Unlock()
|
|
||||||
if drm.inited == 0 {
|
|
||||||
if err = drm.setStaticMapper(); err == nil {
|
|
||||||
atomic.StoreUint32(&drm.inited, 1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// checkAndReload attempts to call the given callback, which is assumed to be dependent
|
|
||||||
// on the data in the restmapper.
|
|
||||||
//
|
|
||||||
// If the callback returns an error matching meta.IsNoMatchErr, it will attempt to reload
|
|
||||||
// the RESTMapper's data and re-call the callback once that's occurred.
|
|
||||||
// If the callback returns any other error, the function will return immediately regardless.
|
|
||||||
//
|
|
||||||
// It will take care of ensuring that reloads are rate-limited and that extraneous calls
|
|
||||||
// aren't made. If a reload would exceed the limiters rate, it returns the error return by
|
|
||||||
// the callback.
|
|
||||||
// It's thread-safe, and worries about thread-safety for the callback (so the callback does
|
|
||||||
// not need to attempt to lock the restmapper).
|
|
||||||
func (drm *dynamicRESTMapper) checkAndReload(checkNeedsReload func() error) error {
|
|
||||||
// first, check the common path -- data is fresh enough
|
|
||||||
// (use an IIFE for the lock's defer)
|
|
||||||
err := func() error {
|
|
||||||
drm.mu.RLock()
|
|
||||||
defer drm.mu.RUnlock()
|
|
||||||
|
|
||||||
return checkNeedsReload()
|
|
||||||
}()
|
|
||||||
|
|
||||||
needsReload := meta.IsNoMatchError(err)
|
|
||||||
if !needsReload {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// if the data wasn't fresh, we'll need to try and update it, so grab the lock...
|
|
||||||
drm.mu.Lock()
|
|
||||||
defer drm.mu.Unlock()
|
|
||||||
|
|
||||||
// ... and double-check that we didn't reload in the meantime
|
|
||||||
err = checkNeedsReload()
|
|
||||||
needsReload = meta.IsNoMatchError(err)
|
|
||||||
if !needsReload {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// we're still stale, so grab a rate-limit token if we can...
|
|
||||||
if !drm.limiter.Allow() {
|
|
||||||
// return error from static mapper here, we have refreshed often enough (exceeding rate of provided limiter)
|
|
||||||
// so that client's can handle this the same way as a "normal" NoResourceMatchError / NoKindMatchError
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// ...reload...
|
|
||||||
if err := drm.setStaticMapper(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// ...and return the results of the closure regardless
|
|
||||||
return checkNeedsReload()
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: wrap reload errors on NoKindMatchError with go 1.13 errors.
|
|
||||||
|
|
||||||
func (drm *dynamicRESTMapper) KindFor(resource schema.GroupVersionResource) (schema.GroupVersionKind, error) {
|
|
||||||
if err := drm.init(); err != nil {
|
|
||||||
return schema.GroupVersionKind{}, err
|
|
||||||
}
|
|
||||||
var gvk schema.GroupVersionKind
|
|
||||||
err := drm.checkAndReload(func() error {
|
|
||||||
var err error
|
|
||||||
gvk, err = drm.staticMapper.KindFor(resource)
|
|
||||||
return err
|
|
||||||
})
|
|
||||||
return gvk, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (drm *dynamicRESTMapper) KindsFor(resource schema.GroupVersionResource) ([]schema.GroupVersionKind, error) {
|
|
||||||
if err := drm.init(); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
var gvks []schema.GroupVersionKind
|
|
||||||
err := drm.checkAndReload(func() error {
|
|
||||||
var err error
|
|
||||||
gvks, err = drm.staticMapper.KindsFor(resource)
|
|
||||||
return err
|
|
||||||
})
|
|
||||||
return gvks, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (drm *dynamicRESTMapper) ResourceFor(input schema.GroupVersionResource) (schema.GroupVersionResource, error) {
|
|
||||||
if err := drm.init(); err != nil {
|
|
||||||
return schema.GroupVersionResource{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
var gvr schema.GroupVersionResource
|
|
||||||
err := drm.checkAndReload(func() error {
|
|
||||||
var err error
|
|
||||||
gvr, err = drm.staticMapper.ResourceFor(input)
|
|
||||||
return err
|
|
||||||
})
|
|
||||||
return gvr, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (drm *dynamicRESTMapper) ResourcesFor(input schema.GroupVersionResource) ([]schema.GroupVersionResource, error) {
|
|
||||||
if err := drm.init(); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
var gvrs []schema.GroupVersionResource
|
|
||||||
err := drm.checkAndReload(func() error {
|
|
||||||
var err error
|
|
||||||
gvrs, err = drm.staticMapper.ResourcesFor(input)
|
|
||||||
return err
|
|
||||||
})
|
|
||||||
return gvrs, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (drm *dynamicRESTMapper) RESTMapping(gk schema.GroupKind, versions ...string) (*meta.RESTMapping, error) {
|
|
||||||
if err := drm.init(); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
var mapping *meta.RESTMapping
|
|
||||||
err := drm.checkAndReload(func() error {
|
|
||||||
var err error
|
|
||||||
mapping, err = drm.staticMapper.RESTMapping(gk, versions...)
|
|
||||||
return err
|
|
||||||
})
|
|
||||||
return mapping, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (drm *dynamicRESTMapper) RESTMappings(gk schema.GroupKind, versions ...string) ([]*meta.RESTMapping, error) {
|
|
||||||
if err := drm.init(); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
var mappings []*meta.RESTMapping
|
|
||||||
err := drm.checkAndReload(func() error {
|
|
||||||
var err error
|
|
||||||
mappings, err = drm.staticMapper.RESTMappings(gk, versions...)
|
|
||||||
return err
|
|
||||||
})
|
|
||||||
return mappings, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (drm *dynamicRESTMapper) ResourceSingularizer(resource string) (string, error) {
|
|
||||||
if err := drm.init(); err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
var singular string
|
|
||||||
err := drm.checkAndReload(func() error {
|
|
||||||
var err error
|
|
||||||
singular, err = drm.staticMapper.ResourceSingularizer(resource)
|
|
||||||
return err
|
|
||||||
})
|
|
||||||
return singular, err
|
|
||||||
}
|
|
@ -18,137 +18,151 @@ package apiutil
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"net/http"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"k8s.io/apimachinery/pkg/api/meta"
|
"k8s.io/apimachinery/pkg/api/meta"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||||
"k8s.io/client-go/discovery"
|
"k8s.io/client-go/discovery"
|
||||||
|
"k8s.io/client-go/rest"
|
||||||
"k8s.io/client-go/restmapper"
|
"k8s.io/client-go/restmapper"
|
||||||
)
|
)
|
||||||
|
|
||||||
// lazyRESTMapper is a RESTMapper that will lazily query the provided
|
// NewDynamicRESTMapper returns a dynamic RESTMapper for cfg. The dynamic
|
||||||
// client for discovery information to do REST mappings.
|
// RESTMapper dynamically discovers resource types at runtime.
|
||||||
type lazyRESTMapper struct {
|
func NewDynamicRESTMapper(cfg *rest.Config, httpClient *http.Client) (meta.RESTMapper, error) {
|
||||||
mapper meta.RESTMapper
|
if httpClient == nil {
|
||||||
client *discovery.DiscoveryClient
|
return nil, fmt.Errorf("httpClient must not be nil, consider using rest.HTTPClientFor(c) to create a client")
|
||||||
knownGroups map[string]*restmapper.APIGroupResources
|
}
|
||||||
apiGroups []metav1.APIGroup
|
|
||||||
|
|
||||||
// mutex to provide thread-safe mapper reloading.
|
client, err := discovery.NewDiscoveryClientForConfigAndClient(cfg, httpClient)
|
||||||
mu sync.Mutex
|
if err != nil {
|
||||||
}
|
return nil, err
|
||||||
|
}
|
||||||
// newLazyRESTMapperWithClient initializes a LazyRESTMapper with a custom discovery client.
|
return &mapper{
|
||||||
func newLazyRESTMapperWithClient(discoveryClient *discovery.DiscoveryClient) (meta.RESTMapper, error) {
|
|
||||||
return &lazyRESTMapper{
|
|
||||||
mapper: restmapper.NewDiscoveryRESTMapper([]*restmapper.APIGroupResources{}),
|
mapper: restmapper.NewDiscoveryRESTMapper([]*restmapper.APIGroupResources{}),
|
||||||
client: discoveryClient,
|
client: client,
|
||||||
knownGroups: map[string]*restmapper.APIGroupResources{},
|
knownGroups: map[string]*restmapper.APIGroupResources{},
|
||||||
apiGroups: []metav1.APIGroup{},
|
apiGroups: map[string]*metav1.APIGroup{},
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// KindFor implements Mapper.KindFor.
|
// mapper is a RESTMapper that will lazily query the provided
|
||||||
func (m *lazyRESTMapper) KindFor(resource schema.GroupVersionResource) (schema.GroupVersionKind, error) {
|
// client for discovery information to do REST mappings.
|
||||||
res, err := m.mapper.KindFor(resource)
|
type mapper struct {
|
||||||
if meta.IsNoMatchError(err) {
|
mapper meta.RESTMapper
|
||||||
if err = m.addKnownGroupAndReload(resource.Group, resource.Version); err != nil {
|
client *discovery.DiscoveryClient
|
||||||
return res, err
|
knownGroups map[string]*restmapper.APIGroupResources
|
||||||
}
|
apiGroups map[string]*metav1.APIGroup
|
||||||
|
|
||||||
res, err = m.mapper.KindFor(resource)
|
// mutex to provide thread-safe mapper reloading.
|
||||||
|
mu sync.RWMutex
|
||||||
|
}
|
||||||
|
|
||||||
|
// KindFor implements Mapper.KindFor.
|
||||||
|
func (m *mapper) KindFor(resource schema.GroupVersionResource) (schema.GroupVersionKind, error) {
|
||||||
|
res, err := m.getMapper().KindFor(resource)
|
||||||
|
if meta.IsNoMatchError(err) {
|
||||||
|
if err := m.addKnownGroupAndReload(resource.Group, resource.Version); err != nil {
|
||||||
|
return schema.GroupVersionKind{}, err
|
||||||
|
}
|
||||||
|
res, err = m.getMapper().KindFor(resource)
|
||||||
}
|
}
|
||||||
|
|
||||||
return res, err
|
return res, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// KindsFor implements Mapper.KindsFor.
|
// KindsFor implements Mapper.KindsFor.
|
||||||
func (m *lazyRESTMapper) KindsFor(resource schema.GroupVersionResource) ([]schema.GroupVersionKind, error) {
|
func (m *mapper) KindsFor(resource schema.GroupVersionResource) ([]schema.GroupVersionKind, error) {
|
||||||
res, err := m.mapper.KindsFor(resource)
|
res, err := m.getMapper().KindsFor(resource)
|
||||||
if meta.IsNoMatchError(err) {
|
if meta.IsNoMatchError(err) {
|
||||||
if err = m.addKnownGroupAndReload(resource.Group, resource.Version); err != nil {
|
if err := m.addKnownGroupAndReload(resource.Group, resource.Version); err != nil {
|
||||||
return res, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
res, err = m.getMapper().KindsFor(resource)
|
||||||
res, err = m.mapper.KindsFor(resource)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return res, err
|
return res, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// ResourceFor implements Mapper.ResourceFor.
|
// ResourceFor implements Mapper.ResourceFor.
|
||||||
func (m *lazyRESTMapper) ResourceFor(input schema.GroupVersionResource) (schema.GroupVersionResource, error) {
|
func (m *mapper) ResourceFor(input schema.GroupVersionResource) (schema.GroupVersionResource, error) {
|
||||||
res, err := m.mapper.ResourceFor(input)
|
res, err := m.getMapper().ResourceFor(input)
|
||||||
if meta.IsNoMatchError(err) {
|
if meta.IsNoMatchError(err) {
|
||||||
if err = m.addKnownGroupAndReload(input.Group, input.Version); err != nil {
|
if err := m.addKnownGroupAndReload(input.Group, input.Version); err != nil {
|
||||||
return res, err
|
return schema.GroupVersionResource{}, err
|
||||||
}
|
}
|
||||||
|
res, err = m.getMapper().ResourceFor(input)
|
||||||
res, err = m.mapper.ResourceFor(input)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return res, err
|
return res, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// ResourcesFor implements Mapper.ResourcesFor.
|
// ResourcesFor implements Mapper.ResourcesFor.
|
||||||
func (m *lazyRESTMapper) ResourcesFor(input schema.GroupVersionResource) ([]schema.GroupVersionResource, error) {
|
func (m *mapper) ResourcesFor(input schema.GroupVersionResource) ([]schema.GroupVersionResource, error) {
|
||||||
res, err := m.mapper.ResourcesFor(input)
|
res, err := m.getMapper().ResourcesFor(input)
|
||||||
if meta.IsNoMatchError(err) {
|
if meta.IsNoMatchError(err) {
|
||||||
if err = m.addKnownGroupAndReload(input.Group, input.Version); err != nil {
|
if err := m.addKnownGroupAndReload(input.Group, input.Version); err != nil {
|
||||||
return res, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
res, err = m.getMapper().ResourcesFor(input)
|
||||||
res, err = m.mapper.ResourcesFor(input)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return res, err
|
return res, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// RESTMapping implements Mapper.RESTMapping.
|
// RESTMapping implements Mapper.RESTMapping.
|
||||||
func (m *lazyRESTMapper) RESTMapping(gk schema.GroupKind, versions ...string) (*meta.RESTMapping, error) {
|
func (m *mapper) RESTMapping(gk schema.GroupKind, versions ...string) (*meta.RESTMapping, error) {
|
||||||
res, err := m.mapper.RESTMapping(gk, versions...)
|
res, err := m.getMapper().RESTMapping(gk, versions...)
|
||||||
if meta.IsNoMatchError(err) {
|
if meta.IsNoMatchError(err) {
|
||||||
if err = m.addKnownGroupAndReload(gk.Group, versions...); err != nil {
|
if err := m.addKnownGroupAndReload(gk.Group, versions...); err != nil {
|
||||||
return res, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
res, err = m.getMapper().RESTMapping(gk, versions...)
|
||||||
res, err = m.mapper.RESTMapping(gk, versions...)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return res, err
|
return res, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// RESTMappings implements Mapper.RESTMappings.
|
// RESTMappings implements Mapper.RESTMappings.
|
||||||
func (m *lazyRESTMapper) RESTMappings(gk schema.GroupKind, versions ...string) ([]*meta.RESTMapping, error) {
|
func (m *mapper) RESTMappings(gk schema.GroupKind, versions ...string) ([]*meta.RESTMapping, error) {
|
||||||
res, err := m.mapper.RESTMappings(gk, versions...)
|
res, err := m.getMapper().RESTMappings(gk, versions...)
|
||||||
if meta.IsNoMatchError(err) {
|
if meta.IsNoMatchError(err) {
|
||||||
if err = m.addKnownGroupAndReload(gk.Group, versions...); err != nil {
|
if err := m.addKnownGroupAndReload(gk.Group, versions...); err != nil {
|
||||||
return res, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
res, err = m.getMapper().RESTMappings(gk, versions...)
|
||||||
res, err = m.mapper.RESTMappings(gk, versions...)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return res, err
|
return res, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// ResourceSingularizer implements Mapper.ResourceSingularizer.
|
// ResourceSingularizer implements Mapper.ResourceSingularizer.
|
||||||
func (m *lazyRESTMapper) ResourceSingularizer(resource string) (string, error) {
|
func (m *mapper) ResourceSingularizer(resource string) (string, error) {
|
||||||
return m.mapper.ResourceSingularizer(resource)
|
return m.getMapper().ResourceSingularizer(resource)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *mapper) getMapper() meta.RESTMapper {
|
||||||
|
m.mu.RLock()
|
||||||
|
defer m.mu.RUnlock()
|
||||||
|
return m.mapper
|
||||||
}
|
}
|
||||||
|
|
||||||
// addKnownGroupAndReload reloads the mapper with updated information about missing API group.
|
// addKnownGroupAndReload reloads the mapper with updated information about missing API group.
|
||||||
// versions can be specified for partial updates, for instance for v1beta1 version only.
|
// versions can be specified for partial updates, for instance for v1beta1 version only.
|
||||||
func (m *lazyRESTMapper) addKnownGroupAndReload(groupName string, versions ...string) error {
|
func (m *mapper) addKnownGroupAndReload(groupName string, versions ...string) error {
|
||||||
m.mu.Lock()
|
// versions will here be [""] if the forwarded Version value of
|
||||||
defer m.mu.Unlock()
|
// GroupVersionResource (in calling method) was not specified.
|
||||||
|
if len(versions) == 1 && versions[0] == "" {
|
||||||
|
versions = nil
|
||||||
|
}
|
||||||
|
|
||||||
// If no specific versions are set by user, we will scan all available ones for the API group.
|
// If no specific versions are set by user, we will scan all available ones for the API group.
|
||||||
// This operation requires 2 requests: /api and /apis, but only once. For all subsequent calls
|
// This operation requires 2 requests: /api and /apis, but only once. For all subsequent calls
|
||||||
// this data will be taken from cache.
|
// this data will be taken from cache.
|
||||||
if len(versions) == 0 {
|
if len(versions) == 0 {
|
||||||
apiGroup, err := m.findAPIGroupByNameLocked(groupName)
|
apiGroup, err := m.findAPIGroupByName(groupName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -157,6 +171,9 @@ func (m *lazyRESTMapper) addKnownGroupAndReload(groupName string, versions ...st
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m.mu.Lock()
|
||||||
|
defer m.mu.Unlock()
|
||||||
|
|
||||||
// Create or fetch group resources from cache.
|
// Create or fetch group resources from cache.
|
||||||
groupResources := &restmapper.APIGroupResources{
|
groupResources := &restmapper.APIGroupResources{
|
||||||
Group: metav1.APIGroup{Name: groupName},
|
Group: metav1.APIGroup{Name: groupName},
|
||||||
@ -205,43 +222,53 @@ func (m *lazyRESTMapper) addKnownGroupAndReload(groupName string, versions ...st
|
|||||||
}
|
}
|
||||||
|
|
||||||
m.mapper = restmapper.NewDiscoveryRESTMapper(updatedGroupResources)
|
m.mapper = restmapper.NewDiscoveryRESTMapper(updatedGroupResources)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// findAPIGroupByNameLocked returns API group by its name.
|
// findAPIGroupByNameLocked returns API group by its name.
|
||||||
func (m *lazyRESTMapper) findAPIGroupByNameLocked(groupName string) (metav1.APIGroup, error) {
|
func (m *mapper) findAPIGroupByName(groupName string) (*metav1.APIGroup, error) {
|
||||||
// Looking in the cache first.
|
// Looking in the cache first.
|
||||||
for _, apiGroup := range m.apiGroups {
|
{
|
||||||
if groupName == apiGroup.Name {
|
m.mu.RLock()
|
||||||
return apiGroup, nil
|
group, ok := m.apiGroups[groupName]
|
||||||
|
m.mu.RUnlock()
|
||||||
|
if ok {
|
||||||
|
return group, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update the cache if nothing was found.
|
// Update the cache if nothing was found.
|
||||||
apiGroups, err := m.client.ServerGroups()
|
apiGroups, err := m.client.ServerGroups()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return metav1.APIGroup{}, fmt.Errorf("failed to get server groups: %w", err)
|
return nil, fmt.Errorf("failed to get server groups: %w", err)
|
||||||
}
|
}
|
||||||
if len(apiGroups.Groups) == 0 {
|
if len(apiGroups.Groups) == 0 {
|
||||||
return metav1.APIGroup{}, fmt.Errorf("received an empty API groups list")
|
return nil, fmt.Errorf("received an empty API groups list")
|
||||||
}
|
}
|
||||||
|
|
||||||
m.apiGroups = apiGroups.Groups
|
m.mu.Lock()
|
||||||
|
for i := range apiGroups.Groups {
|
||||||
|
group := &apiGroups.Groups[i]
|
||||||
|
m.apiGroups[group.Name] = group
|
||||||
|
}
|
||||||
|
m.mu.Unlock()
|
||||||
|
|
||||||
// Looking in the cache again.
|
// Looking in the cache again.
|
||||||
for _, apiGroup := range m.apiGroups {
|
{
|
||||||
if groupName == apiGroup.Name {
|
m.mu.RLock()
|
||||||
return apiGroup, nil
|
group, ok := m.apiGroups[groupName]
|
||||||
|
m.mu.RUnlock()
|
||||||
|
if ok {
|
||||||
|
return group, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If there is still nothing, return an error.
|
// If there is still nothing, return an error.
|
||||||
return metav1.APIGroup{}, fmt.Errorf("failed to find API group %s", groupName)
|
return nil, fmt.Errorf("failed to find API group %q", groupName)
|
||||||
}
|
}
|
||||||
|
|
||||||
// fetchGroupVersionResources fetches the resources for the specified group and its versions.
|
// fetchGroupVersionResources fetches the resources for the specified group and its versions.
|
||||||
func (m *lazyRESTMapper) fetchGroupVersionResources(groupName string, versions ...string) (map[schema.GroupVersion]*metav1.APIResourceList, error) {
|
func (m *mapper) fetchGroupVersionResources(groupName string, versions ...string) (map[schema.GroupVersion]*metav1.APIResourceList, error) {
|
||||||
groupVersionResources := make(map[schema.GroupVersion]*metav1.APIResourceList)
|
groupVersionResources := make(map[schema.GroupVersion]*metav1.APIResourceList)
|
||||||
failedGroups := make(map[schema.GroupVersion]error)
|
failedGroups := make(map[schema.GroupVersion]error)
|
||||||
|
|
181
vendor/sigs.k8s.io/controller-runtime/pkg/client/client.go
generated
vendored
181
vendor/sigs.k8s.io/controller-runtime/pkg/client/client.go
generated
vendored
@ -20,11 +20,11 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"k8s.io/apimachinery/pkg/api/meta"
|
"k8s.io/apimachinery/pkg/api/meta"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||||
"k8s.io/apimachinery/pkg/runtime/serializer"
|
"k8s.io/apimachinery/pkg/runtime/serializer"
|
||||||
@ -36,6 +36,28 @@ import (
|
|||||||
"sigs.k8s.io/controller-runtime/pkg/log"
|
"sigs.k8s.io/controller-runtime/pkg/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Options are creation options for a Client.
|
||||||
|
type Options struct {
|
||||||
|
// HTTPClient is the HTTP client to use for requests.
|
||||||
|
HTTPClient *http.Client
|
||||||
|
|
||||||
|
// Scheme, if provided, will be used to map go structs to GroupVersionKinds
|
||||||
|
Scheme *runtime.Scheme
|
||||||
|
|
||||||
|
// Mapper, if provided, will be used to map GroupVersionKinds to Resources
|
||||||
|
Mapper meta.RESTMapper
|
||||||
|
|
||||||
|
// 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
|
// WarningHandlerOptions are options for configuring a
|
||||||
// warning handler for the client which is responsible
|
// warning handler for the client which is responsible
|
||||||
// for surfacing API Server warnings.
|
// for surfacing API Server warnings.
|
||||||
@ -50,19 +72,21 @@ type WarningHandlerOptions struct {
|
|||||||
AllowDuplicateLogs bool
|
AllowDuplicateLogs bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// Options are creation options for a Client.
|
// CacheOptions are options for creating a cache-backed client.
|
||||||
type Options struct {
|
type CacheOptions struct {
|
||||||
// Scheme, if provided, will be used to map go structs to GroupVersionKinds
|
// Reader is a cache-backed reader that will be used to read objects from the cache.
|
||||||
Scheme *runtime.Scheme
|
// +required
|
||||||
|
Reader Reader
|
||||||
// Mapper, if provided, will be used to map GroupVersionKinds to Resources
|
// DisableFor is a list of objects that should not be read from the cache.
|
||||||
Mapper meta.RESTMapper
|
DisableFor []Object
|
||||||
|
// Unstructured is a flag that indicates whether the cache-backed client should
|
||||||
// Opts is used to configure the warning handler responsible for
|
// read unstructured objects or lists from the cache.
|
||||||
// surfacing and handling warnings messages sent by the API server.
|
Unstructured bool
|
||||||
Opts WarningHandlerOptions
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewClientFunc allows a user to define how to create a client.
|
||||||
|
type NewClientFunc func(config *rest.Config, options Options) (Client, error)
|
||||||
|
|
||||||
// New returns a new Client using the provided config and Options.
|
// New returns a new Client using the provided config and Options.
|
||||||
// The returned client reads *and* writes directly from the server
|
// The returned client reads *and* writes directly from the server
|
||||||
// (it doesn't use object caches). It understands how to work with
|
// (it doesn't use object caches). It understands how to work with
|
||||||
@ -73,8 +97,12 @@ type Options struct {
|
|||||||
// corresponding group, version, and kind for the given type. In the
|
// corresponding group, version, and kind for the given type. In the
|
||||||
// case of unstructured types, the group, version, and kind will be extracted
|
// case of unstructured types, the group, version, and kind will be extracted
|
||||||
// from the corresponding fields on the object.
|
// from the corresponding fields on the object.
|
||||||
func New(config *rest.Config, options Options) (Client, error) {
|
func New(config *rest.Config, options Options) (c Client, err error) {
|
||||||
return newClient(config, options)
|
c, err = newClient(config, options)
|
||||||
|
if err == nil && options.DryRun != nil && *options.DryRun {
|
||||||
|
c = NewDryRunClient(c)
|
||||||
|
}
|
||||||
|
return c, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func newClient(config *rest.Config, options Options) (*client, error) {
|
func newClient(config *rest.Config, options Options) (*client, error) {
|
||||||
@ -82,7 +110,7 @@ func newClient(config *rest.Config, options Options) (*client, error) {
|
|||||||
return nil, fmt.Errorf("must provide non-nil rest.Config to client.New")
|
return nil, fmt.Errorf("must provide non-nil rest.Config to client.New")
|
||||||
}
|
}
|
||||||
|
|
||||||
if !options.Opts.SuppressWarnings {
|
if !options.WarningHandler.SuppressWarnings {
|
||||||
// surface warnings
|
// surface warnings
|
||||||
logger := log.Log.WithName("KubeAPIWarningLogger")
|
logger := log.Log.WithName("KubeAPIWarningLogger")
|
||||||
// Set a WarningHandler, the default WarningHandler
|
// Set a WarningHandler, the default WarningHandler
|
||||||
@ -93,11 +121,20 @@ func newClient(config *rest.Config, options Options) (*client, error) {
|
|||||||
config.WarningHandler = log.NewKubeAPIWarningLogger(
|
config.WarningHandler = log.NewKubeAPIWarningLogger(
|
||||||
logger,
|
logger,
|
||||||
log.KubeAPIWarningLoggerOptions{
|
log.KubeAPIWarningLoggerOptions{
|
||||||
Deduplicate: !options.Opts.AllowDuplicateLogs,
|
Deduplicate: !options.WarningHandler.AllowDuplicateLogs,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Use the rest HTTP client for the provided config if unset
|
||||||
|
if options.HTTPClient == nil {
|
||||||
|
var err error
|
||||||
|
options.HTTPClient, err = rest.HTTPClientFor(config)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Init a scheme if none provided
|
// Init a scheme if none provided
|
||||||
if options.Scheme == nil {
|
if options.Scheme == nil {
|
||||||
options.Scheme = scheme.Scheme
|
options.Scheme = scheme.Scheme
|
||||||
@ -106,34 +143,35 @@ func newClient(config *rest.Config, options Options) (*client, error) {
|
|||||||
// Init a Mapper if none provided
|
// Init a Mapper if none provided
|
||||||
if options.Mapper == nil {
|
if options.Mapper == nil {
|
||||||
var err error
|
var err error
|
||||||
options.Mapper, err = apiutil.NewDynamicRESTMapper(config)
|
options.Mapper, err = apiutil.NewDynamicRESTMapper(config, options.HTTPClient)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
clientcache := &clientCache{
|
resources := &clientRestResources{
|
||||||
config: config,
|
httpClient: options.HTTPClient,
|
||||||
scheme: options.Scheme,
|
config: config,
|
||||||
mapper: options.Mapper,
|
scheme: options.Scheme,
|
||||||
codecs: serializer.NewCodecFactory(options.Scheme),
|
mapper: options.Mapper,
|
||||||
|
codecs: serializer.NewCodecFactory(options.Scheme),
|
||||||
|
|
||||||
structuredResourceByType: make(map[schema.GroupVersionKind]*resourceMeta),
|
structuredResourceByType: make(map[schema.GroupVersionKind]*resourceMeta),
|
||||||
unstructuredResourceByType: make(map[schema.GroupVersionKind]*resourceMeta),
|
unstructuredResourceByType: make(map[schema.GroupVersionKind]*resourceMeta),
|
||||||
}
|
}
|
||||||
|
|
||||||
rawMetaClient, err := metadata.NewForConfig(config)
|
rawMetaClient, err := metadata.NewForConfigAndClient(config, options.HTTPClient)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("unable to construct metadata-only client for use as part of client: %w", err)
|
return nil, fmt.Errorf("unable to construct metadata-only client for use as part of client: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
c := &client{
|
c := &client{
|
||||||
typedClient: typedClient{
|
typedClient: typedClient{
|
||||||
cache: clientcache,
|
resources: resources,
|
||||||
paramCodec: runtime.NewParameterCodec(options.Scheme),
|
paramCodec: runtime.NewParameterCodec(options.Scheme),
|
||||||
},
|
},
|
||||||
unstructuredClient: unstructuredClient{
|
unstructuredClient: unstructuredClient{
|
||||||
cache: clientcache,
|
resources: resources,
|
||||||
paramCodec: noConversionParamCodec{},
|
paramCodec: noConversionParamCodec{},
|
||||||
},
|
},
|
||||||
metadataClient: metadataClient{
|
metadataClient: metadataClient{
|
||||||
@ -143,20 +181,65 @@ func newClient(config *rest.Config, options Options) (*client, error) {
|
|||||||
scheme: options.Scheme,
|
scheme: options.Scheme,
|
||||||
mapper: options.Mapper,
|
mapper: options.Mapper,
|
||||||
}
|
}
|
||||||
|
if options.Cache == nil || options.Cache.Reader == nil {
|
||||||
|
return c, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// We want a cache if we're here.
|
||||||
|
// Set the cache.
|
||||||
|
c.cache = options.Cache.Reader
|
||||||
|
|
||||||
|
// Load uncached GVKs.
|
||||||
|
c.cacheUnstructured = options.Cache.Unstructured
|
||||||
|
c.uncachedGVKs = map[schema.GroupVersionKind]struct{}{}
|
||||||
|
for _, obj := range options.Cache.DisableFor {
|
||||||
|
gvk, err := c.GroupVersionKindFor(obj)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
c.uncachedGVKs[gvk] = struct{}{}
|
||||||
|
}
|
||||||
return c, nil
|
return c, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ Client = &client{}
|
var _ Client = &client{}
|
||||||
|
|
||||||
// client is a client.Client that reads and writes directly from/to an API server. It lazily initializes
|
// client is a client.Client that reads and writes directly from/to an API server.
|
||||||
// new clients at the time they are used, and caches the client.
|
// It lazily initializes new clients at the time they are used.
|
||||||
type client struct {
|
type client struct {
|
||||||
typedClient typedClient
|
typedClient typedClient
|
||||||
unstructuredClient unstructuredClient
|
unstructuredClient unstructuredClient
|
||||||
metadataClient metadataClient
|
metadataClient metadataClient
|
||||||
scheme *runtime.Scheme
|
scheme *runtime.Scheme
|
||||||
mapper meta.RESTMapper
|
mapper meta.RESTMapper
|
||||||
|
|
||||||
|
cache Reader
|
||||||
|
uncachedGVKs map[schema.GroupVersionKind]struct{}
|
||||||
|
cacheUnstructured bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *client) shouldBypassCache(obj runtime.Object) (bool, error) {
|
||||||
|
if c.cache == nil {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
gvk, err := c.GroupVersionKindFor(obj)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
// TODO: this is producing unsafe guesses that don't actually work,
|
||||||
|
// but it matches ~99% of the cases out there.
|
||||||
|
if meta.IsListType(obj) {
|
||||||
|
gvk.Kind = strings.TrimSuffix(gvk.Kind, "List")
|
||||||
|
}
|
||||||
|
if _, isUncached := c.uncachedGVKs[gvk]; isUncached {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
if !c.cacheUnstructured {
|
||||||
|
_, isUnstructured := obj.(runtime.Unstructured)
|
||||||
|
return isUnstructured, nil
|
||||||
|
}
|
||||||
|
return false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// resetGroupVersionKind is a helper function to restore and preserve GroupVersionKind on an object.
|
// resetGroupVersionKind is a helper function to restore and preserve GroupVersionKind on an object.
|
||||||
@ -168,6 +251,16 @@ func (c *client) resetGroupVersionKind(obj runtime.Object, gvk schema.GroupVersi
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GroupVersionKindFor returns the GroupVersionKind for the given object.
|
||||||
|
func (c *client) GroupVersionKindFor(obj runtime.Object) (schema.GroupVersionKind, error) {
|
||||||
|
return apiutil.GVKForObject(obj, c.scheme)
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsObjectNamespaced returns true if the GroupVersionKind of the object is namespaced.
|
||||||
|
func (c *client) IsObjectNamespaced(obj runtime.Object) (bool, error) {
|
||||||
|
return apiutil.IsObjectNamespaced(obj, c.scheme, c.mapper)
|
||||||
|
}
|
||||||
|
|
||||||
// Scheme returns the scheme this client is using.
|
// Scheme returns the scheme this client is using.
|
||||||
func (c *client) Scheme() *runtime.Scheme {
|
func (c *client) Scheme() *runtime.Scheme {
|
||||||
return c.scheme
|
return c.scheme
|
||||||
@ -181,7 +274,7 @@ func (c *client) RESTMapper() meta.RESTMapper {
|
|||||||
// Create implements client.Client.
|
// Create implements client.Client.
|
||||||
func (c *client) Create(ctx context.Context, obj Object, opts ...CreateOption) error {
|
func (c *client) Create(ctx context.Context, obj Object, opts ...CreateOption) error {
|
||||||
switch obj.(type) {
|
switch obj.(type) {
|
||||||
case *unstructured.Unstructured:
|
case runtime.Unstructured:
|
||||||
return c.unstructuredClient.Create(ctx, obj, opts...)
|
return c.unstructuredClient.Create(ctx, obj, opts...)
|
||||||
case *metav1.PartialObjectMetadata:
|
case *metav1.PartialObjectMetadata:
|
||||||
return fmt.Errorf("cannot create using only metadata")
|
return fmt.Errorf("cannot create using only metadata")
|
||||||
@ -194,7 +287,7 @@ func (c *client) Create(ctx context.Context, obj Object, opts ...CreateOption) e
|
|||||||
func (c *client) Update(ctx context.Context, obj Object, opts ...UpdateOption) error {
|
func (c *client) Update(ctx context.Context, obj Object, opts ...UpdateOption) error {
|
||||||
defer c.resetGroupVersionKind(obj, obj.GetObjectKind().GroupVersionKind())
|
defer c.resetGroupVersionKind(obj, obj.GetObjectKind().GroupVersionKind())
|
||||||
switch obj.(type) {
|
switch obj.(type) {
|
||||||
case *unstructured.Unstructured:
|
case runtime.Unstructured:
|
||||||
return c.unstructuredClient.Update(ctx, obj, opts...)
|
return c.unstructuredClient.Update(ctx, obj, opts...)
|
||||||
case *metav1.PartialObjectMetadata:
|
case *metav1.PartialObjectMetadata:
|
||||||
return fmt.Errorf("cannot update using only metadata -- did you mean to patch?")
|
return fmt.Errorf("cannot update using only metadata -- did you mean to patch?")
|
||||||
@ -206,7 +299,7 @@ func (c *client) Update(ctx context.Context, obj Object, opts ...UpdateOption) e
|
|||||||
// Delete implements client.Client.
|
// Delete implements client.Client.
|
||||||
func (c *client) Delete(ctx context.Context, obj Object, opts ...DeleteOption) error {
|
func (c *client) Delete(ctx context.Context, obj Object, opts ...DeleteOption) error {
|
||||||
switch obj.(type) {
|
switch obj.(type) {
|
||||||
case *unstructured.Unstructured:
|
case runtime.Unstructured:
|
||||||
return c.unstructuredClient.Delete(ctx, obj, opts...)
|
return c.unstructuredClient.Delete(ctx, obj, opts...)
|
||||||
case *metav1.PartialObjectMetadata:
|
case *metav1.PartialObjectMetadata:
|
||||||
return c.metadataClient.Delete(ctx, obj, opts...)
|
return c.metadataClient.Delete(ctx, obj, opts...)
|
||||||
@ -218,7 +311,7 @@ func (c *client) Delete(ctx context.Context, obj Object, opts ...DeleteOption) e
|
|||||||
// DeleteAllOf implements client.Client.
|
// DeleteAllOf implements client.Client.
|
||||||
func (c *client) DeleteAllOf(ctx context.Context, obj Object, opts ...DeleteAllOfOption) error {
|
func (c *client) DeleteAllOf(ctx context.Context, obj Object, opts ...DeleteAllOfOption) error {
|
||||||
switch obj.(type) {
|
switch obj.(type) {
|
||||||
case *unstructured.Unstructured:
|
case runtime.Unstructured:
|
||||||
return c.unstructuredClient.DeleteAllOf(ctx, obj, opts...)
|
return c.unstructuredClient.DeleteAllOf(ctx, obj, opts...)
|
||||||
case *metav1.PartialObjectMetadata:
|
case *metav1.PartialObjectMetadata:
|
||||||
return c.metadataClient.DeleteAllOf(ctx, obj, opts...)
|
return c.metadataClient.DeleteAllOf(ctx, obj, opts...)
|
||||||
@ -231,7 +324,7 @@ func (c *client) DeleteAllOf(ctx context.Context, obj Object, opts ...DeleteAllO
|
|||||||
func (c *client) Patch(ctx context.Context, obj Object, patch Patch, opts ...PatchOption) error {
|
func (c *client) Patch(ctx context.Context, obj Object, patch Patch, opts ...PatchOption) error {
|
||||||
defer c.resetGroupVersionKind(obj, obj.GetObjectKind().GroupVersionKind())
|
defer c.resetGroupVersionKind(obj, obj.GetObjectKind().GroupVersionKind())
|
||||||
switch obj.(type) {
|
switch obj.(type) {
|
||||||
case *unstructured.Unstructured:
|
case runtime.Unstructured:
|
||||||
return c.unstructuredClient.Patch(ctx, obj, patch, opts...)
|
return c.unstructuredClient.Patch(ctx, obj, patch, opts...)
|
||||||
case *metav1.PartialObjectMetadata:
|
case *metav1.PartialObjectMetadata:
|
||||||
return c.metadataClient.Patch(ctx, obj, patch, opts...)
|
return c.metadataClient.Patch(ctx, obj, patch, opts...)
|
||||||
@ -242,8 +335,14 @@ func (c *client) Patch(ctx context.Context, obj Object, patch Patch, opts ...Pat
|
|||||||
|
|
||||||
// Get implements client.Client.
|
// Get implements client.Client.
|
||||||
func (c *client) Get(ctx context.Context, key ObjectKey, obj Object, opts ...GetOption) error {
|
func (c *client) Get(ctx context.Context, key ObjectKey, obj Object, opts ...GetOption) error {
|
||||||
|
if isUncached, err := c.shouldBypassCache(obj); err != nil {
|
||||||
|
return err
|
||||||
|
} else if !isUncached {
|
||||||
|
return c.cache.Get(ctx, key, obj, opts...)
|
||||||
|
}
|
||||||
|
|
||||||
switch obj.(type) {
|
switch obj.(type) {
|
||||||
case *unstructured.Unstructured:
|
case runtime.Unstructured:
|
||||||
return c.unstructuredClient.Get(ctx, key, obj, opts...)
|
return c.unstructuredClient.Get(ctx, key, obj, opts...)
|
||||||
case *metav1.PartialObjectMetadata:
|
case *metav1.PartialObjectMetadata:
|
||||||
// Metadata only object should always preserve the GVK coming in from the caller.
|
// Metadata only object should always preserve the GVK coming in from the caller.
|
||||||
@ -256,8 +355,14 @@ func (c *client) Get(ctx context.Context, key ObjectKey, obj Object, opts ...Get
|
|||||||
|
|
||||||
// List implements client.Client.
|
// List implements client.Client.
|
||||||
func (c *client) List(ctx context.Context, obj ObjectList, opts ...ListOption) error {
|
func (c *client) List(ctx context.Context, obj ObjectList, opts ...ListOption) error {
|
||||||
|
if isUncached, err := c.shouldBypassCache(obj); err != nil {
|
||||||
|
return err
|
||||||
|
} else if !isUncached {
|
||||||
|
return c.cache.List(ctx, obj, opts...)
|
||||||
|
}
|
||||||
|
|
||||||
switch x := obj.(type) {
|
switch x := obj.(type) {
|
||||||
case *unstructured.UnstructuredList:
|
case runtime.Unstructured:
|
||||||
return c.unstructuredClient.List(ctx, obj, opts...)
|
return c.unstructuredClient.List(ctx, obj, opts...)
|
||||||
case *metav1.PartialObjectMetadataList:
|
case *metav1.PartialObjectMetadataList:
|
||||||
// Metadata only object should always preserve the GVK.
|
// Metadata only object should always preserve the GVK.
|
||||||
@ -431,7 +536,7 @@ func (po *SubResourcePatchOptions) ApplyToSubResourcePatch(o *SubResourcePatchOp
|
|||||||
|
|
||||||
func (sc *subResourceClient) Get(ctx context.Context, obj Object, subResource Object, opts ...SubResourceGetOption) error {
|
func (sc *subResourceClient) Get(ctx context.Context, obj Object, subResource Object, opts ...SubResourceGetOption) error {
|
||||||
switch obj.(type) {
|
switch obj.(type) {
|
||||||
case *unstructured.Unstructured:
|
case runtime.Unstructured:
|
||||||
return sc.client.unstructuredClient.GetSubResource(ctx, obj, subResource, sc.subResource, opts...)
|
return sc.client.unstructuredClient.GetSubResource(ctx, obj, subResource, sc.subResource, opts...)
|
||||||
case *metav1.PartialObjectMetadata:
|
case *metav1.PartialObjectMetadata:
|
||||||
return errors.New("can not get subresource using only metadata")
|
return errors.New("can not get subresource using only metadata")
|
||||||
@ -446,7 +551,7 @@ func (sc *subResourceClient) Create(ctx context.Context, obj Object, subResource
|
|||||||
defer sc.client.resetGroupVersionKind(subResource, subResource.GetObjectKind().GroupVersionKind())
|
defer sc.client.resetGroupVersionKind(subResource, subResource.GetObjectKind().GroupVersionKind())
|
||||||
|
|
||||||
switch obj.(type) {
|
switch obj.(type) {
|
||||||
case *unstructured.Unstructured:
|
case runtime.Unstructured:
|
||||||
return sc.client.unstructuredClient.CreateSubResource(ctx, obj, subResource, sc.subResource, opts...)
|
return sc.client.unstructuredClient.CreateSubResource(ctx, obj, subResource, sc.subResource, opts...)
|
||||||
case *metav1.PartialObjectMetadata:
|
case *metav1.PartialObjectMetadata:
|
||||||
return fmt.Errorf("cannot update status using only metadata -- did you mean to patch?")
|
return fmt.Errorf("cannot update status using only metadata -- did you mean to patch?")
|
||||||
@ -459,7 +564,7 @@ func (sc *subResourceClient) Create(ctx context.Context, obj Object, subResource
|
|||||||
func (sc *subResourceClient) Update(ctx context.Context, obj Object, opts ...SubResourceUpdateOption) error {
|
func (sc *subResourceClient) Update(ctx context.Context, obj Object, opts ...SubResourceUpdateOption) error {
|
||||||
defer sc.client.resetGroupVersionKind(obj, obj.GetObjectKind().GroupVersionKind())
|
defer sc.client.resetGroupVersionKind(obj, obj.GetObjectKind().GroupVersionKind())
|
||||||
switch obj.(type) {
|
switch obj.(type) {
|
||||||
case *unstructured.Unstructured:
|
case runtime.Unstructured:
|
||||||
return sc.client.unstructuredClient.UpdateSubResource(ctx, obj, sc.subResource, opts...)
|
return sc.client.unstructuredClient.UpdateSubResource(ctx, obj, sc.subResource, opts...)
|
||||||
case *metav1.PartialObjectMetadata:
|
case *metav1.PartialObjectMetadata:
|
||||||
return fmt.Errorf("cannot update status using only metadata -- did you mean to patch?")
|
return fmt.Errorf("cannot update status using only metadata -- did you mean to patch?")
|
||||||
@ -472,7 +577,7 @@ func (sc *subResourceClient) Update(ctx context.Context, obj Object, opts ...Sub
|
|||||||
func (sc *subResourceClient) Patch(ctx context.Context, obj Object, patch Patch, opts ...SubResourcePatchOption) error {
|
func (sc *subResourceClient) Patch(ctx context.Context, obj Object, patch Patch, opts ...SubResourcePatchOption) error {
|
||||||
defer sc.client.resetGroupVersionKind(obj, obj.GetObjectKind().GroupVersionKind())
|
defer sc.client.resetGroupVersionKind(obj, obj.GetObjectKind().GroupVersionKind())
|
||||||
switch obj.(type) {
|
switch obj.(type) {
|
||||||
case *unstructured.Unstructured:
|
case runtime.Unstructured:
|
||||||
return sc.client.unstructuredClient.PatchSubResource(ctx, obj, sc.subResource, patch, opts...)
|
return sc.client.unstructuredClient.PatchSubResource(ctx, obj, sc.subResource, patch, opts...)
|
||||||
case *metav1.PartialObjectMetadata:
|
case *metav1.PartialObjectMetadata:
|
||||||
return sc.client.metadataClient.PatchSubResource(ctx, obj, sc.subResource, patch, opts...)
|
return sc.client.metadataClient.PatchSubResource(ctx, obj, sc.subResource, patch, opts...)
|
||||||
|
@ -17,12 +17,12 @@ limitations under the License.
|
|||||||
package client
|
package client
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"k8s.io/apimachinery/pkg/api/meta"
|
"k8s.io/apimachinery/pkg/api/meta"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||||
"k8s.io/apimachinery/pkg/runtime/serializer"
|
"k8s.io/apimachinery/pkg/runtime/serializer"
|
||||||
@ -30,8 +30,11 @@ import (
|
|||||||
"sigs.k8s.io/controller-runtime/pkg/client/apiutil"
|
"sigs.k8s.io/controller-runtime/pkg/client/apiutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
// clientCache creates and caches rest clients and metadata for Kubernetes types.
|
// clientRestResources creates and stores rest clients and metadata for Kubernetes types.
|
||||||
type clientCache struct {
|
type clientRestResources struct {
|
||||||
|
// httpClient is the http client to use for requests
|
||||||
|
httpClient *http.Client
|
||||||
|
|
||||||
// config is the rest.Config to talk to an apiserver
|
// config is the rest.Config to talk to an apiserver
|
||||||
config *rest.Config
|
config *rest.Config
|
||||||
|
|
||||||
@ -44,22 +47,22 @@ type clientCache struct {
|
|||||||
// codecs are used to create a REST client for a gvk
|
// codecs are used to create a REST client for a gvk
|
||||||
codecs serializer.CodecFactory
|
codecs serializer.CodecFactory
|
||||||
|
|
||||||
// structuredResourceByType caches structured type metadata
|
// structuredResourceByType stores structured type metadata
|
||||||
structuredResourceByType map[schema.GroupVersionKind]*resourceMeta
|
structuredResourceByType map[schema.GroupVersionKind]*resourceMeta
|
||||||
// unstructuredResourceByType caches unstructured type metadata
|
// unstructuredResourceByType stores unstructured type metadata
|
||||||
unstructuredResourceByType map[schema.GroupVersionKind]*resourceMeta
|
unstructuredResourceByType map[schema.GroupVersionKind]*resourceMeta
|
||||||
mu sync.RWMutex
|
mu sync.RWMutex
|
||||||
}
|
}
|
||||||
|
|
||||||
// newResource maps obj to a Kubernetes Resource and constructs a client for that Resource.
|
// newResource maps obj to a Kubernetes Resource and constructs a client for that Resource.
|
||||||
// If the object is a list, the resource represents the item's type instead.
|
// If the object is a list, the resource represents the item's type instead.
|
||||||
func (c *clientCache) newResource(gvk schema.GroupVersionKind, isList, isUnstructured bool) (*resourceMeta, error) {
|
func (c *clientRestResources) newResource(gvk schema.GroupVersionKind, isList, isUnstructured bool) (*resourceMeta, error) {
|
||||||
if strings.HasSuffix(gvk.Kind, "List") && isList {
|
if strings.HasSuffix(gvk.Kind, "List") && isList {
|
||||||
// if this was a list, treat it as a request for the item's resource
|
// if this was a list, treat it as a request for the item's resource
|
||||||
gvk.Kind = gvk.Kind[:len(gvk.Kind)-4]
|
gvk.Kind = gvk.Kind[:len(gvk.Kind)-4]
|
||||||
}
|
}
|
||||||
|
|
||||||
client, err := apiutil.RESTClientForGVK(gvk, isUnstructured, c.config, c.codecs)
|
client, err := apiutil.RESTClientForGVK(gvk, isUnstructured, c.config, c.codecs, c.httpClient)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -72,15 +75,13 @@ func (c *clientCache) newResource(gvk schema.GroupVersionKind, isList, isUnstruc
|
|||||||
|
|
||||||
// getResource returns the resource meta information for the given type of object.
|
// getResource returns the resource meta information for the given type of object.
|
||||||
// If the object is a list, the resource represents the item's type instead.
|
// If the object is a list, the resource represents the item's type instead.
|
||||||
func (c *clientCache) getResource(obj runtime.Object) (*resourceMeta, error) {
|
func (c *clientRestResources) getResource(obj runtime.Object) (*resourceMeta, error) {
|
||||||
gvk, err := apiutil.GVKForObject(obj, c.scheme)
|
gvk, err := apiutil.GVKForObject(obj, c.scheme)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
_, isUnstructured := obj.(*unstructured.Unstructured)
|
_, isUnstructured := obj.(runtime.Unstructured)
|
||||||
_, isUnstructuredList := obj.(*unstructured.UnstructuredList)
|
|
||||||
isUnstructured = isUnstructured || isUnstructuredList
|
|
||||||
|
|
||||||
// It's better to do creation work twice than to not let multiple
|
// It's better to do creation work twice than to not let multiple
|
||||||
// people make requests at once
|
// people make requests at once
|
||||||
@ -108,7 +109,7 @@ func (c *clientCache) getResource(obj runtime.Object) (*resourceMeta, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// getObjMeta returns objMeta containing both type and object metadata and state.
|
// getObjMeta returns objMeta containing both type and object metadata and state.
|
||||||
func (c *clientCache) getObjMeta(obj runtime.Object) (*objMeta, error) {
|
func (c *clientRestResources) getObjMeta(obj runtime.Object) (*objMeta, error) {
|
||||||
r, err := c.getResource(obj)
|
r, err := c.getResource(obj)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -120,7 +121,7 @@ func (c *clientCache) getObjMeta(obj runtime.Object) (*objMeta, error) {
|
|||||||
return &objMeta{resourceMeta: r, Object: m}, err
|
return &objMeta{resourceMeta: r, Object: m}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// resourceMeta caches state for a Kubernetes type.
|
// resourceMeta stores state for a Kubernetes type.
|
||||||
type resourceMeta struct {
|
type resourceMeta struct {
|
||||||
// client is the rest client used to talk to the apiserver
|
// client is the rest client used to talk to the apiserver
|
||||||
rest.Interface
|
rest.Interface
|
6
vendor/sigs.k8s.io/controller-runtime/pkg/client/config/config.go
generated
vendored
6
vendor/sigs.k8s.io/controller-runtime/pkg/client/config/config.go
generated
vendored
@ -98,12 +98,12 @@ func GetConfigWithContext(context string) (*rest.Config, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if cfg.QPS == 0.0 {
|
if cfg.QPS == 0.0 {
|
||||||
cfg.QPS = 20.0
|
cfg.QPS = 20.0
|
||||||
cfg.Burst = 30.0
|
|
||||||
}
|
}
|
||||||
|
if cfg.Burst == 0 {
|
||||||
|
cfg.Burst = 30
|
||||||
|
}
|
||||||
return cfg, nil
|
return cfg, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
3
vendor/sigs.k8s.io/controller-runtime/pkg/client/doc.go
generated
vendored
3
vendor/sigs.k8s.io/controller-runtime/pkg/client/doc.go
generated
vendored
@ -26,8 +26,7 @@ limitations under the License.
|
|||||||
// to the API server.
|
// to the API server.
|
||||||
//
|
//
|
||||||
// It is a common pattern in Kubernetes to read from a cache and write to the API
|
// It is a common pattern in Kubernetes to read from a cache and write to the API
|
||||||
// server. This pattern is covered by the DelegatingClient type, which can
|
// server. This pattern is covered by the creating the Client with a Cache.
|
||||||
// be used to have a client whose Reader is different from the Writer.
|
|
||||||
//
|
//
|
||||||
// # Options
|
// # Options
|
||||||
//
|
//
|
||||||
|
11
vendor/sigs.k8s.io/controller-runtime/pkg/client/dryrun.go
generated
vendored
11
vendor/sigs.k8s.io/controller-runtime/pkg/client/dryrun.go
generated
vendored
@ -21,6 +21,7 @@ import (
|
|||||||
|
|
||||||
"k8s.io/apimachinery/pkg/api/meta"
|
"k8s.io/apimachinery/pkg/api/meta"
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewDryRunClient wraps an existing client and enforces DryRun mode
|
// NewDryRunClient wraps an existing client and enforces DryRun mode
|
||||||
@ -46,6 +47,16 @@ func (c *dryRunClient) RESTMapper() meta.RESTMapper {
|
|||||||
return c.client.RESTMapper()
|
return c.client.RESTMapper()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GroupVersionKindFor returns the GroupVersionKind for the given object.
|
||||||
|
func (c *dryRunClient) GroupVersionKindFor(obj runtime.Object) (schema.GroupVersionKind, error) {
|
||||||
|
return c.client.GroupVersionKindFor(obj)
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsObjectNamespaced returns true if the GroupVersionKind of the object is namespaced.
|
||||||
|
func (c *dryRunClient) IsObjectNamespaced(obj runtime.Object) (bool, error) {
|
||||||
|
return c.client.IsObjectNamespaced(obj)
|
||||||
|
}
|
||||||
|
|
||||||
// Create implements client.Client.
|
// Create implements client.Client.
|
||||||
func (c *dryRunClient) Create(ctx context.Context, obj Object, opts ...CreateOption) error {
|
func (c *dryRunClient) Create(ctx context.Context, obj Object, opts ...CreateOption) error {
|
||||||
return c.client.Create(ctx, obj, append(opts, DryRunAll)...)
|
return c.client.Create(ctx, obj, append(opts, DryRunAll)...)
|
||||||
|
5
vendor/sigs.k8s.io/controller-runtime/pkg/client/interfaces.go
generated
vendored
5
vendor/sigs.k8s.io/controller-runtime/pkg/client/interfaces.go
generated
vendored
@ -20,6 +20,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
|
|
||||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||||
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||||
|
|
||||||
"k8s.io/apimachinery/pkg/api/meta"
|
"k8s.io/apimachinery/pkg/api/meta"
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
@ -169,6 +170,10 @@ type Client interface {
|
|||||||
Scheme() *runtime.Scheme
|
Scheme() *runtime.Scheme
|
||||||
// RESTMapper returns the rest this client is using.
|
// RESTMapper returns the rest this client is using.
|
||||||
RESTMapper() meta.RESTMapper
|
RESTMapper() meta.RESTMapper
|
||||||
|
// GroupVersionKindFor returns the GroupVersionKind for the given object.
|
||||||
|
GroupVersionKindFor(obj runtime.Object) (schema.GroupVersionKind, error)
|
||||||
|
// IsObjectNamespaced returns true if the GroupVersionKind of the object is namespaced.
|
||||||
|
IsObjectNamespaced(obj runtime.Object) (bool, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithWatch supports Watch on top of the CRUD operations supported by
|
// WithWatch supports Watch on top of the CRUD operations supported by
|
||||||
|
33
vendor/sigs.k8s.io/controller-runtime/pkg/client/namespaced_client.go
generated
vendored
33
vendor/sigs.k8s.io/controller-runtime/pkg/client/namespaced_client.go
generated
vendored
@ -22,7 +22,7 @@ import (
|
|||||||
|
|
||||||
"k8s.io/apimachinery/pkg/api/meta"
|
"k8s.io/apimachinery/pkg/api/meta"
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
"sigs.k8s.io/controller-runtime/pkg/internal/objectutil"
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewNamespacedClient wraps an existing client enforcing the namespace value.
|
// NewNamespacedClient wraps an existing client enforcing the namespace value.
|
||||||
@ -52,9 +52,19 @@ func (n *namespacedClient) RESTMapper() meta.RESTMapper {
|
|||||||
return n.client.RESTMapper()
|
return n.client.RESTMapper()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GroupVersionKindFor returns the GroupVersionKind for the given object.
|
||||||
|
func (n *namespacedClient) GroupVersionKindFor(obj runtime.Object) (schema.GroupVersionKind, error) {
|
||||||
|
return n.client.GroupVersionKindFor(obj)
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsObjectNamespaced returns true if the GroupVersionKind of the object is namespaced.
|
||||||
|
func (n *namespacedClient) IsObjectNamespaced(obj runtime.Object) (bool, error) {
|
||||||
|
return n.client.IsObjectNamespaced(obj)
|
||||||
|
}
|
||||||
|
|
||||||
// Create implements client.Client.
|
// Create implements client.Client.
|
||||||
func (n *namespacedClient) Create(ctx context.Context, obj Object, opts ...CreateOption) error {
|
func (n *namespacedClient) Create(ctx context.Context, obj Object, opts ...CreateOption) error {
|
||||||
isNamespaceScoped, err := objectutil.IsAPINamespaced(obj, n.Scheme(), n.RESTMapper())
|
isNamespaceScoped, err := n.IsObjectNamespaced(obj)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("error finding the scope of the object: %w", err)
|
return fmt.Errorf("error finding the scope of the object: %w", err)
|
||||||
}
|
}
|
||||||
@ -72,7 +82,7 @@ func (n *namespacedClient) Create(ctx context.Context, obj Object, opts ...Creat
|
|||||||
|
|
||||||
// Update implements client.Client.
|
// Update implements client.Client.
|
||||||
func (n *namespacedClient) Update(ctx context.Context, obj Object, opts ...UpdateOption) error {
|
func (n *namespacedClient) Update(ctx context.Context, obj Object, opts ...UpdateOption) error {
|
||||||
isNamespaceScoped, err := objectutil.IsAPINamespaced(obj, n.Scheme(), n.RESTMapper())
|
isNamespaceScoped, err := n.IsObjectNamespaced(obj)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("error finding the scope of the object: %w", err)
|
return fmt.Errorf("error finding the scope of the object: %w", err)
|
||||||
}
|
}
|
||||||
@ -90,7 +100,7 @@ func (n *namespacedClient) Update(ctx context.Context, obj Object, opts ...Updat
|
|||||||
|
|
||||||
// Delete implements client.Client.
|
// Delete implements client.Client.
|
||||||
func (n *namespacedClient) Delete(ctx context.Context, obj Object, opts ...DeleteOption) error {
|
func (n *namespacedClient) Delete(ctx context.Context, obj Object, opts ...DeleteOption) error {
|
||||||
isNamespaceScoped, err := objectutil.IsAPINamespaced(obj, n.Scheme(), n.RESTMapper())
|
isNamespaceScoped, err := n.IsObjectNamespaced(obj)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("error finding the scope of the object: %w", err)
|
return fmt.Errorf("error finding the scope of the object: %w", err)
|
||||||
}
|
}
|
||||||
@ -108,7 +118,7 @@ func (n *namespacedClient) Delete(ctx context.Context, obj Object, opts ...Delet
|
|||||||
|
|
||||||
// DeleteAllOf implements client.Client.
|
// DeleteAllOf implements client.Client.
|
||||||
func (n *namespacedClient) DeleteAllOf(ctx context.Context, obj Object, opts ...DeleteAllOfOption) error {
|
func (n *namespacedClient) DeleteAllOf(ctx context.Context, obj Object, opts ...DeleteAllOfOption) error {
|
||||||
isNamespaceScoped, err := objectutil.IsAPINamespaced(obj, n.Scheme(), n.RESTMapper())
|
isNamespaceScoped, err := n.IsObjectNamespaced(obj)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("error finding the scope of the object: %w", err)
|
return fmt.Errorf("error finding the scope of the object: %w", err)
|
||||||
}
|
}
|
||||||
@ -121,7 +131,7 @@ func (n *namespacedClient) DeleteAllOf(ctx context.Context, obj Object, opts ...
|
|||||||
|
|
||||||
// Patch implements client.Client.
|
// Patch implements client.Client.
|
||||||
func (n *namespacedClient) Patch(ctx context.Context, obj Object, patch Patch, opts ...PatchOption) error {
|
func (n *namespacedClient) Patch(ctx context.Context, obj Object, patch Patch, opts ...PatchOption) error {
|
||||||
isNamespaceScoped, err := objectutil.IsAPINamespaced(obj, n.Scheme(), n.RESTMapper())
|
isNamespaceScoped, err := n.IsObjectNamespaced(obj)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("error finding the scope of the object: %w", err)
|
return fmt.Errorf("error finding the scope of the object: %w", err)
|
||||||
}
|
}
|
||||||
@ -139,7 +149,7 @@ func (n *namespacedClient) Patch(ctx context.Context, obj Object, patch Patch, o
|
|||||||
|
|
||||||
// Get implements client.Client.
|
// Get implements client.Client.
|
||||||
func (n *namespacedClient) Get(ctx context.Context, key ObjectKey, obj Object, opts ...GetOption) error {
|
func (n *namespacedClient) Get(ctx context.Context, key ObjectKey, obj Object, opts ...GetOption) error {
|
||||||
isNamespaceScoped, err := objectutil.IsAPINamespaced(obj, n.Scheme(), n.RESTMapper())
|
isNamespaceScoped, err := n.IsObjectNamespaced(obj)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("error finding the scope of the object: %w", err)
|
return fmt.Errorf("error finding the scope of the object: %w", err)
|
||||||
}
|
}
|
||||||
@ -180,7 +190,7 @@ type namespacedClientSubResourceClient struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (nsw *namespacedClientSubResourceClient) Get(ctx context.Context, obj, subResource Object, opts ...SubResourceGetOption) error {
|
func (nsw *namespacedClientSubResourceClient) Get(ctx context.Context, obj, subResource Object, opts ...SubResourceGetOption) error {
|
||||||
isNamespaceScoped, err := objectutil.IsAPINamespaced(obj, nsw.namespacedclient.Scheme(), nsw.namespacedclient.RESTMapper())
|
isNamespaceScoped, err := nsw.namespacedclient.IsObjectNamespaced(obj)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("error finding the scope of the object: %w", err)
|
return fmt.Errorf("error finding the scope of the object: %w", err)
|
||||||
}
|
}
|
||||||
@ -198,7 +208,7 @@ func (nsw *namespacedClientSubResourceClient) Get(ctx context.Context, obj, subR
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (nsw *namespacedClientSubResourceClient) Create(ctx context.Context, obj, subResource Object, opts ...SubResourceCreateOption) error {
|
func (nsw *namespacedClientSubResourceClient) Create(ctx context.Context, obj, subResource Object, opts ...SubResourceCreateOption) error {
|
||||||
isNamespaceScoped, err := objectutil.IsAPINamespaced(obj, nsw.namespacedclient.Scheme(), nsw.namespacedclient.RESTMapper())
|
isNamespaceScoped, err := nsw.namespacedclient.IsObjectNamespaced(obj)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("error finding the scope of the object: %w", err)
|
return fmt.Errorf("error finding the scope of the object: %w", err)
|
||||||
}
|
}
|
||||||
@ -217,7 +227,7 @@ func (nsw *namespacedClientSubResourceClient) Create(ctx context.Context, obj, s
|
|||||||
|
|
||||||
// Update implements client.SubResourceWriter.
|
// Update implements client.SubResourceWriter.
|
||||||
func (nsw *namespacedClientSubResourceClient) Update(ctx context.Context, obj Object, opts ...SubResourceUpdateOption) error {
|
func (nsw *namespacedClientSubResourceClient) Update(ctx context.Context, obj Object, opts ...SubResourceUpdateOption) error {
|
||||||
isNamespaceScoped, err := objectutil.IsAPINamespaced(obj, nsw.namespacedclient.Scheme(), nsw.namespacedclient.RESTMapper())
|
isNamespaceScoped, err := nsw.namespacedclient.IsObjectNamespaced(obj)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("error finding the scope of the object: %w", err)
|
return fmt.Errorf("error finding the scope of the object: %w", err)
|
||||||
}
|
}
|
||||||
@ -235,8 +245,7 @@ func (nsw *namespacedClientSubResourceClient) Update(ctx context.Context, obj Ob
|
|||||||
|
|
||||||
// Patch implements client.SubResourceWriter.
|
// Patch implements client.SubResourceWriter.
|
||||||
func (nsw *namespacedClientSubResourceClient) Patch(ctx context.Context, obj Object, patch Patch, opts ...SubResourcePatchOption) error {
|
func (nsw *namespacedClientSubResourceClient) Patch(ctx context.Context, obj Object, patch Patch, opts ...SubResourcePatchOption) error {
|
||||||
isNamespaceScoped, err := objectutil.IsAPINamespaced(obj, nsw.namespacedclient.Scheme(), nsw.namespacedclient.RESTMapper())
|
isNamespaceScoped, err := nsw.namespacedclient.IsObjectNamespaced(obj)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("error finding the scope of the object: %w", err)
|
return fmt.Errorf("error finding the scope of the object: %w", err)
|
||||||
}
|
}
|
||||||
|
10
vendor/sigs.k8s.io/controller-runtime/pkg/client/options.go
generated
vendored
10
vendor/sigs.k8s.io/controller-runtime/pkg/client/options.go
generated
vendored
@ -606,6 +606,11 @@ func (n InNamespace) ApplyToDeleteAllOf(opts *DeleteAllOfOptions) {
|
|||||||
n.ApplyToList(&opts.ListOptions)
|
n.ApplyToList(&opts.ListOptions)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AsSelector returns a selector that matches objects in the given namespace.
|
||||||
|
func (n InNamespace) AsSelector() fields.Selector {
|
||||||
|
return fields.SelectorFromSet(fields.Set{"metadata.namespace": string(n)})
|
||||||
|
}
|
||||||
|
|
||||||
// Limit specifies the maximum number of results to return from the server.
|
// Limit specifies the maximum number of results to return from the server.
|
||||||
// Limit does not implement DeleteAllOfOption interface because the server
|
// Limit does not implement DeleteAllOfOption interface because the server
|
||||||
// does not support setting it for deletecollection operations.
|
// does not support setting it for deletecollection operations.
|
||||||
@ -788,6 +793,11 @@ func (forceOwnership) ApplyToPatch(opts *PatchOptions) {
|
|||||||
opts.Force = &definitelyTrue
|
opts.Force = &definitelyTrue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (forceOwnership) ApplyToSubResourcePatch(opts *SubResourcePatchOptions) {
|
||||||
|
definitelyTrue := true
|
||||||
|
opts.Force = &definitelyTrue
|
||||||
|
}
|
||||||
|
|
||||||
// }}}
|
// }}}
|
||||||
|
|
||||||
// {{{ DeleteAllOf Options
|
// {{{ DeleteAllOf Options
|
||||||
|
143
vendor/sigs.k8s.io/controller-runtime/pkg/client/split.go
generated
vendored
143
vendor/sigs.k8s.io/controller-runtime/pkg/client/split.go
generated
vendored
@ -1,143 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright 2018 The Kubernetes Authors.
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package client
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"k8s.io/apimachinery/pkg/api/meta"
|
|
||||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
|
||||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
|
||||||
|
|
||||||
"sigs.k8s.io/controller-runtime/pkg/client/apiutil"
|
|
||||||
)
|
|
||||||
|
|
||||||
// NewDelegatingClientInput encapsulates the input parameters to create a new delegating client.
|
|
||||||
type NewDelegatingClientInput struct {
|
|
||||||
CacheReader Reader
|
|
||||||
Client Client
|
|
||||||
UncachedObjects []Object
|
|
||||||
CacheUnstructured bool
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewDelegatingClient creates a new delegating client.
|
|
||||||
//
|
|
||||||
// A delegating client forms a Client by composing separate reader, writer and
|
|
||||||
// statusclient interfaces. This way, you can have an Client that reads from a
|
|
||||||
// cache and writes to the API server.
|
|
||||||
func NewDelegatingClient(in NewDelegatingClientInput) (Client, error) {
|
|
||||||
uncachedGVKs := map[schema.GroupVersionKind]struct{}{}
|
|
||||||
for _, obj := range in.UncachedObjects {
|
|
||||||
gvk, err := apiutil.GVKForObject(obj, in.Client.Scheme())
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
uncachedGVKs[gvk] = struct{}{}
|
|
||||||
}
|
|
||||||
|
|
||||||
return &delegatingClient{
|
|
||||||
scheme: in.Client.Scheme(),
|
|
||||||
mapper: in.Client.RESTMapper(),
|
|
||||||
Reader: &delegatingReader{
|
|
||||||
CacheReader: in.CacheReader,
|
|
||||||
ClientReader: in.Client,
|
|
||||||
scheme: in.Client.Scheme(),
|
|
||||||
uncachedGVKs: uncachedGVKs,
|
|
||||||
cacheUnstructured: in.CacheUnstructured,
|
|
||||||
},
|
|
||||||
Writer: in.Client,
|
|
||||||
StatusClient: in.Client,
|
|
||||||
SubResourceClientConstructor: in.Client,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type delegatingClient struct {
|
|
||||||
Reader
|
|
||||||
Writer
|
|
||||||
StatusClient
|
|
||||||
SubResourceClientConstructor
|
|
||||||
|
|
||||||
scheme *runtime.Scheme
|
|
||||||
mapper meta.RESTMapper
|
|
||||||
}
|
|
||||||
|
|
||||||
// Scheme returns the scheme this client is using.
|
|
||||||
func (d *delegatingClient) Scheme() *runtime.Scheme {
|
|
||||||
return d.scheme
|
|
||||||
}
|
|
||||||
|
|
||||||
// RESTMapper returns the rest mapper this client is using.
|
|
||||||
func (d *delegatingClient) RESTMapper() meta.RESTMapper {
|
|
||||||
return d.mapper
|
|
||||||
}
|
|
||||||
|
|
||||||
// delegatingReader forms a Reader that will cause Get and List requests for
|
|
||||||
// unstructured types to use the ClientReader while requests for any other type
|
|
||||||
// of object with use the CacheReader. This avoids accidentally caching the
|
|
||||||
// entire cluster in the common case of loading arbitrary unstructured objects
|
|
||||||
// (e.g. from OwnerReferences).
|
|
||||||
type delegatingReader struct {
|
|
||||||
CacheReader Reader
|
|
||||||
ClientReader Reader
|
|
||||||
|
|
||||||
uncachedGVKs map[schema.GroupVersionKind]struct{}
|
|
||||||
scheme *runtime.Scheme
|
|
||||||
cacheUnstructured bool
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *delegatingReader) shouldBypassCache(obj runtime.Object) (bool, error) {
|
|
||||||
gvk, err := apiutil.GVKForObject(obj, d.scheme)
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
// TODO: this is producing unsafe guesses that don't actually work,
|
|
||||||
// but it matches ~99% of the cases out there.
|
|
||||||
if meta.IsListType(obj) {
|
|
||||||
gvk.Kind = strings.TrimSuffix(gvk.Kind, "List")
|
|
||||||
}
|
|
||||||
if _, isUncached := d.uncachedGVKs[gvk]; isUncached {
|
|
||||||
return true, nil
|
|
||||||
}
|
|
||||||
if !d.cacheUnstructured {
|
|
||||||
_, isUnstructured := obj.(*unstructured.Unstructured)
|
|
||||||
_, isUnstructuredList := obj.(*unstructured.UnstructuredList)
|
|
||||||
return isUnstructured || isUnstructuredList, nil
|
|
||||||
}
|
|
||||||
return false, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get retrieves an obj for a given object key from the Kubernetes Cluster.
|
|
||||||
func (d *delegatingReader) Get(ctx context.Context, key ObjectKey, obj Object, opts ...GetOption) error {
|
|
||||||
if isUncached, err := d.shouldBypassCache(obj); err != nil {
|
|
||||||
return err
|
|
||||||
} else if isUncached {
|
|
||||||
return d.ClientReader.Get(ctx, key, obj, opts...)
|
|
||||||
}
|
|
||||||
return d.CacheReader.Get(ctx, key, obj, opts...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// List retrieves list of objects for a given namespace and list options.
|
|
||||||
func (d *delegatingReader) List(ctx context.Context, list ObjectList, opts ...ListOption) error {
|
|
||||||
if isUncached, err := d.shouldBypassCache(list); err != nil {
|
|
||||||
return err
|
|
||||||
} else if isUncached {
|
|
||||||
return d.ClientReader.List(ctx, list, opts...)
|
|
||||||
}
|
|
||||||
return d.CacheReader.List(ctx, list, opts...)
|
|
||||||
}
|
|
26
vendor/sigs.k8s.io/controller-runtime/pkg/client/typed_client.go
generated
vendored
26
vendor/sigs.k8s.io/controller-runtime/pkg/client/typed_client.go
generated
vendored
@ -25,16 +25,14 @@ import (
|
|||||||
var _ Reader = &typedClient{}
|
var _ Reader = &typedClient{}
|
||||||
var _ Writer = &typedClient{}
|
var _ Writer = &typedClient{}
|
||||||
|
|
||||||
// client is a client.Client that reads and writes directly from/to an API server. It lazily initializes
|
|
||||||
// new clients at the time they are used, and caches the client.
|
|
||||||
type typedClient struct {
|
type typedClient struct {
|
||||||
cache *clientCache
|
resources *clientRestResources
|
||||||
paramCodec runtime.ParameterCodec
|
paramCodec runtime.ParameterCodec
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create implements client.Client.
|
// Create implements client.Client.
|
||||||
func (c *typedClient) Create(ctx context.Context, obj Object, opts ...CreateOption) error {
|
func (c *typedClient) Create(ctx context.Context, obj Object, opts ...CreateOption) error {
|
||||||
o, err := c.cache.getObjMeta(obj)
|
o, err := c.resources.getObjMeta(obj)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -53,7 +51,7 @@ func (c *typedClient) Create(ctx context.Context, obj Object, opts ...CreateOpti
|
|||||||
|
|
||||||
// Update implements client.Client.
|
// Update implements client.Client.
|
||||||
func (c *typedClient) Update(ctx context.Context, obj Object, opts ...UpdateOption) error {
|
func (c *typedClient) Update(ctx context.Context, obj Object, opts ...UpdateOption) error {
|
||||||
o, err := c.cache.getObjMeta(obj)
|
o, err := c.resources.getObjMeta(obj)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -73,7 +71,7 @@ func (c *typedClient) Update(ctx context.Context, obj Object, opts ...UpdateOpti
|
|||||||
|
|
||||||
// Delete implements client.Client.
|
// Delete implements client.Client.
|
||||||
func (c *typedClient) Delete(ctx context.Context, obj Object, opts ...DeleteOption) error {
|
func (c *typedClient) Delete(ctx context.Context, obj Object, opts ...DeleteOption) error {
|
||||||
o, err := c.cache.getObjMeta(obj)
|
o, err := c.resources.getObjMeta(obj)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -92,7 +90,7 @@ func (c *typedClient) Delete(ctx context.Context, obj Object, opts ...DeleteOpti
|
|||||||
|
|
||||||
// DeleteAllOf implements client.Client.
|
// DeleteAllOf implements client.Client.
|
||||||
func (c *typedClient) DeleteAllOf(ctx context.Context, obj Object, opts ...DeleteAllOfOption) error {
|
func (c *typedClient) DeleteAllOf(ctx context.Context, obj Object, opts ...DeleteAllOfOption) error {
|
||||||
o, err := c.cache.getObjMeta(obj)
|
o, err := c.resources.getObjMeta(obj)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -111,7 +109,7 @@ func (c *typedClient) DeleteAllOf(ctx context.Context, obj Object, opts ...Delet
|
|||||||
|
|
||||||
// Patch implements client.Client.
|
// Patch implements client.Client.
|
||||||
func (c *typedClient) Patch(ctx context.Context, obj Object, patch Patch, opts ...PatchOption) error {
|
func (c *typedClient) Patch(ctx context.Context, obj Object, patch Patch, opts ...PatchOption) error {
|
||||||
o, err := c.cache.getObjMeta(obj)
|
o, err := c.resources.getObjMeta(obj)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -136,7 +134,7 @@ func (c *typedClient) Patch(ctx context.Context, obj Object, patch Patch, opts .
|
|||||||
|
|
||||||
// Get implements client.Client.
|
// Get implements client.Client.
|
||||||
func (c *typedClient) Get(ctx context.Context, key ObjectKey, obj Object, opts ...GetOption) error {
|
func (c *typedClient) Get(ctx context.Context, key ObjectKey, obj Object, opts ...GetOption) error {
|
||||||
r, err := c.cache.getResource(obj)
|
r, err := c.resources.getResource(obj)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -151,7 +149,7 @@ func (c *typedClient) Get(ctx context.Context, key ObjectKey, obj Object, opts .
|
|||||||
|
|
||||||
// List implements client.Client.
|
// List implements client.Client.
|
||||||
func (c *typedClient) List(ctx context.Context, obj ObjectList, opts ...ListOption) error {
|
func (c *typedClient) List(ctx context.Context, obj ObjectList, opts ...ListOption) error {
|
||||||
r, err := c.cache.getResource(obj)
|
r, err := c.resources.getResource(obj)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -168,7 +166,7 @@ func (c *typedClient) List(ctx context.Context, obj ObjectList, opts ...ListOpti
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *typedClient) GetSubResource(ctx context.Context, obj, subResourceObj Object, subResource string, opts ...SubResourceGetOption) error {
|
func (c *typedClient) GetSubResource(ctx context.Context, obj, subResourceObj Object, subResource string, opts ...SubResourceGetOption) error {
|
||||||
o, err := c.cache.getObjMeta(obj)
|
o, err := c.resources.getObjMeta(obj)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -191,7 +189,7 @@ func (c *typedClient) GetSubResource(ctx context.Context, obj, subResourceObj Ob
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *typedClient) CreateSubResource(ctx context.Context, obj Object, subResourceObj Object, subResource string, opts ...SubResourceCreateOption) error {
|
func (c *typedClient) CreateSubResource(ctx context.Context, obj Object, subResourceObj Object, subResource string, opts ...SubResourceCreateOption) error {
|
||||||
o, err := c.cache.getObjMeta(obj)
|
o, err := c.resources.getObjMeta(obj)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -216,7 +214,7 @@ func (c *typedClient) CreateSubResource(ctx context.Context, obj Object, subReso
|
|||||||
|
|
||||||
// UpdateSubResource used by SubResourceWriter to write status.
|
// UpdateSubResource used by SubResourceWriter to write status.
|
||||||
func (c *typedClient) UpdateSubResource(ctx context.Context, obj Object, subResource string, opts ...SubResourceUpdateOption) error {
|
func (c *typedClient) UpdateSubResource(ctx context.Context, obj Object, subResource string, opts ...SubResourceUpdateOption) error {
|
||||||
o, err := c.cache.getObjMeta(obj)
|
o, err := c.resources.getObjMeta(obj)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -251,7 +249,7 @@ func (c *typedClient) UpdateSubResource(ctx context.Context, obj Object, subReso
|
|||||||
|
|
||||||
// PatchSubResource used by SubResourceWriter to write subresource.
|
// PatchSubResource used by SubResourceWriter to write subresource.
|
||||||
func (c *typedClient) PatchSubResource(ctx context.Context, obj Object, subResource string, patch Patch, opts ...SubResourcePatchOption) error {
|
func (c *typedClient) PatchSubResource(ctx context.Context, obj Object, subResource string, patch Patch, opts ...SubResourcePatchOption) error {
|
||||||
o, err := c.cache.getObjMeta(obj)
|
o, err := c.resources.getObjMeta(obj)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
79
vendor/sigs.k8s.io/controller-runtime/pkg/client/unstructured_client.go
generated
vendored
79
vendor/sigs.k8s.io/controller-runtime/pkg/client/unstructured_client.go
generated
vendored
@ -21,30 +21,27 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
)
|
)
|
||||||
|
|
||||||
var _ Reader = &unstructuredClient{}
|
var _ Reader = &unstructuredClient{}
|
||||||
var _ Writer = &unstructuredClient{}
|
var _ Writer = &unstructuredClient{}
|
||||||
|
|
||||||
// client is a client.Client that reads and writes directly from/to an API server. It lazily initializes
|
|
||||||
// new clients at the time they are used, and caches the client.
|
|
||||||
type unstructuredClient struct {
|
type unstructuredClient struct {
|
||||||
cache *clientCache
|
resources *clientRestResources
|
||||||
paramCodec runtime.ParameterCodec
|
paramCodec runtime.ParameterCodec
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create implements client.Client.
|
// Create implements client.Client.
|
||||||
func (uc *unstructuredClient) Create(ctx context.Context, obj Object, opts ...CreateOption) error {
|
func (uc *unstructuredClient) Create(ctx context.Context, obj Object, opts ...CreateOption) error {
|
||||||
u, ok := obj.(*unstructured.Unstructured)
|
u, ok := obj.(runtime.Unstructured)
|
||||||
if !ok {
|
if !ok {
|
||||||
return fmt.Errorf("unstructured client did not understand object: %T", obj)
|
return fmt.Errorf("unstructured client did not understand object: %T", obj)
|
||||||
}
|
}
|
||||||
|
|
||||||
gvk := u.GroupVersionKind()
|
gvk := u.GetObjectKind().GroupVersionKind()
|
||||||
|
|
||||||
o, err := uc.cache.getObjMeta(obj)
|
o, err := uc.resources.getObjMeta(obj)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -60,20 +57,20 @@ func (uc *unstructuredClient) Create(ctx context.Context, obj Object, opts ...Cr
|
|||||||
Do(ctx).
|
Do(ctx).
|
||||||
Into(obj)
|
Into(obj)
|
||||||
|
|
||||||
u.SetGroupVersionKind(gvk)
|
u.GetObjectKind().SetGroupVersionKind(gvk)
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update implements client.Client.
|
// Update implements client.Client.
|
||||||
func (uc *unstructuredClient) Update(ctx context.Context, obj Object, opts ...UpdateOption) error {
|
func (uc *unstructuredClient) Update(ctx context.Context, obj Object, opts ...UpdateOption) error {
|
||||||
u, ok := obj.(*unstructured.Unstructured)
|
u, ok := obj.(runtime.Unstructured)
|
||||||
if !ok {
|
if !ok {
|
||||||
return fmt.Errorf("unstructured client did not understand object: %T", obj)
|
return fmt.Errorf("unstructured client did not understand object: %T", obj)
|
||||||
}
|
}
|
||||||
|
|
||||||
gvk := u.GroupVersionKind()
|
gvk := u.GetObjectKind().GroupVersionKind()
|
||||||
|
|
||||||
o, err := uc.cache.getObjMeta(obj)
|
o, err := uc.resources.getObjMeta(obj)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -90,17 +87,17 @@ func (uc *unstructuredClient) Update(ctx context.Context, obj Object, opts ...Up
|
|||||||
Do(ctx).
|
Do(ctx).
|
||||||
Into(obj)
|
Into(obj)
|
||||||
|
|
||||||
u.SetGroupVersionKind(gvk)
|
u.GetObjectKind().SetGroupVersionKind(gvk)
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete implements client.Client.
|
// Delete implements client.Client.
|
||||||
func (uc *unstructuredClient) Delete(ctx context.Context, obj Object, opts ...DeleteOption) error {
|
func (uc *unstructuredClient) Delete(ctx context.Context, obj Object, opts ...DeleteOption) error {
|
||||||
if _, ok := obj.(*unstructured.Unstructured); !ok {
|
if _, ok := obj.(runtime.Unstructured); !ok {
|
||||||
return fmt.Errorf("unstructured client did not understand object: %T", obj)
|
return fmt.Errorf("unstructured client did not understand object: %T", obj)
|
||||||
}
|
}
|
||||||
|
|
||||||
o, err := uc.cache.getObjMeta(obj)
|
o, err := uc.resources.getObjMeta(obj)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -119,11 +116,11 @@ func (uc *unstructuredClient) Delete(ctx context.Context, obj Object, opts ...De
|
|||||||
|
|
||||||
// DeleteAllOf implements client.Client.
|
// DeleteAllOf implements client.Client.
|
||||||
func (uc *unstructuredClient) DeleteAllOf(ctx context.Context, obj Object, opts ...DeleteAllOfOption) error {
|
func (uc *unstructuredClient) DeleteAllOf(ctx context.Context, obj Object, opts ...DeleteAllOfOption) error {
|
||||||
if _, ok := obj.(*unstructured.Unstructured); !ok {
|
if _, ok := obj.(runtime.Unstructured); !ok {
|
||||||
return fmt.Errorf("unstructured client did not understand object: %T", obj)
|
return fmt.Errorf("unstructured client did not understand object: %T", obj)
|
||||||
}
|
}
|
||||||
|
|
||||||
o, err := uc.cache.getObjMeta(obj)
|
o, err := uc.resources.getObjMeta(obj)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -142,11 +139,11 @@ func (uc *unstructuredClient) DeleteAllOf(ctx context.Context, obj Object, opts
|
|||||||
|
|
||||||
// Patch implements client.Client.
|
// Patch implements client.Client.
|
||||||
func (uc *unstructuredClient) Patch(ctx context.Context, obj Object, patch Patch, opts ...PatchOption) error {
|
func (uc *unstructuredClient) Patch(ctx context.Context, obj Object, patch Patch, opts ...PatchOption) error {
|
||||||
if _, ok := obj.(*unstructured.Unstructured); !ok {
|
if _, ok := obj.(runtime.Unstructured); !ok {
|
||||||
return fmt.Errorf("unstructured client did not understand object: %T", obj)
|
return fmt.Errorf("unstructured client did not understand object: %T", obj)
|
||||||
}
|
}
|
||||||
|
|
||||||
o, err := uc.cache.getObjMeta(obj)
|
o, err := uc.resources.getObjMeta(obj)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -171,17 +168,17 @@ func (uc *unstructuredClient) Patch(ctx context.Context, obj Object, patch Patch
|
|||||||
|
|
||||||
// Get implements client.Client.
|
// Get implements client.Client.
|
||||||
func (uc *unstructuredClient) Get(ctx context.Context, key ObjectKey, obj Object, opts ...GetOption) error {
|
func (uc *unstructuredClient) Get(ctx context.Context, key ObjectKey, obj Object, opts ...GetOption) error {
|
||||||
u, ok := obj.(*unstructured.Unstructured)
|
u, ok := obj.(runtime.Unstructured)
|
||||||
if !ok {
|
if !ok {
|
||||||
return fmt.Errorf("unstructured client did not understand object: %T", obj)
|
return fmt.Errorf("unstructured client did not understand object: %T", obj)
|
||||||
}
|
}
|
||||||
|
|
||||||
gvk := u.GroupVersionKind()
|
gvk := u.GetObjectKind().GroupVersionKind()
|
||||||
|
|
||||||
getOpts := GetOptions{}
|
getOpts := GetOptions{}
|
||||||
getOpts.ApplyOptions(opts)
|
getOpts.ApplyOptions(opts)
|
||||||
|
|
||||||
r, err := uc.cache.getResource(obj)
|
r, err := uc.resources.getResource(obj)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -194,22 +191,22 @@ func (uc *unstructuredClient) Get(ctx context.Context, key ObjectKey, obj Object
|
|||||||
Do(ctx).
|
Do(ctx).
|
||||||
Into(obj)
|
Into(obj)
|
||||||
|
|
||||||
u.SetGroupVersionKind(gvk)
|
u.GetObjectKind().SetGroupVersionKind(gvk)
|
||||||
|
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
// List implements client.Client.
|
// List implements client.Client.
|
||||||
func (uc *unstructuredClient) List(ctx context.Context, obj ObjectList, opts ...ListOption) error {
|
func (uc *unstructuredClient) List(ctx context.Context, obj ObjectList, opts ...ListOption) error {
|
||||||
u, ok := obj.(*unstructured.UnstructuredList)
|
u, ok := obj.(runtime.Unstructured)
|
||||||
if !ok {
|
if !ok {
|
||||||
return fmt.Errorf("unstructured client did not understand object: %T", obj)
|
return fmt.Errorf("unstructured client did not understand object: %T", obj)
|
||||||
}
|
}
|
||||||
|
|
||||||
gvk := u.GroupVersionKind()
|
gvk := u.GetObjectKind().GroupVersionKind()
|
||||||
gvk.Kind = strings.TrimSuffix(gvk.Kind, "List")
|
gvk.Kind = strings.TrimSuffix(gvk.Kind, "List")
|
||||||
|
|
||||||
r, err := uc.cache.getResource(obj)
|
r, err := uc.resources.getResource(obj)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -226,19 +223,19 @@ func (uc *unstructuredClient) List(ctx context.Context, obj ObjectList, opts ...
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (uc *unstructuredClient) GetSubResource(ctx context.Context, obj, subResourceObj Object, subResource string, opts ...SubResourceGetOption) error {
|
func (uc *unstructuredClient) GetSubResource(ctx context.Context, obj, subResourceObj Object, subResource string, opts ...SubResourceGetOption) error {
|
||||||
if _, ok := obj.(*unstructured.Unstructured); !ok {
|
if _, ok := obj.(runtime.Unstructured); !ok {
|
||||||
return fmt.Errorf("unstructured client did not understand object: %T", subResource)
|
return fmt.Errorf("unstructured client did not understand object: %T", obj)
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, ok := subResourceObj.(*unstructured.Unstructured); !ok {
|
if _, ok := subResourceObj.(runtime.Unstructured); !ok {
|
||||||
return fmt.Errorf("unstructured client did not understand object: %T", obj)
|
return fmt.Errorf("unstructured client did not understand object: %T", subResourceObj)
|
||||||
}
|
}
|
||||||
|
|
||||||
if subResourceObj.GetName() == "" {
|
if subResourceObj.GetName() == "" {
|
||||||
subResourceObj.SetName(obj.GetName())
|
subResourceObj.SetName(obj.GetName())
|
||||||
}
|
}
|
||||||
|
|
||||||
o, err := uc.cache.getObjMeta(obj)
|
o, err := uc.resources.getObjMeta(obj)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -257,19 +254,19 @@ func (uc *unstructuredClient) GetSubResource(ctx context.Context, obj, subResour
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (uc *unstructuredClient) CreateSubResource(ctx context.Context, obj, subResourceObj Object, subResource string, opts ...SubResourceCreateOption) error {
|
func (uc *unstructuredClient) CreateSubResource(ctx context.Context, obj, subResourceObj Object, subResource string, opts ...SubResourceCreateOption) error {
|
||||||
if _, ok := obj.(*unstructured.Unstructured); !ok {
|
if _, ok := obj.(runtime.Unstructured); !ok {
|
||||||
return fmt.Errorf("unstructured client did not understand object: %T", subResourceObj)
|
return fmt.Errorf("unstructured client did not understand object: %T", obj)
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, ok := subResourceObj.(*unstructured.Unstructured); !ok {
|
if _, ok := subResourceObj.(runtime.Unstructured); !ok {
|
||||||
return fmt.Errorf("unstructured client did not understand object: %T", obj)
|
return fmt.Errorf("unstructured client did not understand object: %T", subResourceObj)
|
||||||
}
|
}
|
||||||
|
|
||||||
if subResourceObj.GetName() == "" {
|
if subResourceObj.GetName() == "" {
|
||||||
subResourceObj.SetName(obj.GetName())
|
subResourceObj.SetName(obj.GetName())
|
||||||
}
|
}
|
||||||
|
|
||||||
o, err := uc.cache.getObjMeta(obj)
|
o, err := uc.resources.getObjMeta(obj)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -289,11 +286,11 @@ func (uc *unstructuredClient) CreateSubResource(ctx context.Context, obj, subRes
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (uc *unstructuredClient) UpdateSubResource(ctx context.Context, obj Object, subResource string, opts ...SubResourceUpdateOption) error {
|
func (uc *unstructuredClient) UpdateSubResource(ctx context.Context, obj Object, subResource string, opts ...SubResourceUpdateOption) error {
|
||||||
if _, ok := obj.(*unstructured.Unstructured); !ok {
|
if _, ok := obj.(runtime.Unstructured); !ok {
|
||||||
return fmt.Errorf("unstructured client did not understand object: %T", obj)
|
return fmt.Errorf("unstructured client did not understand object: %T", obj)
|
||||||
}
|
}
|
||||||
|
|
||||||
o, err := uc.cache.getObjMeta(obj)
|
o, err := uc.resources.getObjMeta(obj)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -324,14 +321,14 @@ func (uc *unstructuredClient) UpdateSubResource(ctx context.Context, obj Object,
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (uc *unstructuredClient) PatchSubResource(ctx context.Context, obj Object, subResource string, patch Patch, opts ...SubResourcePatchOption) error {
|
func (uc *unstructuredClient) PatchSubResource(ctx context.Context, obj Object, subResource string, patch Patch, opts ...SubResourcePatchOption) error {
|
||||||
u, ok := obj.(*unstructured.Unstructured)
|
u, ok := obj.(runtime.Unstructured)
|
||||||
if !ok {
|
if !ok {
|
||||||
return fmt.Errorf("unstructured client did not understand object: %T", obj)
|
return fmt.Errorf("unstructured client did not understand object: %T", obj)
|
||||||
}
|
}
|
||||||
|
|
||||||
gvk := u.GroupVersionKind()
|
gvk := u.GetObjectKind().GroupVersionKind()
|
||||||
|
|
||||||
o, err := uc.cache.getObjMeta(obj)
|
o, err := uc.resources.getObjMeta(obj)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -359,6 +356,6 @@ func (uc *unstructuredClient) PatchSubResource(ctx context.Context, obj Object,
|
|||||||
Do(ctx).
|
Do(ctx).
|
||||||
Into(body)
|
Into(body)
|
||||||
|
|
||||||
u.SetGroupVersionKind(gvk)
|
u.GetObjectKind().SetGroupVersionKind(gvk)
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
30
vendor/sigs.k8s.io/controller-runtime/pkg/client/watch.go
generated
vendored
30
vendor/sigs.k8s.io/controller-runtime/pkg/client/watch.go
generated
vendored
@ -21,9 +21,8 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
"k8s.io/apimachinery/pkg/watch"
|
"k8s.io/apimachinery/pkg/watch"
|
||||||
"k8s.io/client-go/dynamic"
|
|
||||||
"k8s.io/client-go/rest"
|
"k8s.io/client-go/rest"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -33,21 +32,16 @@ func NewWithWatch(config *rest.Config, options Options) (WithWatch, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
dynamicClient, err := dynamic.NewForConfig(config)
|
return &watchingClient{client: client}, nil
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return &watchingClient{client: client, dynamic: dynamicClient}, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type watchingClient struct {
|
type watchingClient struct {
|
||||||
*client
|
*client
|
||||||
dynamic dynamic.Interface
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *watchingClient) Watch(ctx context.Context, list ObjectList, opts ...ListOption) (watch.Interface, error) {
|
func (w *watchingClient) Watch(ctx context.Context, list ObjectList, opts ...ListOption) (watch.Interface, error) {
|
||||||
switch l := list.(type) {
|
switch l := list.(type) {
|
||||||
case *unstructured.UnstructuredList:
|
case runtime.Unstructured:
|
||||||
return w.unstructuredWatch(ctx, l, opts...)
|
return w.unstructuredWatch(ctx, l, opts...)
|
||||||
case *metav1.PartialObjectMetadataList:
|
case *metav1.PartialObjectMetadataList:
|
||||||
return w.metadataWatch(ctx, l, opts...)
|
return w.metadataWatch(ctx, l, opts...)
|
||||||
@ -81,25 +75,23 @@ func (w *watchingClient) metadataWatch(ctx context.Context, obj *metav1.PartialO
|
|||||||
return resInt.Watch(ctx, *listOpts.AsListOptions())
|
return resInt.Watch(ctx, *listOpts.AsListOptions())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *watchingClient) unstructuredWatch(ctx context.Context, obj *unstructured.UnstructuredList, opts ...ListOption) (watch.Interface, error) {
|
func (w *watchingClient) unstructuredWatch(ctx context.Context, obj runtime.Unstructured, opts ...ListOption) (watch.Interface, error) {
|
||||||
gvk := obj.GroupVersionKind()
|
r, err := w.client.unstructuredClient.resources.getResource(obj)
|
||||||
gvk.Kind = strings.TrimSuffix(gvk.Kind, "List")
|
|
||||||
|
|
||||||
r, err := w.client.unstructuredClient.cache.getResource(obj)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
listOpts := w.listOpts(opts...)
|
listOpts := w.listOpts(opts...)
|
||||||
|
|
||||||
if listOpts.Namespace != "" && r.isNamespaced() {
|
return r.Get().
|
||||||
return w.dynamic.Resource(r.mapping.Resource).Namespace(listOpts.Namespace).Watch(ctx, *listOpts.AsListOptions())
|
NamespaceIfScoped(listOpts.Namespace, r.isNamespaced()).
|
||||||
}
|
Resource(r.resource()).
|
||||||
return w.dynamic.Resource(r.mapping.Resource).Watch(ctx, *listOpts.AsListOptions())
|
VersionedParams(listOpts.AsListOptions(), w.client.unstructuredClient.paramCodec).
|
||||||
|
Watch(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *watchingClient) typedWatch(ctx context.Context, obj ObjectList, opts ...ListOption) (watch.Interface, error) {
|
func (w *watchingClient) typedWatch(ctx context.Context, obj ObjectList, opts ...ListOption) (watch.Interface, error) {
|
||||||
r, err := w.client.typedClient.cache.getResource(obj)
|
r, err := w.client.typedClient.resources.getResource(obj)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
187
vendor/sigs.k8s.io/controller-runtime/pkg/cluster/cluster.go
generated
vendored
187
vendor/sigs.k8s.io/controller-runtime/pkg/cluster/cluster.go
generated
vendored
@ -19,6 +19,7 @@ package cluster
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
|
"net/http"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/go-logr/logr"
|
"github.com/go-logr/logr"
|
||||||
@ -27,6 +28,7 @@ import (
|
|||||||
"k8s.io/client-go/kubernetes/scheme"
|
"k8s.io/client-go/kubernetes/scheme"
|
||||||
"k8s.io/client-go/rest"
|
"k8s.io/client-go/rest"
|
||||||
"k8s.io/client-go/tools/record"
|
"k8s.io/client-go/tools/record"
|
||||||
|
"k8s.io/utils/pointer"
|
||||||
"sigs.k8s.io/controller-runtime/pkg/client/apiutil"
|
"sigs.k8s.io/controller-runtime/pkg/client/apiutil"
|
||||||
logf "sigs.k8s.io/controller-runtime/pkg/internal/log"
|
logf "sigs.k8s.io/controller-runtime/pkg/internal/log"
|
||||||
|
|
||||||
@ -37,14 +39,15 @@ import (
|
|||||||
|
|
||||||
// Cluster provides various methods to interact with a cluster.
|
// Cluster provides various methods to interact with a cluster.
|
||||||
type Cluster interface {
|
type Cluster interface {
|
||||||
// SetFields will set any dependencies on an object for which the object has implemented the inject
|
// GetHTTPClient returns an HTTP client that can be used to talk to the apiserver
|
||||||
// interface - e.g. inject.Client.
|
GetHTTPClient() *http.Client
|
||||||
// Deprecated: use the equivalent Options field to set a field. This method will be removed in v0.10.
|
|
||||||
SetFields(interface{}) error
|
|
||||||
|
|
||||||
// GetConfig returns an initialized Config
|
// GetConfig returns an initialized Config
|
||||||
GetConfig() *rest.Config
|
GetConfig() *rest.Config
|
||||||
|
|
||||||
|
// GetCache returns a cache.Cache
|
||||||
|
GetCache() cache.Cache
|
||||||
|
|
||||||
// GetScheme returns an initialized Scheme
|
// GetScheme returns an initialized Scheme
|
||||||
GetScheme() *runtime.Scheme
|
GetScheme() *runtime.Scheme
|
||||||
|
|
||||||
@ -57,9 +60,6 @@ type Cluster interface {
|
|||||||
// GetFieldIndexer returns a client.FieldIndexer configured with the client
|
// GetFieldIndexer returns a client.FieldIndexer configured with the client
|
||||||
GetFieldIndexer() client.FieldIndexer
|
GetFieldIndexer() client.FieldIndexer
|
||||||
|
|
||||||
// GetCache returns a cache.Cache
|
|
||||||
GetCache() cache.Cache
|
|
||||||
|
|
||||||
// GetEventRecorderFor returns a new EventRecorder for the provided name
|
// GetEventRecorderFor returns a new EventRecorder for the provided name
|
||||||
GetEventRecorderFor(name string) record.EventRecorder
|
GetEventRecorderFor(name string) record.EventRecorder
|
||||||
|
|
||||||
@ -83,7 +83,7 @@ type Options struct {
|
|||||||
Scheme *runtime.Scheme
|
Scheme *runtime.Scheme
|
||||||
|
|
||||||
// MapperProvider provides the rest mapper used to map go types to Kubernetes APIs
|
// MapperProvider provides the rest mapper used to map go types to Kubernetes APIs
|
||||||
MapperProvider func(c *rest.Config) (meta.RESTMapper, error)
|
MapperProvider func(c *rest.Config, httpClient *http.Client) (meta.RESTMapper, error)
|
||||||
|
|
||||||
// Logger is the logger that should be used by this Cluster.
|
// Logger is the logger that should be used by this Cluster.
|
||||||
// If none is set, it defaults to log.Log global logger.
|
// If none is set, it defaults to log.Log global logger.
|
||||||
@ -103,24 +103,54 @@ type Options struct {
|
|||||||
// Note: If a namespace is specified, controllers can still Watch for a
|
// Note: If a namespace is specified, controllers can still Watch for a
|
||||||
// cluster-scoped resource (e.g Node). For namespaced resources the cache
|
// cluster-scoped resource (e.g Node). For namespaced resources the cache
|
||||||
// will only hold objects from the desired namespace.
|
// will only hold objects from the desired namespace.
|
||||||
|
//
|
||||||
|
// Deprecated: Use Cache.Namespaces instead.
|
||||||
Namespace string
|
Namespace string
|
||||||
|
|
||||||
|
// HTTPClient is the http client that will be used to create the default
|
||||||
|
// Cache and Client. If not set the rest.HTTPClientFor function will be used
|
||||||
|
// to create the http client.
|
||||||
|
HTTPClient *http.Client
|
||||||
|
|
||||||
|
// Cache is the cache.Options that will be used to create the default Cache.
|
||||||
|
// By default, the cache will watch and list requested objects in all namespaces.
|
||||||
|
Cache cache.Options
|
||||||
|
|
||||||
// NewCache is the function that will create the cache to be used
|
// NewCache is the function that will create the cache to be used
|
||||||
// by the manager. If not set this will use the default new cache function.
|
// by the manager. If not set this will use the default new cache function.
|
||||||
|
//
|
||||||
|
// When using a custom NewCache, the Cache options will be passed to the
|
||||||
|
// NewCache function.
|
||||||
|
//
|
||||||
|
// NOTE: LOW LEVEL PRIMITIVE!
|
||||||
|
// Only use a custom NewCache if you know what you are doing.
|
||||||
NewCache cache.NewCacheFunc
|
NewCache cache.NewCacheFunc
|
||||||
|
|
||||||
|
// Client is the client.Options that will be used to create the default Client.
|
||||||
|
// By default, the client will use the cache for reads and direct calls for writes.
|
||||||
|
Client client.Options
|
||||||
|
|
||||||
// NewClient is the func that creates the client to be used by the manager.
|
// NewClient is the func that creates the client to be used by the manager.
|
||||||
// If not set this will create the default DelegatingClient that will
|
// If not set this will create a Client backed by a Cache for read operations
|
||||||
// use the cache for reads and the client for writes.
|
// and a direct Client for write operations.
|
||||||
// NOTE: The default client will not cache Unstructured.
|
//
|
||||||
NewClient NewClientFunc
|
// When using a custom NewClient, the Client options will be passed to the
|
||||||
|
// NewClient function.
|
||||||
|
//
|
||||||
|
// NOTE: LOW LEVEL PRIMITIVE!
|
||||||
|
// Only use a custom NewClient if you know what you are doing.
|
||||||
|
NewClient client.NewClientFunc
|
||||||
|
|
||||||
// ClientDisableCacheFor tells the client that, if any cache is used, to bypass it
|
// ClientDisableCacheFor tells the client that, if any cache is used, to bypass it
|
||||||
// for the given objects.
|
// for the given objects.
|
||||||
|
//
|
||||||
|
// Deprecated: Use Client.Cache.DisableFor instead.
|
||||||
ClientDisableCacheFor []client.Object
|
ClientDisableCacheFor []client.Object
|
||||||
|
|
||||||
// DryRunClient specifies whether the client should be configured to enforce
|
// DryRunClient specifies whether the client should be configured to enforce
|
||||||
// dryRun mode.
|
// dryRun mode.
|
||||||
|
//
|
||||||
|
// Deprecated: Use Client.DryRun instead.
|
||||||
DryRunClient bool
|
DryRunClient bool
|
||||||
|
|
||||||
// EventBroadcaster records Events emitted by the manager and sends them to the Kubernetes API
|
// EventBroadcaster records Events emitted by the manager and sends them to the Kubernetes API
|
||||||
@ -137,7 +167,7 @@ type Options struct {
|
|||||||
makeBroadcaster intrec.EventBroadcasterProducer
|
makeBroadcaster intrec.EventBroadcasterProducer
|
||||||
|
|
||||||
// Dependency injection for testing
|
// Dependency injection for testing
|
||||||
newRecorderProvider func(config *rest.Config, scheme *runtime.Scheme, logger logr.Logger, makeBroadcaster intrec.EventBroadcasterProducer) (*intrec.Provider, error)
|
newRecorderProvider func(config *rest.Config, httpClient *http.Client, scheme *runtime.Scheme, logger logr.Logger, makeBroadcaster intrec.EventBroadcasterProducer) (*intrec.Provider, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Option can be used to manipulate Options.
|
// Option can be used to manipulate Options.
|
||||||
@ -153,52 +183,105 @@ func New(config *rest.Config, opts ...Option) (Cluster, error) {
|
|||||||
for _, opt := range opts {
|
for _, opt := range opts {
|
||||||
opt(&options)
|
opt(&options)
|
||||||
}
|
}
|
||||||
options = setOptionsDefaults(options)
|
options, err := setOptionsDefaults(options, config)
|
||||||
|
if err != nil {
|
||||||
|
options.Logger.Error(err, "Failed to set defaults")
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
// Create the mapper provider
|
// Create the mapper provider
|
||||||
mapper, err := options.MapperProvider(config)
|
mapper, err := options.MapperProvider(config, options.HTTPClient)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
options.Logger.Error(err, "Failed to get API Group-Resources")
|
options.Logger.Error(err, "Failed to get API Group-Resources")
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create the cache for the cached read client and registering informers
|
// Create the cache for the cached read client and registering informers
|
||||||
cache, err := options.NewCache(config, cache.Options{Scheme: options.Scheme, Mapper: mapper, Resync: options.SyncPeriod, Namespace: options.Namespace})
|
cacheOpts := options.Cache
|
||||||
|
{
|
||||||
|
if cacheOpts.Scheme == nil {
|
||||||
|
cacheOpts.Scheme = options.Scheme
|
||||||
|
}
|
||||||
|
if cacheOpts.Mapper == nil {
|
||||||
|
cacheOpts.Mapper = mapper
|
||||||
|
}
|
||||||
|
if cacheOpts.HTTPClient == nil {
|
||||||
|
cacheOpts.HTTPClient = options.HTTPClient
|
||||||
|
}
|
||||||
|
if cacheOpts.SyncPeriod == nil {
|
||||||
|
cacheOpts.SyncPeriod = options.SyncPeriod
|
||||||
|
}
|
||||||
|
if len(cacheOpts.Namespaces) == 0 && options.Namespace != "" {
|
||||||
|
cacheOpts.Namespaces = []string{options.Namespace}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cache, err := options.NewCache(config, cacheOpts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
clientOptions := client.Options{Scheme: options.Scheme, Mapper: mapper}
|
// Create the client, and default its options.
|
||||||
|
clientOpts := options.Client
|
||||||
|
{
|
||||||
|
if clientOpts.Scheme == nil {
|
||||||
|
clientOpts.Scheme = options.Scheme
|
||||||
|
}
|
||||||
|
if clientOpts.Mapper == nil {
|
||||||
|
clientOpts.Mapper = mapper
|
||||||
|
}
|
||||||
|
if clientOpts.HTTPClient == nil {
|
||||||
|
clientOpts.HTTPClient = options.HTTPClient
|
||||||
|
}
|
||||||
|
if clientOpts.Cache == nil {
|
||||||
|
clientOpts.Cache = &client.CacheOptions{
|
||||||
|
Unstructured: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if clientOpts.Cache.Reader == nil {
|
||||||
|
clientOpts.Cache.Reader = cache
|
||||||
|
}
|
||||||
|
|
||||||
apiReader, err := client.New(config, clientOptions)
|
// For backward compatibility, the ClientDisableCacheFor option should
|
||||||
|
// be appended to the DisableFor option in the client.
|
||||||
|
clientOpts.Cache.DisableFor = append(clientOpts.Cache.DisableFor, options.ClientDisableCacheFor...)
|
||||||
|
|
||||||
|
if clientOpts.DryRun == nil && options.DryRunClient {
|
||||||
|
// For backward compatibility, the DryRunClient (if set) option should override
|
||||||
|
// the DryRun option in the client (if unset).
|
||||||
|
clientOpts.DryRun = pointer.Bool(true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
clientWriter, err := options.NewClient(config, clientOpts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
writeObj, err := options.NewClient(cache, config, clientOptions, options.ClientDisableCacheFor...)
|
// Create the API Reader, a client with no cache.
|
||||||
|
clientReader, err := client.New(config, client.Options{
|
||||||
|
HTTPClient: options.HTTPClient,
|
||||||
|
Scheme: options.Scheme,
|
||||||
|
Mapper: mapper,
|
||||||
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if options.DryRunClient {
|
|
||||||
writeObj = client.NewDryRunClient(writeObj)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create the recorder provider to inject event recorders for the components.
|
// Create the recorder provider to inject event recorders for the components.
|
||||||
// TODO(directxman12): the log for the event provider should have a context (name, tags, etc) specific
|
// TODO(directxman12): the log for the event provider should have a context (name, tags, etc) specific
|
||||||
// to the particular controller that it's being injected into, rather than a generic one like is here.
|
// to the particular controller that it's being injected into, rather than a generic one like is here.
|
||||||
recorderProvider, err := options.newRecorderProvider(config, options.Scheme, options.Logger.WithName("events"), options.makeBroadcaster)
|
recorderProvider, err := options.newRecorderProvider(config, options.HTTPClient, options.Scheme, options.Logger.WithName("events"), options.makeBroadcaster)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return &cluster{
|
return &cluster{
|
||||||
config: config,
|
config: config,
|
||||||
|
httpClient: options.HTTPClient,
|
||||||
scheme: options.Scheme,
|
scheme: options.Scheme,
|
||||||
cache: cache,
|
cache: cache,
|
||||||
fieldIndexes: cache,
|
fieldIndexes: cache,
|
||||||
client: writeObj,
|
client: clientWriter,
|
||||||
apiReader: apiReader,
|
apiReader: clientReader,
|
||||||
recorderProvider: recorderProvider,
|
recorderProvider: recorderProvider,
|
||||||
mapper: mapper,
|
mapper: mapper,
|
||||||
logger: options.Logger,
|
logger: options.Logger,
|
||||||
@ -206,21 +289,27 @@ func New(config *rest.Config, opts ...Option) (Cluster, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// setOptionsDefaults set default values for Options fields.
|
// setOptionsDefaults set default values for Options fields.
|
||||||
func setOptionsDefaults(options Options) Options {
|
func setOptionsDefaults(options Options, config *rest.Config) (Options, error) {
|
||||||
|
if options.HTTPClient == nil {
|
||||||
|
var err error
|
||||||
|
options.HTTPClient, err = rest.HTTPClientFor(config)
|
||||||
|
if err != nil {
|
||||||
|
return options, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Use the Kubernetes client-go scheme if none is specified
|
// Use the Kubernetes client-go scheme if none is specified
|
||||||
if options.Scheme == nil {
|
if options.Scheme == nil {
|
||||||
options.Scheme = scheme.Scheme
|
options.Scheme = scheme.Scheme
|
||||||
}
|
}
|
||||||
|
|
||||||
if options.MapperProvider == nil {
|
if options.MapperProvider == nil {
|
||||||
options.MapperProvider = func(c *rest.Config) (meta.RESTMapper, error) {
|
options.MapperProvider = apiutil.NewDynamicRESTMapper
|
||||||
return apiutil.NewDynamicRESTMapper(c)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Allow users to define how to create a new client
|
// Allow users to define how to create a new client
|
||||||
if options.NewClient == nil {
|
if options.NewClient == nil {
|
||||||
options.NewClient = DefaultNewClient
|
options.NewClient = client.New
|
||||||
}
|
}
|
||||||
|
|
||||||
// Allow newCache to be mocked
|
// Allow newCache to be mocked
|
||||||
@ -250,39 +339,5 @@ func setOptionsDefaults(options Options) Options {
|
|||||||
options.Logger = logf.RuntimeLog.WithName("cluster")
|
options.Logger = logf.RuntimeLog.WithName("cluster")
|
||||||
}
|
}
|
||||||
|
|
||||||
return options
|
return options, nil
|
||||||
}
|
|
||||||
|
|
||||||
// NewClientFunc allows a user to define how to create a client.
|
|
||||||
type NewClientFunc func(cache cache.Cache, config *rest.Config, options client.Options, uncachedObjects ...client.Object) (client.Client, error)
|
|
||||||
|
|
||||||
// ClientOptions are the optional arguments for tuning the caching client.
|
|
||||||
type ClientOptions struct {
|
|
||||||
UncachedObjects []client.Object
|
|
||||||
CacheUnstructured bool
|
|
||||||
}
|
|
||||||
|
|
||||||
// DefaultNewClient creates the default caching client, that will never cache Unstructured.
|
|
||||||
func DefaultNewClient(cache cache.Cache, config *rest.Config, options client.Options, uncachedObjects ...client.Object) (client.Client, error) {
|
|
||||||
return ClientBuilderWithOptions(ClientOptions{})(cache, config, options, uncachedObjects...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ClientBuilderWithOptions returns a Client constructor that will build a client
|
|
||||||
// honoring the options argument
|
|
||||||
func ClientBuilderWithOptions(options ClientOptions) NewClientFunc {
|
|
||||||
return func(cache cache.Cache, config *rest.Config, clientOpts client.Options, uncachedObjects ...client.Object) (client.Client, error) {
|
|
||||||
options.UncachedObjects = append(options.UncachedObjects, uncachedObjects...)
|
|
||||||
|
|
||||||
c, err := client.New(config, clientOpts)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return client.NewDelegatingClient(client.NewDelegatingClientInput{
|
|
||||||
CacheReader: cache,
|
|
||||||
Client: c,
|
|
||||||
UncachedObjects: options.UncachedObjects,
|
|
||||||
CacheUnstructured: options.CacheUnstructured,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
41
vendor/sigs.k8s.io/controller-runtime/pkg/cluster/internal.go
generated
vendored
41
vendor/sigs.k8s.io/controller-runtime/pkg/cluster/internal.go
generated
vendored
@ -18,6 +18,7 @@ package cluster
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
"github.com/go-logr/logr"
|
"github.com/go-logr/logr"
|
||||||
"k8s.io/apimachinery/pkg/api/meta"
|
"k8s.io/apimachinery/pkg/api/meta"
|
||||||
@ -28,22 +29,16 @@ import (
|
|||||||
"sigs.k8s.io/controller-runtime/pkg/cache"
|
"sigs.k8s.io/controller-runtime/pkg/cache"
|
||||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||||
intrec "sigs.k8s.io/controller-runtime/pkg/internal/recorder"
|
intrec "sigs.k8s.io/controller-runtime/pkg/internal/recorder"
|
||||||
"sigs.k8s.io/controller-runtime/pkg/runtime/inject"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type cluster struct {
|
type cluster struct {
|
||||||
// config is the rest.config used to talk to the apiserver. Required.
|
// config is the rest.config used to talk to the apiserver. Required.
|
||||||
config *rest.Config
|
config *rest.Config
|
||||||
|
|
||||||
// scheme is the scheme injected into Controllers, EventHandlers, Sources and Predicates. Defaults
|
httpClient *http.Client
|
||||||
// to scheme.scheme.
|
scheme *runtime.Scheme
|
||||||
scheme *runtime.Scheme
|
cache cache.Cache
|
||||||
|
client client.Client
|
||||||
cache cache.Cache
|
|
||||||
|
|
||||||
// TODO(directxman12): Provide an escape hatch to get individual indexers
|
|
||||||
// client is the client injected into Controllers (and EventHandlers, Sources and Predicates).
|
|
||||||
client client.Client
|
|
||||||
|
|
||||||
// apiReader is the reader that will make requests to the api server and not the cache.
|
// apiReader is the reader that will make requests to the api server and not the cache.
|
||||||
apiReader client.Reader
|
apiReader client.Reader
|
||||||
@ -64,32 +59,14 @@ type cluster struct {
|
|||||||
logger logr.Logger
|
logger logr.Logger
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *cluster) SetFields(i interface{}) error {
|
|
||||||
if _, err := inject.ConfigInto(c.config, i); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if _, err := inject.ClientInto(c.client, i); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if _, err := inject.APIReaderInto(c.apiReader, i); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if _, err := inject.SchemeInto(c.scheme, i); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if _, err := inject.CacheInto(c.cache, i); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if _, err := inject.MapperInto(c.mapper, i); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *cluster) GetConfig() *rest.Config {
|
func (c *cluster) GetConfig() *rest.Config {
|
||||||
return c.config
|
return c.config
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *cluster) GetHTTPClient() *http.Client {
|
||||||
|
return c.httpClient
|
||||||
|
}
|
||||||
|
|
||||||
func (c *cluster) GetClient() client.Client {
|
func (c *cluster) GetClient() client.Client {
|
||||||
return c.client
|
return c.client
|
||||||
}
|
}
|
||||||
|
12
vendor/sigs.k8s.io/controller-runtime/pkg/config/config.go
generated
vendored
12
vendor/sigs.k8s.io/controller-runtime/pkg/config/config.go
generated
vendored
@ -29,6 +29,8 @@ import (
|
|||||||
|
|
||||||
// ControllerManagerConfiguration defines the functions necessary to parse a config file
|
// ControllerManagerConfiguration defines the functions necessary to parse a config file
|
||||||
// and to configure the Options struct for the ctrl.Manager.
|
// 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 {
|
type ControllerManagerConfiguration interface {
|
||||||
runtime.Object
|
runtime.Object
|
||||||
|
|
||||||
@ -38,6 +40,8 @@ type ControllerManagerConfiguration interface {
|
|||||||
|
|
||||||
// DeferredFileLoader is used to configure the decoder for loading controller
|
// DeferredFileLoader is used to configure the decoder for loading controller
|
||||||
// runtime component config types.
|
// 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 {
|
type DeferredFileLoader struct {
|
||||||
ControllerManagerConfiguration
|
ControllerManagerConfiguration
|
||||||
path string
|
path string
|
||||||
@ -52,6 +56,8 @@ type DeferredFileLoader struct {
|
|||||||
// Defaults:
|
// Defaults:
|
||||||
// * Path: "./config.yaml"
|
// * Path: "./config.yaml"
|
||||||
// * Kind: GenericControllerManagerConfiguration
|
// * 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 {
|
func File() *DeferredFileLoader {
|
||||||
scheme := runtime.NewScheme()
|
scheme := runtime.NewScheme()
|
||||||
utilruntime.Must(v1alpha1.AddToScheme(scheme))
|
utilruntime.Must(v1alpha1.AddToScheme(scheme))
|
||||||
@ -83,12 +89,6 @@ func (d *DeferredFileLoader) OfKind(obj ControllerManagerConfiguration) *Deferre
|
|||||||
return d
|
return d
|
||||||
}
|
}
|
||||||
|
|
||||||
// InjectScheme will configure the scheme to be used for decoding the file.
|
|
||||||
func (d *DeferredFileLoader) InjectScheme(scheme *runtime.Scheme) error {
|
|
||||||
d.scheme = scheme
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// loadFile is used from the mutex.Once to load the file.
|
// loadFile is used from the mutex.Once to load the file.
|
||||||
func (d *DeferredFileLoader) loadFile() {
|
func (d *DeferredFileLoader) loadFile() {
|
||||||
if d.scheme == nil {
|
if d.scheme == nil {
|
||||||
|
49
vendor/sigs.k8s.io/controller-runtime/pkg/config/controller.go
generated
vendored
Normal file
49
vendor/sigs.k8s.io/controller-runtime/pkg/config/controller.go
generated
vendored
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2023 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 "time"
|
||||||
|
|
||||||
|
// Controller contains configuration options for a controller.
|
||||||
|
type Controller 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`.
|
||||||
|
GroupKindConcurrency map[string]int
|
||||||
|
|
||||||
|
// MaxConcurrentReconciles is the maximum number of concurrent Reconciles which can be run. Defaults to 1.
|
||||||
|
MaxConcurrentReconciles int
|
||||||
|
|
||||||
|
// CacheSyncTimeout refers to the time limit set to wait for syncing caches.
|
||||||
|
// Defaults to 2 minutes if not set.
|
||||||
|
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.
|
||||||
|
RecoverPanic *bool
|
||||||
|
|
||||||
|
// NeedLeaderElection indicates whether the controller needs to use leader election.
|
||||||
|
// Defaults to true, which means the controller will use leader election.
|
||||||
|
NeedLeaderElection *bool
|
||||||
|
}
|
10
vendor/sigs.k8s.io/controller-runtime/pkg/config/doc.go
generated
vendored
10
vendor/sigs.k8s.io/controller-runtime/pkg/config/doc.go
generated
vendored
@ -14,12 +14,6 @@ See the License for the specific language governing permissions and
|
|||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// Package config contains functionality for interacting with ComponentConfig
|
// Package config contains functionality for interacting with
|
||||||
// files
|
// configuration for controller-runtime components.
|
||||||
//
|
|
||||||
// # DeferredFileLoader
|
|
||||||
//
|
|
||||||
// This uses a deferred file decoding allowing you to chain your configuration
|
|
||||||
// setup. You can pass this into manager.Options#File and it will load your
|
|
||||||
// config.
|
|
||||||
package config
|
package config
|
||||||
|
2
vendor/sigs.k8s.io/controller-runtime/pkg/config/v1alpha1/doc.go
generated
vendored
2
vendor/sigs.k8s.io/controller-runtime/pkg/config/v1alpha1/doc.go
generated
vendored
@ -17,4 +17,6 @@ limitations under the License.
|
|||||||
// Package v1alpha1 provides the ControllerManagerConfiguration used for
|
// Package v1alpha1 provides the ControllerManagerConfiguration used for
|
||||||
// configuring ctrl.Manager
|
// configuring ctrl.Manager
|
||||||
// +kubebuilder:object:generate=true
|
// +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
|
package v1alpha1
|
||||||
|
6
vendor/sigs.k8s.io/controller-runtime/pkg/config/v1alpha1/register.go
generated
vendored
6
vendor/sigs.k8s.io/controller-runtime/pkg/config/v1alpha1/register.go
generated
vendored
@ -23,12 +23,18 @@ import (
|
|||||||
|
|
||||||
var (
|
var (
|
||||||
// GroupVersion is group version used to register these objects.
|
// 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"}
|
GroupVersion = schema.GroupVersion{Group: "controller-runtime.sigs.k8s.io", Version: "v1alpha1"}
|
||||||
|
|
||||||
// SchemeBuilder is used to add go types to the GroupVersionKind scheme.
|
// 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}
|
SchemeBuilder = &scheme.Builder{GroupVersion: GroupVersion}
|
||||||
|
|
||||||
// AddToScheme adds the types in this group-version to the given scheme.
|
// 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
|
AddToScheme = SchemeBuilder.AddToScheme
|
||||||
)
|
)
|
||||||
|
|
||||||
|
19
vendor/sigs.k8s.io/controller-runtime/pkg/config/v1alpha1/types.go
generated
vendored
19
vendor/sigs.k8s.io/controller-runtime/pkg/config/v1alpha1/types.go
generated
vendored
@ -25,6 +25,8 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// ControllerManagerConfigurationSpec defines the desired state of GenericControllerManagerConfiguration.
|
// 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 {
|
type ControllerManagerConfigurationSpec struct {
|
||||||
// SyncPeriod determines the minimum frequency at which watched resources are
|
// SyncPeriod determines the minimum frequency at which watched resources are
|
||||||
// reconciled. A lower period will correct entropy more quickly, but reduce
|
// reconciled. A lower period will correct entropy more quickly, but reduce
|
||||||
@ -60,7 +62,7 @@ type ControllerManagerConfigurationSpec struct {
|
|||||||
// +optional
|
// +optional
|
||||||
Controller *ControllerConfigurationSpec `json:"controller,omitempty"`
|
Controller *ControllerConfigurationSpec `json:"controller,omitempty"`
|
||||||
|
|
||||||
// Metrics contains thw controller metrics configuration
|
// Metrics contains the controller metrics configuration
|
||||||
// +optional
|
// +optional
|
||||||
Metrics ControllerMetrics `json:"metrics,omitempty"`
|
Metrics ControllerMetrics `json:"metrics,omitempty"`
|
||||||
|
|
||||||
@ -75,6 +77,11 @@ type ControllerManagerConfigurationSpec struct {
|
|||||||
|
|
||||||
// ControllerConfigurationSpec defines the global configuration for
|
// ControllerConfigurationSpec defines the global configuration for
|
||||||
// controllers registered with the manager.
|
// 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 {
|
type ControllerConfigurationSpec struct {
|
||||||
// GroupKindConcurrency is a map from a Kind to the number of concurrent reconciliation
|
// GroupKindConcurrency is a map from a Kind to the number of concurrent reconciliation
|
||||||
// allowed for that controller.
|
// allowed for that controller.
|
||||||
@ -101,6 +108,8 @@ type ControllerConfigurationSpec struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ControllerMetrics defines the metrics configs.
|
// 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 {
|
type ControllerMetrics struct {
|
||||||
// BindAddress is the TCP address that the controller should bind to
|
// BindAddress is the TCP address that the controller should bind to
|
||||||
// for serving prometheus metrics.
|
// for serving prometheus metrics.
|
||||||
@ -110,6 +119,8 @@ type ControllerMetrics struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ControllerHealth defines the health configs.
|
// 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 {
|
type ControllerHealth struct {
|
||||||
// HealthProbeBindAddress is the TCP address that the controller should bind to
|
// HealthProbeBindAddress is the TCP address that the controller should bind to
|
||||||
// for serving health probes
|
// for serving health probes
|
||||||
@ -127,6 +138,8 @@ type ControllerHealth struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ControllerWebhook defines the webhook server for the controller.
|
// 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 {
|
type ControllerWebhook struct {
|
||||||
// Port is the port that the webhook server serves at.
|
// Port is the port that the webhook server serves at.
|
||||||
// It is used to set webhook.Server.Port.
|
// It is used to set webhook.Server.Port.
|
||||||
@ -149,6 +162,8 @@ type ControllerWebhook struct {
|
|||||||
// +kubebuilder:object:root=true
|
// +kubebuilder:object:root=true
|
||||||
|
|
||||||
// ControllerManagerConfiguration is the Schema for the GenericControllerManagerConfigurations API.
|
// 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 {
|
type ControllerManagerConfiguration struct {
|
||||||
metav1.TypeMeta `json:",inline"`
|
metav1.TypeMeta `json:",inline"`
|
||||||
|
|
||||||
@ -157,6 +172,8 @@ type ControllerManagerConfiguration struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Complete returns the configuration for controller-runtime.
|
// 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) {
|
func (c *ControllerManagerConfigurationSpec) Complete() (ControllerManagerConfigurationSpec, error) {
|
||||||
return *c, nil
|
return *c, nil
|
||||||
}
|
}
|
||||||
|
43
vendor/sigs.k8s.io/controller-runtime/pkg/controller/controller.go
generated
vendored
43
vendor/sigs.k8s.io/controller-runtime/pkg/controller/controller.go
generated
vendored
@ -39,6 +39,18 @@ type Options struct {
|
|||||||
// MaxConcurrentReconciles is the maximum number of concurrent Reconciles which can be run. Defaults to 1.
|
// MaxConcurrentReconciles is the maximum number of concurrent Reconciles which can be run. Defaults to 1.
|
||||||
MaxConcurrentReconciles int
|
MaxConcurrentReconciles int
|
||||||
|
|
||||||
|
// CacheSyncTimeout refers to the time limit set to wait for syncing caches.
|
||||||
|
// Defaults to 2 minutes if not set.
|
||||||
|
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.
|
||||||
|
RecoverPanic *bool
|
||||||
|
|
||||||
|
// NeedLeaderElection indicates whether the controller needs to use leader election.
|
||||||
|
// Defaults to true, which means the controller will use leader election.
|
||||||
|
NeedLeaderElection *bool
|
||||||
|
|
||||||
// Reconciler reconciles an object
|
// Reconciler reconciles an object
|
||||||
Reconciler reconcile.Reconciler
|
Reconciler reconcile.Reconciler
|
||||||
|
|
||||||
@ -50,14 +62,6 @@ type Options struct {
|
|||||||
// LogConstructor is used to construct a logger used for this controller and passed
|
// LogConstructor is used to construct a logger used for this controller and passed
|
||||||
// to each reconciliation via the context field.
|
// to each reconciliation via the context field.
|
||||||
LogConstructor func(request *reconcile.Request) logr.Logger
|
LogConstructor func(request *reconcile.Request) logr.Logger
|
||||||
|
|
||||||
// CacheSyncTimeout refers to the time limit set to wait for syncing caches.
|
|
||||||
// Defaults to 2 minutes if not set.
|
|
||||||
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.
|
|
||||||
RecoverPanic *bool
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Controller implements a Kubernetes API. A Controller manages a work queue fed reconcile.Requests
|
// Controller implements a Kubernetes API. A Controller manages a work queue fed reconcile.Requests
|
||||||
@ -124,26 +128,33 @@ func NewUnmanaged(name string, mgr manager.Manager, options Options) (Controller
|
|||||||
}
|
}
|
||||||
|
|
||||||
if options.MaxConcurrentReconciles <= 0 {
|
if options.MaxConcurrentReconciles <= 0 {
|
||||||
options.MaxConcurrentReconciles = 1
|
if mgr.GetControllerOptions().MaxConcurrentReconciles > 0 {
|
||||||
|
options.MaxConcurrentReconciles = mgr.GetControllerOptions().MaxConcurrentReconciles
|
||||||
|
} else {
|
||||||
|
options.MaxConcurrentReconciles = 1
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if options.CacheSyncTimeout == 0 {
|
if options.CacheSyncTimeout == 0 {
|
||||||
options.CacheSyncTimeout = 2 * time.Minute
|
if mgr.GetControllerOptions().CacheSyncTimeout != 0 {
|
||||||
|
options.CacheSyncTimeout = mgr.GetControllerOptions().CacheSyncTimeout
|
||||||
|
} else {
|
||||||
|
options.CacheSyncTimeout = 2 * time.Minute
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if options.RateLimiter == nil {
|
if options.RateLimiter == nil {
|
||||||
options.RateLimiter = workqueue.DefaultControllerRateLimiter()
|
options.RateLimiter = workqueue.DefaultControllerRateLimiter()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Inject dependencies into Reconciler
|
|
||||||
if err := mgr.SetFields(options.Reconciler); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if options.RecoverPanic == nil {
|
if options.RecoverPanic == nil {
|
||||||
options.RecoverPanic = mgr.GetControllerOptions().RecoverPanic
|
options.RecoverPanic = mgr.GetControllerOptions().RecoverPanic
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if options.NeedLeaderElection == nil {
|
||||||
|
options.NeedLeaderElection = mgr.GetControllerOptions().NeedLeaderElection
|
||||||
|
}
|
||||||
|
|
||||||
// Create controller with dependencies set
|
// Create controller with dependencies set
|
||||||
return &controller.Controller{
|
return &controller.Controller{
|
||||||
Do: options.Reconciler,
|
Do: options.Reconciler,
|
||||||
@ -152,10 +163,10 @@ func NewUnmanaged(name string, mgr manager.Manager, options Options) (Controller
|
|||||||
},
|
},
|
||||||
MaxConcurrentReconciles: options.MaxConcurrentReconciles,
|
MaxConcurrentReconciles: options.MaxConcurrentReconciles,
|
||||||
CacheSyncTimeout: options.CacheSyncTimeout,
|
CacheSyncTimeout: options.CacheSyncTimeout,
|
||||||
SetFields: mgr.SetFields,
|
|
||||||
Name: name,
|
Name: name,
|
||||||
LogConstructor: options.LogConstructor,
|
LogConstructor: options.LogConstructor,
|
||||||
RecoverPanic: options.RecoverPanic,
|
RecoverPanic: options.RecoverPanic,
|
||||||
|
LeaderElected: options.NeedLeaderElection,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
10
vendor/sigs.k8s.io/controller-runtime/pkg/handler/enqueue.go
generated
vendored
10
vendor/sigs.k8s.io/controller-runtime/pkg/handler/enqueue.go
generated
vendored
@ -17,6 +17,8 @@ limitations under the License.
|
|||||||
package handler
|
package handler
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
"k8s.io/apimachinery/pkg/types"
|
"k8s.io/apimachinery/pkg/types"
|
||||||
"k8s.io/client-go/util/workqueue"
|
"k8s.io/client-go/util/workqueue"
|
||||||
"sigs.k8s.io/controller-runtime/pkg/event"
|
"sigs.k8s.io/controller-runtime/pkg/event"
|
||||||
@ -36,7 +38,7 @@ var _ EventHandler = &EnqueueRequestForObject{}
|
|||||||
type EnqueueRequestForObject struct{}
|
type EnqueueRequestForObject struct{}
|
||||||
|
|
||||||
// Create implements EventHandler.
|
// Create implements EventHandler.
|
||||||
func (e *EnqueueRequestForObject) Create(evt event.CreateEvent, q workqueue.RateLimitingInterface) {
|
func (e *EnqueueRequestForObject) Create(ctx context.Context, evt event.CreateEvent, q workqueue.RateLimitingInterface) {
|
||||||
if evt.Object == nil {
|
if evt.Object == nil {
|
||||||
enqueueLog.Error(nil, "CreateEvent received with no metadata", "event", evt)
|
enqueueLog.Error(nil, "CreateEvent received with no metadata", "event", evt)
|
||||||
return
|
return
|
||||||
@ -48,7 +50,7 @@ func (e *EnqueueRequestForObject) Create(evt event.CreateEvent, q workqueue.Rate
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Update implements EventHandler.
|
// Update implements EventHandler.
|
||||||
func (e *EnqueueRequestForObject) Update(evt event.UpdateEvent, q workqueue.RateLimitingInterface) {
|
func (e *EnqueueRequestForObject) Update(ctx context.Context, evt event.UpdateEvent, q workqueue.RateLimitingInterface) {
|
||||||
switch {
|
switch {
|
||||||
case evt.ObjectNew != nil:
|
case evt.ObjectNew != nil:
|
||||||
q.Add(reconcile.Request{NamespacedName: types.NamespacedName{
|
q.Add(reconcile.Request{NamespacedName: types.NamespacedName{
|
||||||
@ -66,7 +68,7 @@ func (e *EnqueueRequestForObject) Update(evt event.UpdateEvent, q workqueue.Rate
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Delete implements EventHandler.
|
// Delete implements EventHandler.
|
||||||
func (e *EnqueueRequestForObject) Delete(evt event.DeleteEvent, q workqueue.RateLimitingInterface) {
|
func (e *EnqueueRequestForObject) Delete(ctx context.Context, evt event.DeleteEvent, q workqueue.RateLimitingInterface) {
|
||||||
if evt.Object == nil {
|
if evt.Object == nil {
|
||||||
enqueueLog.Error(nil, "DeleteEvent received with no metadata", "event", evt)
|
enqueueLog.Error(nil, "DeleteEvent received with no metadata", "event", evt)
|
||||||
return
|
return
|
||||||
@ -78,7 +80,7 @@ func (e *EnqueueRequestForObject) Delete(evt event.DeleteEvent, q workqueue.Rate
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Generic implements EventHandler.
|
// Generic implements EventHandler.
|
||||||
func (e *EnqueueRequestForObject) Generic(evt event.GenericEvent, q workqueue.RateLimitingInterface) {
|
func (e *EnqueueRequestForObject) Generic(ctx context.Context, evt event.GenericEvent, q workqueue.RateLimitingInterface) {
|
||||||
if evt.Object == nil {
|
if evt.Object == nil {
|
||||||
enqueueLog.Error(nil, "GenericEvent received with no metadata", "event", evt)
|
enqueueLog.Error(nil, "GenericEvent received with no metadata", "event", evt)
|
||||||
return
|
return
|
||||||
|
37
vendor/sigs.k8s.io/controller-runtime/pkg/handler/enqueue_mapped.go
generated
vendored
37
vendor/sigs.k8s.io/controller-runtime/pkg/handler/enqueue_mapped.go
generated
vendored
@ -17,16 +17,17 @@ limitations under the License.
|
|||||||
package handler
|
package handler
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
"k8s.io/client-go/util/workqueue"
|
"k8s.io/client-go/util/workqueue"
|
||||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||||
"sigs.k8s.io/controller-runtime/pkg/event"
|
"sigs.k8s.io/controller-runtime/pkg/event"
|
||||||
"sigs.k8s.io/controller-runtime/pkg/reconcile"
|
"sigs.k8s.io/controller-runtime/pkg/reconcile"
|
||||||
"sigs.k8s.io/controller-runtime/pkg/runtime/inject"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// MapFunc is the signature required for enqueueing requests from a generic function.
|
// MapFunc is the signature required for enqueueing requests from a generic function.
|
||||||
// This type is usually used with EnqueueRequestsFromMapFunc when registering an event handler.
|
// This type is usually used with EnqueueRequestsFromMapFunc when registering an event handler.
|
||||||
type MapFunc func(client.Object) []reconcile.Request
|
type MapFunc func(context.Context, client.Object) []reconcile.Request
|
||||||
|
|
||||||
// EnqueueRequestsFromMapFunc enqueues Requests by running a transformation function that outputs a collection
|
// 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
|
// of reconcile.Requests on each Event. The reconcile.Requests may be for an arbitrary set of objects
|
||||||
@ -52,32 +53,32 @@ type enqueueRequestsFromMapFunc struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create implements EventHandler.
|
// Create implements EventHandler.
|
||||||
func (e *enqueueRequestsFromMapFunc) Create(evt event.CreateEvent, q workqueue.RateLimitingInterface) {
|
func (e *enqueueRequestsFromMapFunc) Create(ctx context.Context, evt event.CreateEvent, q workqueue.RateLimitingInterface) {
|
||||||
reqs := map[reconcile.Request]empty{}
|
reqs := map[reconcile.Request]empty{}
|
||||||
e.mapAndEnqueue(q, evt.Object, reqs)
|
e.mapAndEnqueue(ctx, q, evt.Object, reqs)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update implements EventHandler.
|
// Update implements EventHandler.
|
||||||
func (e *enqueueRequestsFromMapFunc) Update(evt event.UpdateEvent, q workqueue.RateLimitingInterface) {
|
func (e *enqueueRequestsFromMapFunc) Update(ctx context.Context, evt event.UpdateEvent, q workqueue.RateLimitingInterface) {
|
||||||
reqs := map[reconcile.Request]empty{}
|
reqs := map[reconcile.Request]empty{}
|
||||||
e.mapAndEnqueue(q, evt.ObjectOld, reqs)
|
e.mapAndEnqueue(ctx, q, evt.ObjectOld, reqs)
|
||||||
e.mapAndEnqueue(q, evt.ObjectNew, reqs)
|
e.mapAndEnqueue(ctx, q, evt.ObjectNew, reqs)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete implements EventHandler.
|
// Delete implements EventHandler.
|
||||||
func (e *enqueueRequestsFromMapFunc) Delete(evt event.DeleteEvent, q workqueue.RateLimitingInterface) {
|
func (e *enqueueRequestsFromMapFunc) Delete(ctx context.Context, evt event.DeleteEvent, q workqueue.RateLimitingInterface) {
|
||||||
reqs := map[reconcile.Request]empty{}
|
reqs := map[reconcile.Request]empty{}
|
||||||
e.mapAndEnqueue(q, evt.Object, reqs)
|
e.mapAndEnqueue(ctx, q, evt.Object, reqs)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generic implements EventHandler.
|
// Generic implements EventHandler.
|
||||||
func (e *enqueueRequestsFromMapFunc) Generic(evt event.GenericEvent, q workqueue.RateLimitingInterface) {
|
func (e *enqueueRequestsFromMapFunc) Generic(ctx context.Context, evt event.GenericEvent, q workqueue.RateLimitingInterface) {
|
||||||
reqs := map[reconcile.Request]empty{}
|
reqs := map[reconcile.Request]empty{}
|
||||||
e.mapAndEnqueue(q, evt.Object, reqs)
|
e.mapAndEnqueue(ctx, q, evt.Object, reqs)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *enqueueRequestsFromMapFunc) mapAndEnqueue(q workqueue.RateLimitingInterface, object client.Object, reqs map[reconcile.Request]empty) {
|
func (e *enqueueRequestsFromMapFunc) mapAndEnqueue(ctx context.Context, q workqueue.RateLimitingInterface, object client.Object, reqs map[reconcile.Request]empty) {
|
||||||
for _, req := range e.toRequests(object) {
|
for _, req := range e.toRequests(ctx, object) {
|
||||||
_, ok := reqs[req]
|
_, ok := reqs[req]
|
||||||
if !ok {
|
if !ok {
|
||||||
q.Add(req)
|
q.Add(req)
|
||||||
@ -85,13 +86,3 @@ func (e *enqueueRequestsFromMapFunc) mapAndEnqueue(q workqueue.RateLimitingInter
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// EnqueueRequestsFromMapFunc can inject fields into the mapper.
|
|
||||||
|
|
||||||
// InjectFunc implements inject.Injector.
|
|
||||||
func (e *enqueueRequestsFromMapFunc) InjectFunc(f inject.Func) error {
|
|
||||||
if f == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return f(e.toRequests)
|
|
||||||
}
|
|
||||||
|
86
vendor/sigs.k8s.io/controller-runtime/pkg/handler/enqueue_owner.go
generated
vendored
86
vendor/sigs.k8s.io/controller-runtime/pkg/handler/enqueue_owner.go
generated
vendored
@ -17,6 +17,7 @@ limitations under the License.
|
|||||||
package handler
|
package handler
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"k8s.io/apimachinery/pkg/api/meta"
|
"k8s.io/apimachinery/pkg/api/meta"
|
||||||
@ -25,15 +26,18 @@ import (
|
|||||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||||
"k8s.io/apimachinery/pkg/types"
|
"k8s.io/apimachinery/pkg/types"
|
||||||
"k8s.io/client-go/util/workqueue"
|
"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/event"
|
||||||
logf "sigs.k8s.io/controller-runtime/pkg/internal/log"
|
logf "sigs.k8s.io/controller-runtime/pkg/internal/log"
|
||||||
"sigs.k8s.io/controller-runtime/pkg/reconcile"
|
"sigs.k8s.io/controller-runtime/pkg/reconcile"
|
||||||
"sigs.k8s.io/controller-runtime/pkg/runtime/inject"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var _ EventHandler = &EnqueueRequestForOwner{}
|
var _ EventHandler = &enqueueRequestForOwner{}
|
||||||
|
|
||||||
var log = logf.RuntimeLog.WithName("eventhandler").WithName("EnqueueRequestForOwner")
|
var log = logf.RuntimeLog.WithName("eventhandler").WithName("enqueueRequestForOwner")
|
||||||
|
|
||||||
|
// OwnerOption modifies an EnqueueRequestForOwner EventHandler.
|
||||||
|
type OwnerOption func(e *enqueueRequestForOwner)
|
||||||
|
|
||||||
// EnqueueRequestForOwner enqueues Requests for the Owners of an object. E.g. the object that created
|
// EnqueueRequestForOwner enqueues Requests for the Owners of an object. E.g. the object that created
|
||||||
// the object that was the source of the Event.
|
// the object that was the source of the Event.
|
||||||
@ -42,13 +46,34 @@ var log = logf.RuntimeLog.WithName("eventhandler").WithName("EnqueueRequestForOw
|
|||||||
//
|
//
|
||||||
// - a source.Kind Source with Type of Pod.
|
// - a source.Kind Source with Type of Pod.
|
||||||
//
|
//
|
||||||
// - a handler.EnqueueRequestForOwner EventHandler with an OwnerType of ReplicaSet and IsController set to true.
|
// - a handler.enqueueRequestForOwner EventHandler with an OwnerType of ReplicaSet and OnlyControllerOwner set to true.
|
||||||
type EnqueueRequestForOwner struct {
|
func EnqueueRequestForOwner(scheme *runtime.Scheme, mapper meta.RESTMapper, ownerType client.Object, opts ...OwnerOption) EventHandler {
|
||||||
// OwnerType is the type of the Owner object to look for in OwnerReferences. Only Group and Kind are compared.
|
e := &enqueueRequestForOwner{
|
||||||
OwnerType runtime.Object
|
ownerType: ownerType,
|
||||||
|
mapper: mapper,
|
||||||
|
}
|
||||||
|
if err := e.parseOwnerTypeGroupKind(scheme); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
for _, opt := range opts {
|
||||||
|
opt(e)
|
||||||
|
}
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
|
||||||
// IsController if set will only look at the first OwnerReference with Controller: true.
|
// OnlyControllerOwner if provided will only look at the first OwnerReference with Controller: true.
|
||||||
IsController bool
|
func OnlyControllerOwner() OwnerOption {
|
||||||
|
return func(e *enqueueRequestForOwner) {
|
||||||
|
e.isController = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type enqueueRequestForOwner struct {
|
||||||
|
// ownerType is the type of the Owner object to look for in OwnerReferences. Only Group and Kind are compared.
|
||||||
|
ownerType runtime.Object
|
||||||
|
|
||||||
|
// isController if set will only look at the first OwnerReference with Controller: true.
|
||||||
|
isController bool
|
||||||
|
|
||||||
// groupKind is the cached Group and Kind from OwnerType
|
// groupKind is the cached Group and Kind from OwnerType
|
||||||
groupKind schema.GroupKind
|
groupKind schema.GroupKind
|
||||||
@ -58,7 +83,7 @@ type EnqueueRequestForOwner struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create implements EventHandler.
|
// Create implements EventHandler.
|
||||||
func (e *EnqueueRequestForOwner) Create(evt event.CreateEvent, q workqueue.RateLimitingInterface) {
|
func (e *enqueueRequestForOwner) Create(ctx context.Context, evt event.CreateEvent, q workqueue.RateLimitingInterface) {
|
||||||
reqs := map[reconcile.Request]empty{}
|
reqs := map[reconcile.Request]empty{}
|
||||||
e.getOwnerReconcileRequest(evt.Object, reqs)
|
e.getOwnerReconcileRequest(evt.Object, reqs)
|
||||||
for req := range reqs {
|
for req := range reqs {
|
||||||
@ -67,7 +92,7 @@ func (e *EnqueueRequestForOwner) Create(evt event.CreateEvent, q workqueue.RateL
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Update implements EventHandler.
|
// Update implements EventHandler.
|
||||||
func (e *EnqueueRequestForOwner) Update(evt event.UpdateEvent, q workqueue.RateLimitingInterface) {
|
func (e *enqueueRequestForOwner) Update(ctx context.Context, evt event.UpdateEvent, q workqueue.RateLimitingInterface) {
|
||||||
reqs := map[reconcile.Request]empty{}
|
reqs := map[reconcile.Request]empty{}
|
||||||
e.getOwnerReconcileRequest(evt.ObjectOld, reqs)
|
e.getOwnerReconcileRequest(evt.ObjectOld, reqs)
|
||||||
e.getOwnerReconcileRequest(evt.ObjectNew, reqs)
|
e.getOwnerReconcileRequest(evt.ObjectNew, reqs)
|
||||||
@ -77,7 +102,7 @@ func (e *EnqueueRequestForOwner) Update(evt event.UpdateEvent, q workqueue.RateL
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Delete implements EventHandler.
|
// Delete implements EventHandler.
|
||||||
func (e *EnqueueRequestForOwner) Delete(evt event.DeleteEvent, q workqueue.RateLimitingInterface) {
|
func (e *enqueueRequestForOwner) Delete(ctx context.Context, evt event.DeleteEvent, q workqueue.RateLimitingInterface) {
|
||||||
reqs := map[reconcile.Request]empty{}
|
reqs := map[reconcile.Request]empty{}
|
||||||
e.getOwnerReconcileRequest(evt.Object, reqs)
|
e.getOwnerReconcileRequest(evt.Object, reqs)
|
||||||
for req := range reqs {
|
for req := range reqs {
|
||||||
@ -86,7 +111,7 @@ func (e *EnqueueRequestForOwner) Delete(evt event.DeleteEvent, q workqueue.RateL
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Generic implements EventHandler.
|
// Generic implements EventHandler.
|
||||||
func (e *EnqueueRequestForOwner) Generic(evt event.GenericEvent, q workqueue.RateLimitingInterface) {
|
func (e *enqueueRequestForOwner) Generic(ctx context.Context, evt event.GenericEvent, q workqueue.RateLimitingInterface) {
|
||||||
reqs := map[reconcile.Request]empty{}
|
reqs := map[reconcile.Request]empty{}
|
||||||
e.getOwnerReconcileRequest(evt.Object, reqs)
|
e.getOwnerReconcileRequest(evt.Object, reqs)
|
||||||
for req := range reqs {
|
for req := range reqs {
|
||||||
@ -96,17 +121,17 @@ func (e *EnqueueRequestForOwner) Generic(evt event.GenericEvent, q workqueue.Rat
|
|||||||
|
|
||||||
// parseOwnerTypeGroupKind parses the OwnerType into a Group and Kind and caches the result. Returns false
|
// 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.
|
// if the OwnerType could not be parsed using the scheme.
|
||||||
func (e *EnqueueRequestForOwner) parseOwnerTypeGroupKind(scheme *runtime.Scheme) error {
|
func (e *enqueueRequestForOwner) parseOwnerTypeGroupKind(scheme *runtime.Scheme) error {
|
||||||
// Get the kinds of the type
|
// Get the kinds of the type
|
||||||
kinds, _, err := scheme.ObjectKinds(e.OwnerType)
|
kinds, _, err := scheme.ObjectKinds(e.ownerType)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error(err, "Could not get ObjectKinds for OwnerType", "owner type", fmt.Sprintf("%T", e.OwnerType))
|
log.Error(err, "Could not get ObjectKinds for OwnerType", "owner type", fmt.Sprintf("%T", e.ownerType))
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
// Expect only 1 kind. If there is more than one kind this is probably an edge case such as ListOptions.
|
// Expect only 1 kind. If there is more than one kind this is probably an edge case such as ListOptions.
|
||||||
if len(kinds) != 1 {
|
if len(kinds) != 1 {
|
||||||
err := fmt.Errorf("expected exactly 1 kind for OwnerType %T, but found %s kinds", e.OwnerType, kinds)
|
err := fmt.Errorf("expected exactly 1 kind for OwnerType %T, but found %s kinds", e.ownerType, kinds)
|
||||||
log.Error(nil, "expected exactly 1 kind for OwnerType", "owner type", fmt.Sprintf("%T", e.OwnerType), "kinds", kinds)
|
log.Error(nil, "expected exactly 1 kind for OwnerType", "owner type", fmt.Sprintf("%T", e.ownerType), "kinds", kinds)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
// Cache the Group and Kind for the OwnerType
|
// Cache the Group and Kind for the OwnerType
|
||||||
@ -116,7 +141,7 @@ func (e *EnqueueRequestForOwner) parseOwnerTypeGroupKind(scheme *runtime.Scheme)
|
|||||||
|
|
||||||
// getOwnerReconcileRequest looks at object and builds a map of reconcile.Request to reconcile
|
// getOwnerReconcileRequest looks at object and builds a map of reconcile.Request to reconcile
|
||||||
// owners of object that match e.OwnerType.
|
// owners of object that match e.OwnerType.
|
||||||
func (e *EnqueueRequestForOwner) getOwnerReconcileRequest(object metav1.Object, result map[reconcile.Request]empty) {
|
func (e *enqueueRequestForOwner) getOwnerReconcileRequest(object metav1.Object, result map[reconcile.Request]empty) {
|
||||||
// Iterate through the OwnerReferences looking for a match on Group and Kind against what was requested
|
// Iterate through the OwnerReferences looking for a match on Group and Kind against what was requested
|
||||||
// by the user
|
// by the user
|
||||||
for _, ref := range e.getOwnersReferences(object) {
|
for _, ref := range e.getOwnersReferences(object) {
|
||||||
@ -138,7 +163,7 @@ func (e *EnqueueRequestForOwner) getOwnerReconcileRequest(object metav1.Object,
|
|||||||
Name: ref.Name,
|
Name: ref.Name,
|
||||||
}}
|
}}
|
||||||
|
|
||||||
// if owner is not namespaced then we should set the namespace to the empty
|
// if owner is not namespaced then we should not set the namespace
|
||||||
mapping, err := e.mapper.RESTMapping(e.groupKind, refGV.Version)
|
mapping, err := e.mapper.RESTMapping(e.groupKind, refGV.Version)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error(err, "Could not retrieve rest mapping", "kind", e.groupKind)
|
log.Error(err, "Could not retrieve rest mapping", "kind", e.groupKind)
|
||||||
@ -153,16 +178,16 @@ func (e *EnqueueRequestForOwner) getOwnerReconcileRequest(object metav1.Object,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// getOwnersReferences returns the OwnerReferences for an object as specified by the EnqueueRequestForOwner
|
// 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 true: only take the Controller OwnerReference (if found)
|
||||||
// - if IsController is false: take all OwnerReferences.
|
// - if IsController is false: take all OwnerReferences.
|
||||||
func (e *EnqueueRequestForOwner) getOwnersReferences(object metav1.Object) []metav1.OwnerReference {
|
func (e *enqueueRequestForOwner) getOwnersReferences(object metav1.Object) []metav1.OwnerReference {
|
||||||
if object == nil {
|
if object == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// If not filtered as Controller only, then use all the OwnerReferences
|
// If not filtered as Controller only, then use all the OwnerReferences
|
||||||
if !e.IsController {
|
if !e.isController {
|
||||||
return object.GetOwnerReferences()
|
return object.GetOwnerReferences()
|
||||||
}
|
}
|
||||||
// If filtered to a Controller, only take the Controller OwnerReference
|
// If filtered to a Controller, only take the Controller OwnerReference
|
||||||
@ -172,18 +197,3 @@ func (e *EnqueueRequestForOwner) getOwnersReferences(object metav1.Object) []met
|
|||||||
// No Controller OwnerReference found
|
// No Controller OwnerReference found
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ inject.Scheme = &EnqueueRequestForOwner{}
|
|
||||||
|
|
||||||
// InjectScheme is called by the Controller to provide a singleton scheme to the EnqueueRequestForOwner.
|
|
||||||
func (e *EnqueueRequestForOwner) InjectScheme(s *runtime.Scheme) error {
|
|
||||||
return e.parseOwnerTypeGroupKind(s)
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ inject.Mapper = &EnqueueRequestForOwner{}
|
|
||||||
|
|
||||||
// InjectMapper is called by the Controller to provide the rest mapper used by the manager.
|
|
||||||
func (e *EnqueueRequestForOwner) InjectMapper(m meta.RESTMapper) error {
|
|
||||||
e.mapper = m
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
34
vendor/sigs.k8s.io/controller-runtime/pkg/handler/eventhandler.go
generated
vendored
34
vendor/sigs.k8s.io/controller-runtime/pkg/handler/eventhandler.go
generated
vendored
@ -17,6 +17,8 @@ limitations under the License.
|
|||||||
package handler
|
package handler
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
"k8s.io/client-go/util/workqueue"
|
"k8s.io/client-go/util/workqueue"
|
||||||
"sigs.k8s.io/controller-runtime/pkg/event"
|
"sigs.k8s.io/controller-runtime/pkg/event"
|
||||||
)
|
)
|
||||||
@ -41,17 +43,17 @@ import (
|
|||||||
// Most users shouldn't need to implement their own EventHandler.
|
// Most users shouldn't need to implement their own EventHandler.
|
||||||
type EventHandler interface {
|
type EventHandler interface {
|
||||||
// Create is called in response to an create event - e.g. Pod Creation.
|
// Create is called in response to an create event - e.g. Pod Creation.
|
||||||
Create(event.CreateEvent, workqueue.RateLimitingInterface)
|
Create(context.Context, event.CreateEvent, workqueue.RateLimitingInterface)
|
||||||
|
|
||||||
// Update is called in response to an update event - e.g. Pod Updated.
|
// Update is called in response to an update event - e.g. Pod Updated.
|
||||||
Update(event.UpdateEvent, workqueue.RateLimitingInterface)
|
Update(context.Context, event.UpdateEvent, workqueue.RateLimitingInterface)
|
||||||
|
|
||||||
// Delete is called in response to a delete event - e.g. Pod Deleted.
|
// Delete is called in response to a delete event - e.g. Pod Deleted.
|
||||||
Delete(event.DeleteEvent, workqueue.RateLimitingInterface)
|
Delete(context.Context, event.DeleteEvent, workqueue.RateLimitingInterface)
|
||||||
|
|
||||||
// Generic is called in response to an event of an unknown type or a synthetic event triggered as a cron or
|
// 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.
|
// external trigger request - e.g. reconcile Autoscaling, or a Webhook.
|
||||||
Generic(event.GenericEvent, workqueue.RateLimitingInterface)
|
Generic(context.Context, event.GenericEvent, workqueue.RateLimitingInterface)
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ EventHandler = Funcs{}
|
var _ EventHandler = Funcs{}
|
||||||
@ -60,45 +62,45 @@ var _ EventHandler = Funcs{}
|
|||||||
type Funcs struct {
|
type Funcs struct {
|
||||||
// Create is called in response to an add event. Defaults to no-op.
|
// Create is called in response to an add event. Defaults to no-op.
|
||||||
// RateLimitingInterface is used to enqueue reconcile.Requests.
|
// RateLimitingInterface is used to enqueue reconcile.Requests.
|
||||||
CreateFunc func(event.CreateEvent, workqueue.RateLimitingInterface)
|
CreateFunc func(context.Context, event.CreateEvent, workqueue.RateLimitingInterface)
|
||||||
|
|
||||||
// Update is called in response to an update event. Defaults to no-op.
|
// Update is called in response to an update event. Defaults to no-op.
|
||||||
// RateLimitingInterface is used to enqueue reconcile.Requests.
|
// RateLimitingInterface is used to enqueue reconcile.Requests.
|
||||||
UpdateFunc func(event.UpdateEvent, workqueue.RateLimitingInterface)
|
UpdateFunc func(context.Context, event.UpdateEvent, workqueue.RateLimitingInterface)
|
||||||
|
|
||||||
// Delete is called in response to a delete event. Defaults to no-op.
|
// Delete is called in response to a delete event. Defaults to no-op.
|
||||||
// RateLimitingInterface is used to enqueue reconcile.Requests.
|
// RateLimitingInterface is used to enqueue reconcile.Requests.
|
||||||
DeleteFunc func(event.DeleteEvent, workqueue.RateLimitingInterface)
|
DeleteFunc func(context.Context, event.DeleteEvent, workqueue.RateLimitingInterface)
|
||||||
|
|
||||||
// GenericFunc is called in response to a generic event. Defaults to no-op.
|
// GenericFunc is called in response to a generic event. Defaults to no-op.
|
||||||
// RateLimitingInterface is used to enqueue reconcile.Requests.
|
// RateLimitingInterface is used to enqueue reconcile.Requests.
|
||||||
GenericFunc func(event.GenericEvent, workqueue.RateLimitingInterface)
|
GenericFunc func(context.Context, event.GenericEvent, workqueue.RateLimitingInterface)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create implements EventHandler.
|
// Create implements EventHandler.
|
||||||
func (h Funcs) Create(e event.CreateEvent, q workqueue.RateLimitingInterface) {
|
func (h Funcs) Create(ctx context.Context, e event.CreateEvent, q workqueue.RateLimitingInterface) {
|
||||||
if h.CreateFunc != nil {
|
if h.CreateFunc != nil {
|
||||||
h.CreateFunc(e, q)
|
h.CreateFunc(ctx, e, q)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete implements EventHandler.
|
// Delete implements EventHandler.
|
||||||
func (h Funcs) Delete(e event.DeleteEvent, q workqueue.RateLimitingInterface) {
|
func (h Funcs) Delete(ctx context.Context, e event.DeleteEvent, q workqueue.RateLimitingInterface) {
|
||||||
if h.DeleteFunc != nil {
|
if h.DeleteFunc != nil {
|
||||||
h.DeleteFunc(e, q)
|
h.DeleteFunc(ctx, e, q)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update implements EventHandler.
|
// Update implements EventHandler.
|
||||||
func (h Funcs) Update(e event.UpdateEvent, q workqueue.RateLimitingInterface) {
|
func (h Funcs) Update(ctx context.Context, e event.UpdateEvent, q workqueue.RateLimitingInterface) {
|
||||||
if h.UpdateFunc != nil {
|
if h.UpdateFunc != nil {
|
||||||
h.UpdateFunc(e, q)
|
h.UpdateFunc(ctx, e, q)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generic implements EventHandler.
|
// Generic implements EventHandler.
|
||||||
func (h Funcs) Generic(e event.GenericEvent, q workqueue.RateLimitingInterface) {
|
func (h Funcs) Generic(ctx context.Context, e event.GenericEvent, q workqueue.RateLimitingInterface) {
|
||||||
if h.GenericFunc != nil {
|
if h.GenericFunc != nil {
|
||||||
h.GenericFunc(e, q)
|
h.GenericFunc(ctx, e, q)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
43
vendor/sigs.k8s.io/controller-runtime/pkg/internal/controller/controller.go
generated
vendored
43
vendor/sigs.k8s.io/controller-runtime/pkg/internal/controller/controller.go
generated
vendored
@ -33,12 +33,9 @@ import (
|
|||||||
logf "sigs.k8s.io/controller-runtime/pkg/log"
|
logf "sigs.k8s.io/controller-runtime/pkg/log"
|
||||||
"sigs.k8s.io/controller-runtime/pkg/predicate"
|
"sigs.k8s.io/controller-runtime/pkg/predicate"
|
||||||
"sigs.k8s.io/controller-runtime/pkg/reconcile"
|
"sigs.k8s.io/controller-runtime/pkg/reconcile"
|
||||||
"sigs.k8s.io/controller-runtime/pkg/runtime/inject"
|
|
||||||
"sigs.k8s.io/controller-runtime/pkg/source"
|
"sigs.k8s.io/controller-runtime/pkg/source"
|
||||||
)
|
)
|
||||||
|
|
||||||
var _ inject.Injector = &Controller{}
|
|
||||||
|
|
||||||
// Controller implements controller.Controller.
|
// Controller implements controller.Controller.
|
||||||
type Controller struct {
|
type Controller struct {
|
||||||
// Name is used to uniquely identify a Controller in tracing, logging and monitoring. Name is required.
|
// Name is used to uniquely identify a Controller in tracing, logging and monitoring. Name is required.
|
||||||
@ -61,10 +58,6 @@ type Controller struct {
|
|||||||
// the Queue for processing
|
// the Queue for processing
|
||||||
Queue workqueue.RateLimitingInterface
|
Queue workqueue.RateLimitingInterface
|
||||||
|
|
||||||
// SetFields is used to inject dependencies into other objects such as Sources, EventHandlers and Predicates
|
|
||||||
// Deprecated: the caller should handle injected fields itself.
|
|
||||||
SetFields func(i interface{}) error
|
|
||||||
|
|
||||||
// mu is used to synchronize Controller setup
|
// mu is used to synchronize Controller setup
|
||||||
mu sync.Mutex
|
mu sync.Mutex
|
||||||
|
|
||||||
@ -93,6 +86,9 @@ type Controller struct {
|
|||||||
|
|
||||||
// RecoverPanic indicates whether the panic caused by reconcile should be recovered.
|
// RecoverPanic indicates whether the panic caused by reconcile should be recovered.
|
||||||
RecoverPanic *bool
|
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.
|
// watchDescription contains all the information necessary to start a watch.
|
||||||
@ -127,19 +123,6 @@ func (c *Controller) Watch(src source.Source, evthdler handler.EventHandler, prc
|
|||||||
c.mu.Lock()
|
c.mu.Lock()
|
||||||
defer c.mu.Unlock()
|
defer c.mu.Unlock()
|
||||||
|
|
||||||
// Inject Cache into arguments
|
|
||||||
if err := c.SetFields(src); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if err := c.SetFields(evthdler); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
for _, pr := range prct {
|
|
||||||
if err := c.SetFields(pr); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Controller hasn't started yet, store the watches locally and return.
|
// Controller hasn't started yet, store the watches locally and return.
|
||||||
//
|
//
|
||||||
// These watches are going to be held on the controller struct until the manager or user calls Start(...).
|
// These watches are going to be held on the controller struct until the manager or user calls Start(...).
|
||||||
@ -152,6 +135,14 @@ func (c *Controller) Watch(src source.Source, evthdler handler.EventHandler, prc
|
|||||||
return src.Start(c.ctx, evthdler, c.Queue, prct...)
|
return src.Start(c.ctx, evthdler, c.Queue, prct...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NeedLeaderElection implements the manager.LeaderElectionRunnable interface.
|
||||||
|
func (c *Controller) NeedLeaderElection() bool {
|
||||||
|
if c.LeaderElected == nil {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return *c.LeaderElected
|
||||||
|
}
|
||||||
|
|
||||||
// Start implements controller.Controller.
|
// Start implements controller.Controller.
|
||||||
func (c *Controller) Start(ctx context.Context) error {
|
func (c *Controller) Start(ctx context.Context) error {
|
||||||
// use an IIFE to get proper lock handling
|
// use an IIFE to get proper lock handling
|
||||||
@ -323,7 +314,11 @@ func (c *Controller) reconcileHandler(ctx context.Context, obj interface{}) {
|
|||||||
result, err := c.Reconcile(ctx, req)
|
result, err := c.Reconcile(ctx, req)
|
||||||
switch {
|
switch {
|
||||||
case err != nil:
|
case err != nil:
|
||||||
c.Queue.AddRateLimited(req)
|
if errors.Is(err, reconcile.TerminalError(nil)) {
|
||||||
|
ctrlmetrics.TerminalReconcileErrors.WithLabelValues(c.Name).Inc()
|
||||||
|
} else {
|
||||||
|
c.Queue.AddRateLimited(req)
|
||||||
|
}
|
||||||
ctrlmetrics.ReconcileErrors.WithLabelValues(c.Name).Inc()
|
ctrlmetrics.ReconcileErrors.WithLabelValues(c.Name).Inc()
|
||||||
ctrlmetrics.ReconcileTotal.WithLabelValues(c.Name, labelError).Inc()
|
ctrlmetrics.ReconcileTotal.WithLabelValues(c.Name, labelError).Inc()
|
||||||
log.Error(err, "Reconciler error")
|
log.Error(err, "Reconciler error")
|
||||||
@ -351,12 +346,6 @@ func (c *Controller) GetLogger() logr.Logger {
|
|||||||
return c.LogConstructor(nil)
|
return c.LogConstructor(nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
// InjectFunc implement SetFields.Injector.
|
|
||||||
func (c *Controller) InjectFunc(f inject.Func) error {
|
|
||||||
c.SetFields = f
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// updateMetrics updates prometheus metrics within the controller.
|
// updateMetrics updates prometheus metrics within the controller.
|
||||||
func (c *Controller) updateMetrics(reconcileTime time.Duration) {
|
func (c *Controller) updateMetrics(reconcileTime time.Duration) {
|
||||||
ctrlmetrics.ReconcileTime.WithLabelValues(c.Name).Observe(reconcileTime.Seconds())
|
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
@ -39,6 +39,13 @@ var (
|
|||||||
Help: "Total number of reconciliation errors per controller",
|
Help: "Total number of reconciliation errors per controller",
|
||||||
}, []string{"controller"})
|
}, []string{"controller"})
|
||||||
|
|
||||||
|
// TerminalReconcileErrors is a prometheus counter metrics which holds the total
|
||||||
|
// number of terminal errors from the Reconciler.
|
||||||
|
TerminalReconcileErrors = prometheus.NewCounterVec(prometheus.CounterOpts{
|
||||||
|
Name: "controller_runtime_terminal_reconcile_errors_total",
|
||||||
|
Help: "Total number of terminal reconciliation errors per controller",
|
||||||
|
}, []string{"controller"})
|
||||||
|
|
||||||
// ReconcileTime is a prometheus metric which keeps track of the duration
|
// ReconcileTime is a prometheus metric which keeps track of the duration
|
||||||
// of reconciliations.
|
// of reconciliations.
|
||||||
ReconcileTime = prometheus.NewHistogramVec(prometheus.HistogramOpts{
|
ReconcileTime = prometheus.NewHistogramVec(prometheus.HistogramOpts{
|
||||||
@ -67,6 +74,7 @@ func init() {
|
|||||||
metrics.Registry.MustRegister(
|
metrics.Registry.MustRegister(
|
||||||
ReconcileTotal,
|
ReconcileTotal,
|
||||||
ReconcileErrors,
|
ReconcileErrors,
|
||||||
|
TerminalReconcileErrors,
|
||||||
ReconcileTime,
|
ReconcileTime,
|
||||||
WorkerCount,
|
WorkerCount,
|
||||||
ActiveWorkers,
|
ActiveWorkers,
|
||||||
|
78
vendor/sigs.k8s.io/controller-runtime/pkg/internal/objectutil/objectutil.go
generated
vendored
78
vendor/sigs.k8s.io/controller-runtime/pkg/internal/objectutil/objectutil.go
generated
vendored
@ -1,78 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright 2018 The Kubernetes Authors.
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package objectutil
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
apimeta "k8s.io/apimachinery/pkg/api/meta"
|
|
||||||
"k8s.io/apimachinery/pkg/labels"
|
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
|
||||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
|
||||||
"sigs.k8s.io/controller-runtime/pkg/client/apiutil"
|
|
||||||
)
|
|
||||||
|
|
||||||
// FilterWithLabels returns a copy of the items in objs matching labelSel.
|
|
||||||
func FilterWithLabels(objs []runtime.Object, labelSel labels.Selector) ([]runtime.Object, error) {
|
|
||||||
outItems := make([]runtime.Object, 0, len(objs))
|
|
||||||
for _, obj := range objs {
|
|
||||||
meta, err := apimeta.Accessor(obj)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if labelSel != nil {
|
|
||||||
lbls := labels.Set(meta.GetLabels())
|
|
||||||
if !labelSel.Matches(lbls) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
outItems = append(outItems, obj.DeepCopyObject())
|
|
||||||
}
|
|
||||||
return outItems, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsAPINamespaced returns true if the object is namespace scoped.
|
|
||||||
// For unstructured objects the gvk is found from the object itself.
|
|
||||||
func IsAPINamespaced(obj runtime.Object, scheme *runtime.Scheme, restmapper apimeta.RESTMapper) (bool, error) {
|
|
||||||
gvk, err := apiutil.GVKForObject(obj, scheme)
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return IsAPINamespacedWithGVK(gvk, scheme, restmapper)
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsAPINamespacedWithGVK returns true if the object having the provided
|
|
||||||
// GVK is namespace scoped.
|
|
||||||
func IsAPINamespacedWithGVK(gk schema.GroupVersionKind, scheme *runtime.Scheme, restmapper apimeta.RESTMapper) (bool, error) {
|
|
||||||
restmapping, err := restmapper.RESTMapping(schema.GroupKind{Group: gk.Group, Kind: gk.Kind})
|
|
||||||
if err != nil {
|
|
||||||
return false, fmt.Errorf("failed to get restmapping: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
scope := restmapping.Scope.Name()
|
|
||||||
|
|
||||||
if scope == "" {
|
|
||||||
return false, errors.New("scope cannot be identified, empty scope returned")
|
|
||||||
}
|
|
||||||
|
|
||||||
if scope != apimeta.RESTScopeNameRoot {
|
|
||||||
return true, nil
|
|
||||||
}
|
|
||||||
return false, nil
|
|
||||||
}
|
|
9
vendor/sigs.k8s.io/controller-runtime/pkg/internal/recorder/recorder.go
generated
vendored
9
vendor/sigs.k8s.io/controller-runtime/pkg/internal/recorder/recorder.go
generated
vendored
@ -19,6 +19,7 @@ package recorder
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"net/http"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/go-logr/logr"
|
"github.com/go-logr/logr"
|
||||||
@ -110,8 +111,12 @@ func (p *Provider) getBroadcaster() record.EventBroadcaster {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NewProvider create a new Provider instance.
|
// NewProvider create a new Provider instance.
|
||||||
func NewProvider(config *rest.Config, scheme *runtime.Scheme, logger logr.Logger, makeBroadcaster EventBroadcasterProducer) (*Provider, error) {
|
func NewProvider(config *rest.Config, httpClient *http.Client, scheme *runtime.Scheme, logger logr.Logger, makeBroadcaster EventBroadcasterProducer) (*Provider, error) {
|
||||||
corev1Client, err := corev1client.NewForConfig(config)
|
if httpClient == nil {
|
||||||
|
panic("httpClient must not be nil")
|
||||||
|
}
|
||||||
|
|
||||||
|
corev1Client, err := corev1client.NewForConfigAndClient(config, httpClient)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to init client: %w", err)
|
return nil, fmt.Errorf("failed to init client: %w", err)
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,7 @@ limitations under the License.
|
|||||||
package internal
|
package internal
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"k8s.io/client-go/tools/cache"
|
"k8s.io/client-go/tools/cache"
|
||||||
@ -31,17 +32,39 @@ import (
|
|||||||
|
|
||||||
var log = logf.RuntimeLog.WithName("source").WithName("EventHandler")
|
var log = logf.RuntimeLog.WithName("source").WithName("EventHandler")
|
||||||
|
|
||||||
var _ cache.ResourceEventHandler = EventHandler{}
|
// NewEventHandler creates a new EventHandler.
|
||||||
|
func NewEventHandler(ctx context.Context, queue workqueue.RateLimitingInterface, handler handler.EventHandler, predicates []predicate.Predicate) *EventHandler {
|
||||||
|
return &EventHandler{
|
||||||
|
ctx: ctx,
|
||||||
|
handler: handler,
|
||||||
|
queue: queue,
|
||||||
|
predicates: predicates,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// EventHandler adapts a handler.EventHandler interface to a cache.ResourceEventHandler interface.
|
// EventHandler adapts a handler.EventHandler interface to a cache.ResourceEventHandler interface.
|
||||||
type EventHandler struct {
|
type EventHandler struct {
|
||||||
EventHandler handler.EventHandler
|
// ctx stores the context that created the event handler
|
||||||
Queue workqueue.RateLimitingInterface
|
// that is used to propagate cancellation signals to each handler function.
|
||||||
Predicates []predicate.Predicate
|
ctx context.Context
|
||||||
|
|
||||||
|
handler handler.EventHandler
|
||||||
|
queue workqueue.RateLimitingInterface
|
||||||
|
predicates []predicate.Predicate
|
||||||
|
}
|
||||||
|
|
||||||
|
// HandlerFuncs converts EventHandler to a ResourceEventHandlerFuncs
|
||||||
|
// TODO: switch to ResourceEventHandlerDetailedFuncs with client-go 1.27
|
||||||
|
func (e *EventHandler) HandlerFuncs() cache.ResourceEventHandlerFuncs {
|
||||||
|
return cache.ResourceEventHandlerFuncs{
|
||||||
|
AddFunc: e.OnAdd,
|
||||||
|
UpdateFunc: e.OnUpdate,
|
||||||
|
DeleteFunc: e.OnDelete,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// OnAdd creates CreateEvent and calls Create on EventHandler.
|
// OnAdd creates CreateEvent and calls Create on EventHandler.
|
||||||
func (e EventHandler) OnAdd(obj interface{}) {
|
func (e *EventHandler) OnAdd(obj interface{}) {
|
||||||
c := event.CreateEvent{}
|
c := event.CreateEvent{}
|
||||||
|
|
||||||
// Pull Object out of the object
|
// Pull Object out of the object
|
||||||
@ -53,18 +76,20 @@ func (e EventHandler) OnAdd(obj interface{}) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, p := range e.Predicates {
|
for _, p := range e.predicates {
|
||||||
if !p.Create(c) {
|
if !p.Create(c) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Invoke create handler
|
// Invoke create handler
|
||||||
e.EventHandler.Create(c, e.Queue)
|
ctx, cancel := context.WithCancel(e.ctx)
|
||||||
|
defer cancel()
|
||||||
|
e.handler.Create(ctx, c, e.queue)
|
||||||
}
|
}
|
||||||
|
|
||||||
// OnUpdate creates UpdateEvent and calls Update on EventHandler.
|
// OnUpdate creates UpdateEvent and calls Update on EventHandler.
|
||||||
func (e EventHandler) OnUpdate(oldObj, newObj interface{}) {
|
func (e *EventHandler) OnUpdate(oldObj, newObj interface{}) {
|
||||||
u := event.UpdateEvent{}
|
u := event.UpdateEvent{}
|
||||||
|
|
||||||
if o, ok := oldObj.(client.Object); ok {
|
if o, ok := oldObj.(client.Object); ok {
|
||||||
@ -84,18 +109,20 @@ func (e EventHandler) OnUpdate(oldObj, newObj interface{}) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, p := range e.Predicates {
|
for _, p := range e.predicates {
|
||||||
if !p.Update(u) {
|
if !p.Update(u) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Invoke update handler
|
// Invoke update handler
|
||||||
e.EventHandler.Update(u, e.Queue)
|
ctx, cancel := context.WithCancel(e.ctx)
|
||||||
|
defer cancel()
|
||||||
|
e.handler.Update(ctx, u, e.queue)
|
||||||
}
|
}
|
||||||
|
|
||||||
// OnDelete creates DeleteEvent and calls Delete on EventHandler.
|
// OnDelete creates DeleteEvent and calls Delete on EventHandler.
|
||||||
func (e EventHandler) OnDelete(obj interface{}) {
|
func (e *EventHandler) OnDelete(obj interface{}) {
|
||||||
d := event.DeleteEvent{}
|
d := event.DeleteEvent{}
|
||||||
|
|
||||||
// Deal with tombstone events by pulling the object out. Tombstone events wrap the object in a
|
// Deal with tombstone events by pulling the object out. Tombstone events wrap the object in a
|
||||||
@ -114,6 +141,9 @@ func (e EventHandler) OnDelete(obj interface{}) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set DeleteStateUnknown to true
|
||||||
|
d.DeleteStateUnknown = true
|
||||||
|
|
||||||
// Set obj to the tombstone obj
|
// Set obj to the tombstone obj
|
||||||
obj = tombstone.Obj
|
obj = tombstone.Obj
|
||||||
}
|
}
|
||||||
@ -127,12 +157,14 @@ func (e EventHandler) OnDelete(obj interface{}) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, p := range e.Predicates {
|
for _, p := range e.predicates {
|
||||||
if !p.Delete(d) {
|
if !p.Delete(d) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Invoke delete handler
|
// Invoke delete handler
|
||||||
e.EventHandler.Delete(d, e.Queue)
|
ctx, cancel := context.WithCancel(e.ctx)
|
||||||
|
defer cancel()
|
||||||
|
e.handler.Delete(ctx, d, e.queue)
|
||||||
}
|
}
|
117
vendor/sigs.k8s.io/controller-runtime/pkg/internal/source/kind.go
generated
vendored
Normal file
117
vendor/sigs.k8s.io/controller-runtime/pkg/internal/source/kind.go
generated
vendored
Normal file
@ -0,0 +1,117 @@
|
|||||||
|
package internal
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"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"
|
||||||
|
"sigs.k8s.io/controller-runtime/pkg/predicate"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Kind is used to provide a source of events originating inside the cluster from Watches (e.g. Pod Create).
|
||||||
|
type Kind struct {
|
||||||
|
// Type is the type of object to watch. e.g. &v1.Pod{}
|
||||||
|
Type client.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
|
||||||
|
// contain an error, startup and syncing finished.
|
||||||
|
started 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 {
|
||||||
|
return fmt.Errorf("must create Kind with a non-nil object")
|
||||||
|
}
|
||||||
|
if ks.Cache == nil {
|
||||||
|
return fmt.Errorf("must create Kind with a non-nil cache")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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)
|
||||||
|
go func() {
|
||||||
|
var (
|
||||||
|
i cache.Informer
|
||||||
|
lastErr error
|
||||||
|
)
|
||||||
|
|
||||||
|
// Tries to get an informer until it returns true,
|
||||||
|
// an error or the specified context is cancelled or expired.
|
||||||
|
if err := wait.PollUntilContextCancel(ctx, 10*time.Second, true, func(ctx context.Context) (bool, error) {
|
||||||
|
// Lookup the Informer from the Cache and add an EventHandler which populates the Queue
|
||||||
|
i, lastErr = ks.Cache.GetInformer(ctx, ks.Type)
|
||||||
|
if lastErr != nil {
|
||||||
|
kindMatchErr := &meta.NoKindMatchError{}
|
||||||
|
switch {
|
||||||
|
case errors.As(lastErr, &kindMatchErr):
|
||||||
|
log.Error(lastErr, "if kind is a CRD, it should be installed before calling Start",
|
||||||
|
"kind", kindMatchErr.GroupKind)
|
||||||
|
case runtime.IsNotRegisteredError(lastErr):
|
||||||
|
log.Error(lastErr, "kind must be registered to the Scheme")
|
||||||
|
default:
|
||||||
|
log.Error(lastErr, "failed to get informer from cache")
|
||||||
|
}
|
||||||
|
return false, nil // Retry.
|
||||||
|
}
|
||||||
|
return true, nil
|
||||||
|
}); err != nil {
|
||||||
|
if lastErr != nil {
|
||||||
|
ks.started <- fmt.Errorf("failed to get informer from cache: %w", lastErr)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ks.started <- err
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err := i.AddEventHandler(NewEventHandler(ctx, queue, handler, prct).HandlerFuncs())
|
||||||
|
if err != nil {
|
||||||
|
ks.started <- err
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !ks.Cache.WaitForCacheSync(ctx) {
|
||||||
|
// Would be great to return something more informative here
|
||||||
|
ks.started <- errors.New("cache did not sync")
|
||||||
|
}
|
||||||
|
close(ks.started)
|
||||||
|
}()
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ks *Kind) String() string {
|
||||||
|
if ks.Type != nil {
|
||||||
|
return fmt.Sprintf("kind source: %T", ks.Type)
|
||||||
|
}
|
||||||
|
return "kind source: unknown type"
|
||||||
|
}
|
||||||
|
|
||||||
|
// WaitForSync implements SyncingSource to allow controllers to wait with starting
|
||||||
|
// workers until the cache is synced.
|
||||||
|
func (ks *Kind) WaitForSync(ctx context.Context) error {
|
||||||
|
select {
|
||||||
|
case err := <-ks.started:
|
||||||
|
return err
|
||||||
|
case <-ctx.Done():
|
||||||
|
ks.startCancel()
|
||||||
|
if errors.Is(ctx.Err(), context.Canceled) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return fmt.Errorf("timed out waiting for cache to be synced for Kind %T", ks.Type)
|
||||||
|
}
|
||||||
|
}
|
40
vendor/sigs.k8s.io/controller-runtime/pkg/log/deleg.go
generated
vendored
40
vendor/sigs.k8s.io/controller-runtime/pkg/log/deleg.go
generated
vendored
@ -25,7 +25,7 @@ import (
|
|||||||
// loggerPromise knows how to populate a concrete logr.Logger
|
// loggerPromise knows how to populate a concrete logr.Logger
|
||||||
// with options, given an actual base logger later on down the line.
|
// with options, given an actual base logger later on down the line.
|
||||||
type loggerPromise struct {
|
type loggerPromise struct {
|
||||||
logger *DelegatingLogSink
|
logger *delegatingLogSink
|
||||||
childPromises []*loggerPromise
|
childPromises []*loggerPromise
|
||||||
promisesLock sync.Mutex
|
promisesLock sync.Mutex
|
||||||
|
|
||||||
@ -33,7 +33,7 @@ type loggerPromise struct {
|
|||||||
tags []interface{}
|
tags []interface{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *loggerPromise) WithName(l *DelegatingLogSink, name string) *loggerPromise {
|
func (p *loggerPromise) WithName(l *delegatingLogSink, name string) *loggerPromise {
|
||||||
res := &loggerPromise{
|
res := &loggerPromise{
|
||||||
logger: l,
|
logger: l,
|
||||||
name: &name,
|
name: &name,
|
||||||
@ -47,7 +47,7 @@ func (p *loggerPromise) WithName(l *DelegatingLogSink, name string) *loggerPromi
|
|||||||
}
|
}
|
||||||
|
|
||||||
// WithValues provides a new Logger with the tags appended.
|
// WithValues provides a new Logger with the tags appended.
|
||||||
func (p *loggerPromise) WithValues(l *DelegatingLogSink, tags ...interface{}) *loggerPromise {
|
func (p *loggerPromise) WithValues(l *delegatingLogSink, tags ...interface{}) *loggerPromise {
|
||||||
res := &loggerPromise{
|
res := &loggerPromise{
|
||||||
logger: l,
|
logger: l,
|
||||||
tags: tags,
|
tags: tags,
|
||||||
@ -84,12 +84,12 @@ func (p *loggerPromise) Fulfill(parentLogSink logr.LogSink) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// DelegatingLogSink is a logsink that delegates to another logr.LogSink.
|
// delegatingLogSink is a logsink that delegates to another logr.LogSink.
|
||||||
// If the underlying promise is not nil, it registers calls to sub-loggers with
|
// If the underlying promise is not nil, it registers calls to sub-loggers with
|
||||||
// the logging factory to be populated later, and returns a new delegating
|
// the logging factory to be populated later, and returns a new delegating
|
||||||
// logger. It expects to have *some* logr.Logger set at all times (generally
|
// logger. It expects to have *some* logr.Logger set at all times (generally
|
||||||
// a no-op logger before the promises are fulfilled).
|
// a no-op logger before the promises are fulfilled).
|
||||||
type DelegatingLogSink struct {
|
type delegatingLogSink struct {
|
||||||
lock sync.RWMutex
|
lock sync.RWMutex
|
||||||
logger logr.LogSink
|
logger logr.LogSink
|
||||||
promise *loggerPromise
|
promise *loggerPromise
|
||||||
@ -97,7 +97,8 @@ type DelegatingLogSink struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Init implements logr.LogSink.
|
// Init implements logr.LogSink.
|
||||||
func (l *DelegatingLogSink) Init(info logr.RuntimeInfo) {
|
func (l *delegatingLogSink) Init(info logr.RuntimeInfo) {
|
||||||
|
eventuallyFulfillRoot()
|
||||||
l.lock.Lock()
|
l.lock.Lock()
|
||||||
defer l.lock.Unlock()
|
defer l.lock.Unlock()
|
||||||
l.info = info
|
l.info = info
|
||||||
@ -106,7 +107,8 @@ func (l *DelegatingLogSink) Init(info logr.RuntimeInfo) {
|
|||||||
// Enabled tests whether this Logger is enabled. For example, commandline
|
// Enabled tests whether this Logger is enabled. For example, commandline
|
||||||
// flags might be used to set the logging verbosity and disable some info
|
// flags might be used to set the logging verbosity and disable some info
|
||||||
// logs.
|
// logs.
|
||||||
func (l *DelegatingLogSink) Enabled(level int) bool {
|
func (l *delegatingLogSink) Enabled(level int) bool {
|
||||||
|
eventuallyFulfillRoot()
|
||||||
l.lock.RLock()
|
l.lock.RLock()
|
||||||
defer l.lock.RUnlock()
|
defer l.lock.RUnlock()
|
||||||
return l.logger.Enabled(level)
|
return l.logger.Enabled(level)
|
||||||
@ -118,7 +120,8 @@ func (l *DelegatingLogSink) Enabled(level int) bool {
|
|||||||
// the log line. The key/value pairs can then be used to add additional
|
// the log line. The key/value pairs can then be used to add additional
|
||||||
// variable information. The key/value pairs should alternate string
|
// variable information. The key/value pairs should alternate string
|
||||||
// keys and arbitrary values.
|
// keys and arbitrary values.
|
||||||
func (l *DelegatingLogSink) Info(level int, msg string, keysAndValues ...interface{}) {
|
func (l *delegatingLogSink) Info(level int, msg string, keysAndValues ...interface{}) {
|
||||||
|
eventuallyFulfillRoot()
|
||||||
l.lock.RLock()
|
l.lock.RLock()
|
||||||
defer l.lock.RUnlock()
|
defer l.lock.RUnlock()
|
||||||
l.logger.Info(level, msg, keysAndValues...)
|
l.logger.Info(level, msg, keysAndValues...)
|
||||||
@ -132,14 +135,16 @@ func (l *DelegatingLogSink) Info(level int, msg string, keysAndValues ...interfa
|
|||||||
// The msg field should be used to add context to any underlying error,
|
// The msg field should be used to add context to any underlying error,
|
||||||
// while the err field should be used to attach the actual error that
|
// while the err field should be used to attach the actual error that
|
||||||
// triggered this log line, if present.
|
// triggered this log line, if present.
|
||||||
func (l *DelegatingLogSink) Error(err error, msg string, keysAndValues ...interface{}) {
|
func (l *delegatingLogSink) Error(err error, msg string, keysAndValues ...interface{}) {
|
||||||
|
eventuallyFulfillRoot()
|
||||||
l.lock.RLock()
|
l.lock.RLock()
|
||||||
defer l.lock.RUnlock()
|
defer l.lock.RUnlock()
|
||||||
l.logger.Error(err, msg, keysAndValues...)
|
l.logger.Error(err, msg, keysAndValues...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithName provides a new Logger with the name appended.
|
// WithName provides a new Logger with the name appended.
|
||||||
func (l *DelegatingLogSink) WithName(name string) logr.LogSink {
|
func (l *delegatingLogSink) WithName(name string) logr.LogSink {
|
||||||
|
eventuallyFulfillRoot()
|
||||||
l.lock.RLock()
|
l.lock.RLock()
|
||||||
defer l.lock.RUnlock()
|
defer l.lock.RUnlock()
|
||||||
|
|
||||||
@ -151,7 +156,7 @@ func (l *DelegatingLogSink) WithName(name string) logr.LogSink {
|
|||||||
return sink
|
return sink
|
||||||
}
|
}
|
||||||
|
|
||||||
res := &DelegatingLogSink{logger: l.logger}
|
res := &delegatingLogSink{logger: l.logger}
|
||||||
promise := l.promise.WithName(res, name)
|
promise := l.promise.WithName(res, name)
|
||||||
res.promise = promise
|
res.promise = promise
|
||||||
|
|
||||||
@ -159,7 +164,8 @@ func (l *DelegatingLogSink) WithName(name string) logr.LogSink {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// WithValues provides a new Logger with the tags appended.
|
// WithValues provides a new Logger with the tags appended.
|
||||||
func (l *DelegatingLogSink) WithValues(tags ...interface{}) logr.LogSink {
|
func (l *delegatingLogSink) WithValues(tags ...interface{}) logr.LogSink {
|
||||||
|
eventuallyFulfillRoot()
|
||||||
l.lock.RLock()
|
l.lock.RLock()
|
||||||
defer l.lock.RUnlock()
|
defer l.lock.RUnlock()
|
||||||
|
|
||||||
@ -171,7 +177,7 @@ func (l *DelegatingLogSink) WithValues(tags ...interface{}) logr.LogSink {
|
|||||||
return sink
|
return sink
|
||||||
}
|
}
|
||||||
|
|
||||||
res := &DelegatingLogSink{logger: l.logger}
|
res := &delegatingLogSink{logger: l.logger}
|
||||||
promise := l.promise.WithValues(res, tags...)
|
promise := l.promise.WithValues(res, tags...)
|
||||||
res.promise = promise
|
res.promise = promise
|
||||||
|
|
||||||
@ -181,16 +187,16 @@ func (l *DelegatingLogSink) WithValues(tags ...interface{}) logr.LogSink {
|
|||||||
// Fulfill switches the logger over to use the actual logger
|
// Fulfill switches the logger over to use the actual logger
|
||||||
// provided, instead of the temporary initial one, if this method
|
// provided, instead of the temporary initial one, if this method
|
||||||
// has not been previously called.
|
// has not been previously called.
|
||||||
func (l *DelegatingLogSink) Fulfill(actual logr.LogSink) {
|
func (l *delegatingLogSink) Fulfill(actual logr.LogSink) {
|
||||||
if l.promise != nil {
|
if l.promise != nil {
|
||||||
l.promise.Fulfill(actual)
|
l.promise.Fulfill(actual)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewDelegatingLogSink constructs a new DelegatingLogSink which uses
|
// newDelegatingLogSink constructs a new DelegatingLogSink which uses
|
||||||
// the given logger before its promise is fulfilled.
|
// the given logger before its promise is fulfilled.
|
||||||
func NewDelegatingLogSink(initial logr.LogSink) *DelegatingLogSink {
|
func newDelegatingLogSink(initial logr.LogSink) *delegatingLogSink {
|
||||||
l := &DelegatingLogSink{
|
l := &delegatingLogSink{
|
||||||
logger: initial,
|
logger: initial,
|
||||||
promise: &loggerPromise{promisesLock: sync.Mutex{}},
|
promise: &loggerPromise{promisesLock: sync.Mutex{}},
|
||||||
}
|
}
|
||||||
|
46
vendor/sigs.k8s.io/controller-runtime/pkg/log/log.go
generated
vendored
46
vendor/sigs.k8s.io/controller-runtime/pkg/log/log.go
generated
vendored
@ -35,7 +35,10 @@ package log
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"sync"
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"runtime/debug"
|
||||||
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/go-logr/logr"
|
"github.com/go-logr/logr"
|
||||||
@ -43,35 +46,24 @@ import (
|
|||||||
|
|
||||||
// SetLogger sets a concrete logging implementation for all deferred Loggers.
|
// SetLogger sets a concrete logging implementation for all deferred Loggers.
|
||||||
func SetLogger(l logr.Logger) {
|
func SetLogger(l logr.Logger) {
|
||||||
loggerWasSetLock.Lock()
|
logFullfilled.Store(true)
|
||||||
defer loggerWasSetLock.Unlock()
|
rootLog.Fulfill(l.GetSink())
|
||||||
|
|
||||||
loggerWasSet = true
|
|
||||||
dlog.Fulfill(l.GetSink())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// It is safe to assume that if this wasn't set within the first 30 seconds of a binaries
|
func eventuallyFulfillRoot() {
|
||||||
// lifetime, it will never get set. The DelegatingLogSink causes a high number of memory
|
if logFullfilled.Load() {
|
||||||
// allocations when not given an actual Logger, so we set a NullLogSink to avoid that.
|
return
|
||||||
//
|
}
|
||||||
// We need to keep the DelegatingLogSink because we have various inits() that get a logger from
|
if time.Since(rootLogCreated).Seconds() >= 30 {
|
||||||
// here. They will always get executed before any code that imports controller-runtime
|
if logFullfilled.CompareAndSwap(false, true) {
|
||||||
// has a chance to run and hence to set an actual logger.
|
fmt.Fprintf(os.Stderr, "[controller-runtime] log.SetLogger(...) was never called, logs will not be displayed:\n%s", debug.Stack())
|
||||||
func init() {
|
SetLogger(logr.New(NullLogSink{}))
|
||||||
// Init is blocking, so start a new goroutine
|
|
||||||
go func() {
|
|
||||||
time.Sleep(30 * time.Second)
|
|
||||||
loggerWasSetLock.Lock()
|
|
||||||
defer loggerWasSetLock.Unlock()
|
|
||||||
if !loggerWasSet {
|
|
||||||
dlog.Fulfill(NullLogSink{})
|
|
||||||
}
|
}
|
||||||
}()
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
loggerWasSetLock sync.Mutex
|
logFullfilled atomic.Bool
|
||||||
loggerWasSet bool
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Log is the base logger used by kubebuilder. It delegates
|
// Log is the base logger used by kubebuilder. It delegates
|
||||||
@ -80,8 +72,10 @@ var (
|
|||||||
// the first 30 seconds of a binaries lifetime, it will get
|
// the first 30 seconds of a binaries lifetime, it will get
|
||||||
// set to a NullLogSink.
|
// set to a NullLogSink.
|
||||||
var (
|
var (
|
||||||
dlog = NewDelegatingLogSink(NullLogSink{})
|
rootLog, rootLogCreated = func() (*delegatingLogSink, time.Time) {
|
||||||
Log = logr.New(dlog)
|
return newDelegatingLogSink(NullLogSink{}), time.Now()
|
||||||
|
}()
|
||||||
|
Log = logr.New(rootLog)
|
||||||
)
|
)
|
||||||
|
|
||||||
// FromContext returns a logger with predefined values from a context.Context.
|
// FromContext returns a logger with predefined values from a context.Context.
|
||||||
|
120
vendor/sigs.k8s.io/controller-runtime/pkg/manager/internal.go
generated
vendored
120
vendor/sigs.k8s.io/controller-runtime/pkg/manager/internal.go
generated
vendored
@ -18,11 +18,11 @@ package manager
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"crypto/tls"
|
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"net/http/pprof"
|
||||||
"sync"
|
"sync"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
@ -32,7 +32,6 @@ import (
|
|||||||
"k8s.io/apimachinery/pkg/api/meta"
|
"k8s.io/apimachinery/pkg/api/meta"
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
kerrors "k8s.io/apimachinery/pkg/util/errors"
|
kerrors "k8s.io/apimachinery/pkg/util/errors"
|
||||||
"k8s.io/apimachinery/pkg/util/wait"
|
|
||||||
"k8s.io/client-go/rest"
|
"k8s.io/client-go/rest"
|
||||||
"k8s.io/client-go/tools/leaderelection"
|
"k8s.io/client-go/tools/leaderelection"
|
||||||
"k8s.io/client-go/tools/leaderelection/resourcelock"
|
"k8s.io/client-go/tools/leaderelection/resourcelock"
|
||||||
@ -41,12 +40,11 @@ import (
|
|||||||
"sigs.k8s.io/controller-runtime/pkg/cache"
|
"sigs.k8s.io/controller-runtime/pkg/cache"
|
||||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||||
"sigs.k8s.io/controller-runtime/pkg/cluster"
|
"sigs.k8s.io/controller-runtime/pkg/cluster"
|
||||||
"sigs.k8s.io/controller-runtime/pkg/config/v1alpha1"
|
"sigs.k8s.io/controller-runtime/pkg/config"
|
||||||
"sigs.k8s.io/controller-runtime/pkg/healthz"
|
"sigs.k8s.io/controller-runtime/pkg/healthz"
|
||||||
"sigs.k8s.io/controller-runtime/pkg/internal/httpserver"
|
"sigs.k8s.io/controller-runtime/pkg/internal/httpserver"
|
||||||
intrec "sigs.k8s.io/controller-runtime/pkg/internal/recorder"
|
intrec "sigs.k8s.io/controller-runtime/pkg/internal/recorder"
|
||||||
"sigs.k8s.io/controller-runtime/pkg/metrics"
|
"sigs.k8s.io/controller-runtime/pkg/metrics"
|
||||||
"sigs.k8s.io/controller-runtime/pkg/runtime/inject"
|
|
||||||
"sigs.k8s.io/controller-runtime/pkg/webhook"
|
"sigs.k8s.io/controller-runtime/pkg/webhook"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -107,8 +105,11 @@ type controllerManager struct {
|
|||||||
// Healthz probe handler
|
// Healthz probe handler
|
||||||
healthzHandler *healthz.Handler
|
healthzHandler *healthz.Handler
|
||||||
|
|
||||||
// controllerOptions are the global controller options.
|
// pprofListener is used to serve pprof
|
||||||
controllerOptions v1alpha1.ControllerConfigurationSpec
|
pprofListener net.Listener
|
||||||
|
|
||||||
|
// controllerConfig are the global controller options.
|
||||||
|
controllerConfig config.Controller
|
||||||
|
|
||||||
// Logger is the logger that should be used by this manager.
|
// Logger is the logger that should be used by this manager.
|
||||||
// If none is set, it defaults to log.Log global logger.
|
// If none is set, it defaults to log.Log global logger.
|
||||||
@ -128,18 +129,7 @@ type controllerManager struct {
|
|||||||
// election was configured.
|
// election was configured.
|
||||||
elected chan struct{}
|
elected chan struct{}
|
||||||
|
|
||||||
// port is the port that the webhook server serves at.
|
webhookServer webhook.Server
|
||||||
port int
|
|
||||||
// host is the hostname that the webhook server binds to.
|
|
||||||
host string
|
|
||||||
// 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
|
|
||||||
certDir string
|
|
||||||
// tlsOpts is used to allow configuring the TLS config used for the webhook server.
|
|
||||||
tlsOpts []func(*tls.Config)
|
|
||||||
|
|
||||||
webhookServer *webhook.Server
|
|
||||||
// webhookServerOnce will be called in GetWebhookServer() to optionally initialize
|
// webhookServerOnce will be called in GetWebhookServer() to optionally initialize
|
||||||
// webhookServer if unset, and Add() it to controllerManager.
|
// webhookServer if unset, and Add() it to controllerManager.
|
||||||
webhookServerOnce sync.Once
|
webhookServerOnce sync.Once
|
||||||
@ -191,31 +181,9 @@ func (cm *controllerManager) Add(r Runnable) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (cm *controllerManager) add(r Runnable) error {
|
func (cm *controllerManager) add(r Runnable) error {
|
||||||
// Set dependencies on the object
|
|
||||||
if err := cm.SetFields(r); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return cm.runnables.Add(r)
|
return cm.runnables.Add(r)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Deprecated: use the equivalent Options field to set a field. This method will be removed in v0.10.
|
|
||||||
func (cm *controllerManager) SetFields(i interface{}) error {
|
|
||||||
if err := cm.cluster.SetFields(i); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if _, err := inject.InjectorInto(cm.SetFields, i); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if _, err := inject.StopChannelInto(cm.internalProceduresStop, i); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if _, err := inject.LoggerInto(cm.logger, i); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// AddMetricsExtraHandler adds extra handler served on path to the http server that serves metrics.
|
// AddMetricsExtraHandler adds extra handler served on path to the http server that serves metrics.
|
||||||
func (cm *controllerManager) AddMetricsExtraHandler(path string, handler http.Handler) error {
|
func (cm *controllerManager) AddMetricsExtraHandler(path string, handler http.Handler) error {
|
||||||
cm.Lock()
|
cm.Lock()
|
||||||
@ -272,6 +240,10 @@ func (cm *controllerManager) AddReadyzCheck(name string, check healthz.Checker)
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (cm *controllerManager) GetHTTPClient() *http.Client {
|
||||||
|
return cm.cluster.GetHTTPClient()
|
||||||
|
}
|
||||||
|
|
||||||
func (cm *controllerManager) GetConfig() *rest.Config {
|
func (cm *controllerManager) GetConfig() *rest.Config {
|
||||||
return cm.cluster.GetConfig()
|
return cm.cluster.GetConfig()
|
||||||
}
|
}
|
||||||
@ -304,15 +276,10 @@ func (cm *controllerManager) GetAPIReader() client.Reader {
|
|||||||
return cm.cluster.GetAPIReader()
|
return cm.cluster.GetAPIReader()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cm *controllerManager) GetWebhookServer() *webhook.Server {
|
func (cm *controllerManager) GetWebhookServer() webhook.Server {
|
||||||
cm.webhookServerOnce.Do(func() {
|
cm.webhookServerOnce.Do(func() {
|
||||||
if cm.webhookServer == nil {
|
if cm.webhookServer == nil {
|
||||||
cm.webhookServer = &webhook.Server{
|
panic("webhook should not be nil")
|
||||||
Port: cm.port,
|
|
||||||
Host: cm.host,
|
|
||||||
CertDir: cm.certDir,
|
|
||||||
TLSOpts: cm.tlsOpts,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if err := cm.Add(cm.webhookServer); err != nil {
|
if err := cm.Add(cm.webhookServer); err != nil {
|
||||||
panic(fmt.Sprintf("unable to add webhook server to the controller manager: %s", err))
|
panic(fmt.Sprintf("unable to add webhook server to the controller manager: %s", err))
|
||||||
@ -325,23 +292,29 @@ func (cm *controllerManager) GetLogger() logr.Logger {
|
|||||||
return cm.logger
|
return cm.logger
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cm *controllerManager) GetControllerOptions() v1alpha1.ControllerConfigurationSpec {
|
func (cm *controllerManager) GetControllerOptions() config.Controller {
|
||||||
return cm.controllerOptions
|
return cm.controllerConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cm *controllerManager) serveMetrics() {
|
func (cm *controllerManager) addMetricsServer() error {
|
||||||
|
mux := http.NewServeMux()
|
||||||
|
srv := httpserver.New(mux)
|
||||||
|
|
||||||
handler := promhttp.HandlerFor(metrics.Registry, promhttp.HandlerOpts{
|
handler := promhttp.HandlerFor(metrics.Registry, promhttp.HandlerOpts{
|
||||||
ErrorHandling: promhttp.HTTPErrorOnError,
|
ErrorHandling: promhttp.HTTPErrorOnError,
|
||||||
})
|
})
|
||||||
// TODO(JoelSpeed): Use existing Kubernetes machinery for serving metrics
|
// TODO(JoelSpeed): Use existing Kubernetes machinery for serving metrics
|
||||||
mux := http.NewServeMux()
|
|
||||||
mux.Handle(defaultMetricsEndpoint, handler)
|
mux.Handle(defaultMetricsEndpoint, handler)
|
||||||
for path, extraHandler := range cm.metricsExtraHandlers {
|
for path, extraHandler := range cm.metricsExtraHandlers {
|
||||||
mux.Handle(path, extraHandler)
|
mux.Handle(path, extraHandler)
|
||||||
}
|
}
|
||||||
|
|
||||||
server := httpserver.New(mux)
|
return cm.add(&server{
|
||||||
go cm.httpServe("metrics", cm.logger.WithValues("path", defaultMetricsEndpoint), server, cm.metricsListener)
|
Kind: "metrics",
|
||||||
|
Log: cm.logger.WithValues("path", defaultMetricsEndpoint),
|
||||||
|
Server: srv,
|
||||||
|
Listener: cm.metricsListener,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cm *controllerManager) serveHealthProbes() {
|
func (cm *controllerManager) serveHealthProbes() {
|
||||||
@ -362,6 +335,24 @@ func (cm *controllerManager) serveHealthProbes() {
|
|||||||
go cm.httpServe("health probe", cm.logger, server, cm.healthProbeListener)
|
go cm.httpServe("health probe", cm.logger, server, cm.healthProbeListener)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (cm *controllerManager) addPprofServer() error {
|
||||||
|
mux := http.NewServeMux()
|
||||||
|
srv := httpserver.New(mux)
|
||||||
|
|
||||||
|
mux.HandleFunc("/debug/pprof/", pprof.Index)
|
||||||
|
mux.HandleFunc("/debug/pprof/cmdline", pprof.Cmdline)
|
||||||
|
mux.HandleFunc("/debug/pprof/profile", pprof.Profile)
|
||||||
|
mux.HandleFunc("/debug/pprof/symbol", pprof.Symbol)
|
||||||
|
mux.HandleFunc("/debug/pprof/trace", pprof.Trace)
|
||||||
|
|
||||||
|
return cm.add(&server{
|
||||||
|
Kind: "pprof",
|
||||||
|
Log: cm.logger,
|
||||||
|
Server: srv,
|
||||||
|
Listener: cm.pprofListener,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func (cm *controllerManager) httpServe(kind string, log logr.Logger, server *http.Server, ln net.Listener) {
|
func (cm *controllerManager) httpServe(kind string, log logr.Logger, server *http.Server, ln net.Listener) {
|
||||||
log = log.WithValues("kind", kind, "addr", ln.Addr())
|
log = log.WithValues("kind", kind, "addr", ln.Addr())
|
||||||
|
|
||||||
@ -451,7 +442,9 @@ func (cm *controllerManager) Start(ctx context.Context) (err error) {
|
|||||||
// (If we don't serve metrics for non-leaders, prometheus will still scrape
|
// (If we don't serve metrics for non-leaders, prometheus will still scrape
|
||||||
// the pod but will get a connection refused).
|
// the pod but will get a connection refused).
|
||||||
if cm.metricsListener != nil {
|
if cm.metricsListener != nil {
|
||||||
cm.serveMetrics()
|
if err := cm.addMetricsServer(); err != nil {
|
||||||
|
return fmt.Errorf("failed to add metrics server: %w", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Serve health probes.
|
// Serve health probes.
|
||||||
@ -459,6 +452,13 @@ func (cm *controllerManager) Start(ctx context.Context) (err error) {
|
|||||||
cm.serveHealthProbes()
|
cm.serveHealthProbes()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add pprof server
|
||||||
|
if cm.pprofListener != nil {
|
||||||
|
if err := cm.addPprofServer(); err != nil {
|
||||||
|
return fmt.Errorf("failed to add pprof server: %w", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// First start any webhook servers, which includes conversion, validation, and defaulting
|
// First start any webhook servers, which includes conversion, validation, and defaulting
|
||||||
// webhooks that are registered.
|
// webhooks that are registered.
|
||||||
//
|
//
|
||||||
@ -466,22 +466,22 @@ func (cm *controllerManager) Start(ctx context.Context) (err error) {
|
|||||||
// between conversion webhooks and the cache sync (usually initial list) which causes the webhooks
|
// between conversion webhooks and the cache sync (usually initial list) which causes the webhooks
|
||||||
// to never start because no cache can be populated.
|
// to never start because no cache can be populated.
|
||||||
if err := cm.runnables.Webhooks.Start(cm.internalCtx); err != nil {
|
if err := cm.runnables.Webhooks.Start(cm.internalCtx); err != nil {
|
||||||
if !errors.Is(err, wait.ErrWaitTimeout) {
|
if err != nil {
|
||||||
return err
|
return fmt.Errorf("failed to start webhooks: %w", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start and wait for caches.
|
// Start and wait for caches.
|
||||||
if err := cm.runnables.Caches.Start(cm.internalCtx); err != nil {
|
if err := cm.runnables.Caches.Start(cm.internalCtx); err != nil {
|
||||||
if !errors.Is(err, wait.ErrWaitTimeout) {
|
if err != nil {
|
||||||
return err
|
return fmt.Errorf("failed to start caches: %w", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start the non-leaderelection Runnables after the cache has synced.
|
// Start the non-leaderelection Runnables after the cache has synced.
|
||||||
if err := cm.runnables.Others.Start(cm.internalCtx); err != nil {
|
if err := cm.runnables.Others.Start(cm.internalCtx); err != nil {
|
||||||
if !errors.Is(err, wait.ErrWaitTimeout) {
|
if err != nil {
|
||||||
return err
|
return fmt.Errorf("failed to start other runnables: %w", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
176
vendor/sigs.k8s.io/controller-runtime/pkg/manager/manager.go
generated
vendored
176
vendor/sigs.k8s.io/controller-runtime/pkg/manager/manager.go
generated
vendored
@ -33,6 +33,7 @@ import (
|
|||||||
"k8s.io/client-go/tools/leaderelection/resourcelock"
|
"k8s.io/client-go/tools/leaderelection/resourcelock"
|
||||||
"k8s.io/client-go/tools/record"
|
"k8s.io/client-go/tools/record"
|
||||||
"k8s.io/utils/pointer"
|
"k8s.io/utils/pointer"
|
||||||
|
|
||||||
"sigs.k8s.io/controller-runtime/pkg/cache"
|
"sigs.k8s.io/controller-runtime/pkg/cache"
|
||||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||||
"sigs.k8s.io/controller-runtime/pkg/cluster"
|
"sigs.k8s.io/controller-runtime/pkg/cluster"
|
||||||
@ -44,7 +45,6 @@ import (
|
|||||||
"sigs.k8s.io/controller-runtime/pkg/log"
|
"sigs.k8s.io/controller-runtime/pkg/log"
|
||||||
"sigs.k8s.io/controller-runtime/pkg/metrics"
|
"sigs.k8s.io/controller-runtime/pkg/metrics"
|
||||||
"sigs.k8s.io/controller-runtime/pkg/recorder"
|
"sigs.k8s.io/controller-runtime/pkg/recorder"
|
||||||
"sigs.k8s.io/controller-runtime/pkg/runtime/inject"
|
|
||||||
"sigs.k8s.io/controller-runtime/pkg/webhook"
|
"sigs.k8s.io/controller-runtime/pkg/webhook"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -55,8 +55,7 @@ type Manager interface {
|
|||||||
cluster.Cluster
|
cluster.Cluster
|
||||||
|
|
||||||
// Add will set requested dependencies on the component, and cause the component to be
|
// Add will set requested dependencies on the component, and cause the component to be
|
||||||
// started when Start is called. Add will inject any dependencies for which the argument
|
// started when Start is called.
|
||||||
// implements the inject interface - e.g. inject.Client.
|
|
||||||
// Depending on if a Runnable implements LeaderElectionRunnable interface, a Runnable can be run in either
|
// Depending on if a Runnable implements LeaderElectionRunnable interface, a Runnable can be run in either
|
||||||
// non-leaderelection mode (always running) or leader election mode (managed by leader election if enabled).
|
// non-leaderelection mode (always running) or leader election mode (managed by leader election if enabled).
|
||||||
Add(Runnable) error
|
Add(Runnable) error
|
||||||
@ -88,13 +87,13 @@ type Manager interface {
|
|||||||
Start(ctx context.Context) error
|
Start(ctx context.Context) error
|
||||||
|
|
||||||
// GetWebhookServer returns a webhook.Server
|
// GetWebhookServer returns a webhook.Server
|
||||||
GetWebhookServer() *webhook.Server
|
GetWebhookServer() webhook.Server
|
||||||
|
|
||||||
// GetLogger returns this manager's logger.
|
// GetLogger returns this manager's logger.
|
||||||
GetLogger() logr.Logger
|
GetLogger() logr.Logger
|
||||||
|
|
||||||
// GetControllerOptions returns controller global configuration options.
|
// GetControllerOptions returns controller global configuration options.
|
||||||
GetControllerOptions() v1alpha1.ControllerConfigurationSpec
|
GetControllerOptions() config.Controller
|
||||||
}
|
}
|
||||||
|
|
||||||
// Options are the arguments for creating a new Manager.
|
// Options are the arguments for creating a new Manager.
|
||||||
@ -102,10 +101,44 @@ type Options struct {
|
|||||||
// Scheme is the scheme used to resolve runtime.Objects to GroupVersionKinds / Resources.
|
// Scheme is the scheme used to resolve runtime.Objects to GroupVersionKinds / Resources.
|
||||||
// Defaults to the kubernetes/client-go scheme.Scheme, but it's almost always better
|
// Defaults to the kubernetes/client-go scheme.Scheme, but it's almost always better
|
||||||
// to pass your own scheme in. See the documentation in pkg/scheme for more information.
|
// to pass your own scheme in. See the documentation in pkg/scheme for more information.
|
||||||
|
//
|
||||||
|
// If set, the Scheme will be used to create the default Client and Cache.
|
||||||
Scheme *runtime.Scheme
|
Scheme *runtime.Scheme
|
||||||
|
|
||||||
// MapperProvider provides the rest mapper used to map go types to Kubernetes APIs
|
// MapperProvider provides the rest mapper used to map go types to Kubernetes APIs.
|
||||||
MapperProvider func(c *rest.Config) (meta.RESTMapper, error)
|
//
|
||||||
|
// If set, the RESTMapper returned by this function is used to create the RESTMapper
|
||||||
|
// used by the Client and Cache.
|
||||||
|
MapperProvider func(c *rest.Config, httpClient *http.Client) (meta.RESTMapper, error)
|
||||||
|
|
||||||
|
// Cache is the cache.Options that will be used to create the default Cache.
|
||||||
|
// By default, the cache will watch and list requested objects in all namespaces.
|
||||||
|
Cache cache.Options
|
||||||
|
|
||||||
|
// NewCache is the function that will create the cache to be used
|
||||||
|
// by the manager. If not set this will use the default new cache function.
|
||||||
|
//
|
||||||
|
// When using a custom NewCache, the Cache options will be passed to the
|
||||||
|
// NewCache function.
|
||||||
|
//
|
||||||
|
// NOTE: LOW LEVEL PRIMITIVE!
|
||||||
|
// Only use a custom NewCache if you know what you are doing.
|
||||||
|
NewCache cache.NewCacheFunc
|
||||||
|
|
||||||
|
// Client is the client.Options that will be used to create the default Client.
|
||||||
|
// By default, the client will use the cache for reads and direct calls for writes.
|
||||||
|
Client client.Options
|
||||||
|
|
||||||
|
// NewClient is the func that creates the client to be used by the manager.
|
||||||
|
// If not set this will create a Client backed by a Cache for read operations
|
||||||
|
// and a direct Client for write operations.
|
||||||
|
//
|
||||||
|
// When using a custom NewClient, the Client options will be passed to the
|
||||||
|
// NewClient function.
|
||||||
|
//
|
||||||
|
// NOTE: LOW LEVEL PRIMITIVE!
|
||||||
|
// Only use a custom NewClient if you know what you are doing.
|
||||||
|
NewClient client.NewClientFunc
|
||||||
|
|
||||||
// SyncPeriod determines the minimum frequency at which watched resources are
|
// SyncPeriod determines the minimum frequency at which watched resources are
|
||||||
// reconciled. A lower period will correct entropy more quickly, but reduce
|
// reconciled. A lower period will correct entropy more quickly, but reduce
|
||||||
@ -132,6 +165,8 @@ type Options struct {
|
|||||||
// is "done" with an object, and would otherwise not requeue it, i.e., we
|
// is "done" with an object, and would otherwise not requeue it, i.e., we
|
||||||
// recommend the `Reconcile` function return `reconcile.Result{RequeueAfter: t}`,
|
// recommend the `Reconcile` function return `reconcile.Result{RequeueAfter: t}`,
|
||||||
// instead of `reconcile.Result{}`.
|
// instead of `reconcile.Result{}`.
|
||||||
|
//
|
||||||
|
// Deprecated: Use Cache.SyncPeriod instead.
|
||||||
SyncPeriod *time.Duration
|
SyncPeriod *time.Duration
|
||||||
|
|
||||||
// Logger is the logger that should be used by this manager.
|
// Logger is the logger that should be used by this manager.
|
||||||
@ -217,6 +252,8 @@ type Options struct {
|
|||||||
// Note: If a namespace is specified, controllers can still Watch for a
|
// Note: If a namespace is specified, controllers can still Watch for a
|
||||||
// cluster-scoped resource (e.g Node). For namespaced resources, the cache
|
// cluster-scoped resource (e.g Node). For namespaced resources, the cache
|
||||||
// will only hold objects from the desired namespace.
|
// will only hold objects from the desired namespace.
|
||||||
|
//
|
||||||
|
// Deprecated: Use Cache.Namespaces instead.
|
||||||
Namespace string
|
Namespace string
|
||||||
|
|
||||||
// MetricsBindAddress is the TCP address that the controller should bind to
|
// MetricsBindAddress is the TCP address that the controller should bind to
|
||||||
@ -235,11 +272,22 @@ type Options struct {
|
|||||||
// Liveness probe endpoint name, defaults to "healthz"
|
// Liveness probe endpoint name, defaults to "healthz"
|
||||||
LivenessEndpointName string
|
LivenessEndpointName string
|
||||||
|
|
||||||
|
// PprofBindAddress is the TCP address that the controller should bind to
|
||||||
|
// for serving pprof.
|
||||||
|
// It can be set to "" or "0" to disable the pprof serving.
|
||||||
|
// Since pprof may contain sensitive information, make sure to protect it
|
||||||
|
// before exposing it to public.
|
||||||
|
PprofBindAddress string
|
||||||
|
|
||||||
// Port is the port that the webhook server serves at.
|
// Port is the port that the webhook server serves at.
|
||||||
// It is used to set webhook.Server.Port if WebhookServer is not set.
|
// It is used to set webhook.Server.Port if WebhookServer is not set.
|
||||||
|
//
|
||||||
|
// Deprecated: Use WebhookServer instead. A WebhookServer can be created via webhook.NewServer.
|
||||||
Port int
|
Port int
|
||||||
// Host is the hostname that the webhook server binds to.
|
// Host is the hostname that the webhook server binds to.
|
||||||
// It is used to set webhook.Server.Host if WebhookServer is not set.
|
// It is used to set webhook.Server.Host if WebhookServer is not set.
|
||||||
|
//
|
||||||
|
// Deprecated: Use WebhookServer instead. A WebhookServer can be created via webhook.NewServer.
|
||||||
Host string
|
Host string
|
||||||
|
|
||||||
// CertDir is the directory that contains the server key and certificate.
|
// CertDir is the directory that contains the server key and certificate.
|
||||||
@ -247,26 +295,19 @@ type Options struct {
|
|||||||
// {TempDir}/k8s-webhook-server/serving-certs. The server key and certificate
|
// {TempDir}/k8s-webhook-server/serving-certs. The server key and certificate
|
||||||
// must be named tls.key and tls.crt, respectively.
|
// must be named tls.key and tls.crt, respectively.
|
||||||
// It is used to set webhook.Server.CertDir if WebhookServer is not set.
|
// It is used to set webhook.Server.CertDir if WebhookServer is not set.
|
||||||
|
//
|
||||||
|
// Deprecated: Use WebhookServer instead. A WebhookServer can be created via webhook.NewServer.
|
||||||
CertDir string
|
CertDir string
|
||||||
|
|
||||||
// TLSOpts is used to allow configuring the TLS config used for the webhook server.
|
// TLSOpts is used to allow configuring the TLS config used for the webhook server.
|
||||||
|
//
|
||||||
|
// Deprecated: Use WebhookServer instead. A WebhookServer can be created via webhook.NewServer.
|
||||||
TLSOpts []func(*tls.Config)
|
TLSOpts []func(*tls.Config)
|
||||||
|
|
||||||
// WebhookServer is an externally configured webhook.Server. By default,
|
// WebhookServer is an externally configured webhook.Server. By default,
|
||||||
// a Manager will create a default server using Port, Host, and CertDir;
|
// a Manager will create a default server using Port, Host, and CertDir;
|
||||||
// if this is set, the Manager will use this server instead.
|
// if this is set, the Manager will use this server instead.
|
||||||
WebhookServer *webhook.Server
|
WebhookServer webhook.Server
|
||||||
|
|
||||||
// Functions to allow for a user to customize values that will be injected.
|
|
||||||
|
|
||||||
// NewCache is the function that will create the cache to be used
|
|
||||||
// by the manager. If not set this will use the default new cache function.
|
|
||||||
NewCache cache.NewCacheFunc
|
|
||||||
|
|
||||||
// NewClient is the func that creates the client to be used by the manager.
|
|
||||||
// If not set this will create the default DelegatingClient that will
|
|
||||||
// use the cache for reads and the client for writes.
|
|
||||||
NewClient cluster.NewClientFunc
|
|
||||||
|
|
||||||
// BaseContext is the function that provides Context values to Runnables
|
// BaseContext is the function that provides Context values to Runnables
|
||||||
// managed by the Manager. If a BaseContext function isn't provided, Runnables
|
// managed by the Manager. If a BaseContext function isn't provided, Runnables
|
||||||
@ -275,10 +316,14 @@ type Options struct {
|
|||||||
|
|
||||||
// ClientDisableCacheFor tells the client that, if any cache is used, to bypass it
|
// ClientDisableCacheFor tells the client that, if any cache is used, to bypass it
|
||||||
// for the given objects.
|
// for the given objects.
|
||||||
|
//
|
||||||
|
// Deprecated: Use Client.Cache.DisableCacheFor instead.
|
||||||
ClientDisableCacheFor []client.Object
|
ClientDisableCacheFor []client.Object
|
||||||
|
|
||||||
// DryRunClient specifies whether the client should be configured to enforce
|
// DryRunClient specifies whether the client should be configured to enforce
|
||||||
// dryRun mode.
|
// dryRun mode.
|
||||||
|
//
|
||||||
|
// Deprecated: Use Client.DryRun instead.
|
||||||
DryRunClient bool
|
DryRunClient bool
|
||||||
|
|
||||||
// EventBroadcaster records Events emitted by the manager and sends them to the Kubernetes API
|
// EventBroadcaster records Events emitted by the manager and sends them to the Kubernetes API
|
||||||
@ -297,7 +342,7 @@ type Options struct {
|
|||||||
// Controller contains global configuration options for controllers
|
// Controller contains global configuration options for controllers
|
||||||
// registered within this manager.
|
// registered within this manager.
|
||||||
// +optional
|
// +optional
|
||||||
Controller v1alpha1.ControllerConfigurationSpec
|
Controller config.Controller
|
||||||
|
|
||||||
// makeBroadcaster allows deferring the creation of the broadcaster to
|
// makeBroadcaster allows deferring the creation of the broadcaster to
|
||||||
// avoid leaking goroutines if we never call Start on this manager. It also
|
// avoid leaking goroutines if we never call Start on this manager. It also
|
||||||
@ -306,10 +351,11 @@ type Options struct {
|
|||||||
makeBroadcaster intrec.EventBroadcasterProducer
|
makeBroadcaster intrec.EventBroadcasterProducer
|
||||||
|
|
||||||
// Dependency injection for testing
|
// Dependency injection for testing
|
||||||
newRecorderProvider func(config *rest.Config, scheme *runtime.Scheme, logger logr.Logger, makeBroadcaster intrec.EventBroadcasterProducer) (*intrec.Provider, error)
|
newRecorderProvider func(config *rest.Config, httpClient *http.Client, scheme *runtime.Scheme, logger logr.Logger, makeBroadcaster intrec.EventBroadcasterProducer) (*intrec.Provider, error)
|
||||||
newResourceLock func(config *rest.Config, recorderProvider recorder.Provider, options leaderelection.Options) (resourcelock.Interface, error)
|
newResourceLock func(config *rest.Config, recorderProvider recorder.Provider, options leaderelection.Options) (resourcelock.Interface, error)
|
||||||
newMetricsListener func(addr string) (net.Listener, error)
|
newMetricsListener func(addr string) (net.Listener, error)
|
||||||
newHealthProbeListener func(addr string) (net.Listener, error)
|
newHealthProbeListener func(addr string) (net.Listener, error)
|
||||||
|
newPprofListener func(addr string) (net.Listener, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// BaseContextFunc is a function used to provide a base Context to Runnables
|
// BaseContextFunc is a function used to provide a base Context to Runnables
|
||||||
@ -353,12 +399,14 @@ func New(config *rest.Config, options Options) (Manager, error) {
|
|||||||
clusterOptions.MapperProvider = options.MapperProvider
|
clusterOptions.MapperProvider = options.MapperProvider
|
||||||
clusterOptions.Logger = options.Logger
|
clusterOptions.Logger = options.Logger
|
||||||
clusterOptions.SyncPeriod = options.SyncPeriod
|
clusterOptions.SyncPeriod = options.SyncPeriod
|
||||||
clusterOptions.Namespace = options.Namespace
|
|
||||||
clusterOptions.NewCache = options.NewCache
|
clusterOptions.NewCache = options.NewCache
|
||||||
clusterOptions.NewClient = options.NewClient
|
clusterOptions.NewClient = options.NewClient
|
||||||
clusterOptions.ClientDisableCacheFor = options.ClientDisableCacheFor
|
clusterOptions.Cache = options.Cache
|
||||||
clusterOptions.DryRunClient = options.DryRunClient
|
clusterOptions.Client = options.Client
|
||||||
clusterOptions.EventBroadcaster = options.EventBroadcaster //nolint:staticcheck
|
clusterOptions.Namespace = options.Namespace //nolint:staticcheck
|
||||||
|
clusterOptions.ClientDisableCacheFor = options.ClientDisableCacheFor //nolint:staticcheck
|
||||||
|
clusterOptions.DryRunClient = options.DryRunClient //nolint:staticcheck
|
||||||
|
clusterOptions.EventBroadcaster = options.EventBroadcaster //nolint:staticcheck
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -367,7 +415,7 @@ func New(config *rest.Config, options Options) (Manager, error) {
|
|||||||
// Create the recorder provider to inject event recorders for the components.
|
// Create the recorder provider to inject event recorders for the components.
|
||||||
// TODO(directxman12): the log for the event provider should have a context (name, tags, etc) specific
|
// TODO(directxman12): the log for the event provider should have a context (name, tags, etc) specific
|
||||||
// to the particular controller that it's being injected into, rather than a generic one like is here.
|
// to the particular controller that it's being injected into, rather than a generic one like is here.
|
||||||
recorderProvider, err := options.newRecorderProvider(config, cluster.GetScheme(), options.Logger.WithName("events"), options.makeBroadcaster)
|
recorderProvider, err := options.newRecorderProvider(config, cluster.GetHTTPClient(), cluster.GetScheme(), options.Logger.WithName("events"), options.makeBroadcaster)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -381,7 +429,7 @@ func New(config *rest.Config, options Options) (Manager, error) {
|
|||||||
leaderRecorderProvider = recorderProvider
|
leaderRecorderProvider = recorderProvider
|
||||||
} else {
|
} else {
|
||||||
leaderConfig = rest.CopyConfig(options.LeaderElectionConfig)
|
leaderConfig = rest.CopyConfig(options.LeaderElectionConfig)
|
||||||
leaderRecorderProvider, err = options.newRecorderProvider(leaderConfig, cluster.GetScheme(), options.Logger.WithName("events"), options.makeBroadcaster)
|
leaderRecorderProvider, err = options.newRecorderProvider(leaderConfig, cluster.GetHTTPClient(), cluster.GetScheme(), options.Logger.WithName("events"), options.makeBroadcaster)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -419,6 +467,13 @@ func New(config *rest.Config, options Options) (Manager, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Create pprof listener. This will throw an error if the bind
|
||||||
|
// address is invalid or already in use.
|
||||||
|
pprofListener, err := options.newPprofListener(options.PprofBindAddress)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to new pprof listener: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
errChan := make(chan error)
|
errChan := make(chan error)
|
||||||
runnables := newRunnables(options.BaseContext, errChan)
|
runnables := newRunnables(options.BaseContext, errChan)
|
||||||
|
|
||||||
@ -431,13 +486,9 @@ func New(config *rest.Config, options Options) (Manager, error) {
|
|||||||
resourceLock: resourceLock,
|
resourceLock: resourceLock,
|
||||||
metricsListener: metricsListener,
|
metricsListener: metricsListener,
|
||||||
metricsExtraHandlers: metricsExtraHandlers,
|
metricsExtraHandlers: metricsExtraHandlers,
|
||||||
controllerOptions: options.Controller,
|
controllerConfig: options.Controller,
|
||||||
logger: options.Logger,
|
logger: options.Logger,
|
||||||
elected: make(chan struct{}),
|
elected: make(chan struct{}),
|
||||||
port: options.Port,
|
|
||||||
host: options.Host,
|
|
||||||
certDir: options.CertDir,
|
|
||||||
tlsOpts: options.TLSOpts,
|
|
||||||
webhookServer: options.WebhookServer,
|
webhookServer: options.WebhookServer,
|
||||||
leaderElectionID: options.LeaderElectionID,
|
leaderElectionID: options.LeaderElectionID,
|
||||||
leaseDuration: *options.LeaseDuration,
|
leaseDuration: *options.LeaseDuration,
|
||||||
@ -446,6 +497,7 @@ func New(config *rest.Config, options Options) (Manager, error) {
|
|||||||
healthProbeListener: healthProbeListener,
|
healthProbeListener: healthProbeListener,
|
||||||
readinessEndpointName: options.ReadinessEndpointName,
|
readinessEndpointName: options.ReadinessEndpointName,
|
||||||
livenessEndpointName: options.LivenessEndpointName,
|
livenessEndpointName: options.LivenessEndpointName,
|
||||||
|
pprofListener: pprofListener,
|
||||||
gracefulShutdownTimeout: *options.GracefulShutdownTimeout,
|
gracefulShutdownTimeout: *options.GracefulShutdownTimeout,
|
||||||
internalProceduresStop: make(chan struct{}),
|
internalProceduresStop: make(chan struct{}),
|
||||||
leaderElectionStopped: make(chan struct{}),
|
leaderElectionStopped: make(chan struct{}),
|
||||||
@ -456,14 +508,14 @@ func New(config *rest.Config, options Options) (Manager, error) {
|
|||||||
// AndFrom will use a supplied type and convert to Options
|
// AndFrom will use a supplied type and convert to Options
|
||||||
// any options already set on Options will be ignored, this is used to allow
|
// any options already set on Options will be ignored, this is used to allow
|
||||||
// cli flags to override anything specified in the config file.
|
// 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) {
|
func (o Options) AndFrom(loader config.ControllerManagerConfiguration) (Options, error) {
|
||||||
if inj, wantsScheme := loader.(inject.Scheme); wantsScheme {
|
|
||||||
err := inj.InjectScheme(o.Scheme)
|
|
||||||
if err != nil {
|
|
||||||
return o, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
newObj, err := loader.Complete()
|
newObj, err := loader.Complete()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return o, err
|
return o, err
|
||||||
@ -498,18 +550,23 @@ func (o Options) AndFrom(loader config.ControllerManagerConfiguration) (Options,
|
|||||||
if o.Port == 0 && newObj.Webhook.Port != nil {
|
if o.Port == 0 && newObj.Webhook.Port != nil {
|
||||||
o.Port = *newObj.Webhook.Port
|
o.Port = *newObj.Webhook.Port
|
||||||
}
|
}
|
||||||
|
|
||||||
if o.Host == "" && newObj.Webhook.Host != "" {
|
if o.Host == "" && newObj.Webhook.Host != "" {
|
||||||
o.Host = newObj.Webhook.Host
|
o.Host = newObj.Webhook.Host
|
||||||
}
|
}
|
||||||
|
|
||||||
if o.CertDir == "" && newObj.Webhook.CertDir != "" {
|
if o.CertDir == "" && newObj.Webhook.CertDir != "" {
|
||||||
o.CertDir = newObj.Webhook.CertDir
|
o.CertDir = newObj.Webhook.CertDir
|
||||||
}
|
}
|
||||||
|
if o.WebhookServer == nil {
|
||||||
|
o.WebhookServer = webhook.NewServer(webhook.Options{
|
||||||
|
Port: o.Port,
|
||||||
|
Host: o.Host,
|
||||||
|
CertDir: o.CertDir,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
if newObj.Controller != nil {
|
if newObj.Controller != nil {
|
||||||
if o.Controller.CacheSyncTimeout == nil && newObj.Controller.CacheSyncTimeout != nil {
|
if o.Controller.CacheSyncTimeout == 0 && newObj.Controller.CacheSyncTimeout != nil {
|
||||||
o.Controller.CacheSyncTimeout = newObj.Controller.CacheSyncTimeout
|
o.Controller.CacheSyncTimeout = *newObj.Controller.CacheSyncTimeout
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(o.Controller.GroupKindConcurrency) == 0 && len(newObj.Controller.GroupKindConcurrency) > 0 {
|
if len(o.Controller.GroupKindConcurrency) == 0 && len(newObj.Controller.GroupKindConcurrency) > 0 {
|
||||||
@ -521,6 +578,13 @@ func (o Options) AndFrom(loader config.ControllerManagerConfiguration) (Options,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// AndFromOrDie will use options.AndFrom() and will panic if there are errors.
|
// 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 {
|
func (o Options) AndFromOrDie(loader config.ControllerManagerConfiguration) Options {
|
||||||
o, err := o.AndFrom(loader)
|
o, err := o.AndFrom(loader)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -579,6 +643,19 @@ func defaultHealthProbeListener(addr string) (net.Listener, error) {
|
|||||||
return ln, nil
|
return ln, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// defaultPprofListener creates the default pprof listener bound to the given address.
|
||||||
|
func defaultPprofListener(addr string) (net.Listener, error) {
|
||||||
|
if addr == "" || addr == "0" {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
ln, err := net.Listen("tcp", addr)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("error listening on %s: %w", addr, err)
|
||||||
|
}
|
||||||
|
return ln, nil
|
||||||
|
}
|
||||||
|
|
||||||
// defaultBaseContext is used as the BaseContext value in Options if one
|
// defaultBaseContext is used as the BaseContext value in Options if one
|
||||||
// has not already been set.
|
// has not already been set.
|
||||||
func defaultBaseContext() context.Context {
|
func defaultBaseContext() context.Context {
|
||||||
@ -639,6 +716,10 @@ func setOptionsDefaults(options Options) Options {
|
|||||||
options.newHealthProbeListener = defaultHealthProbeListener
|
options.newHealthProbeListener = defaultHealthProbeListener
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if options.newPprofListener == nil {
|
||||||
|
options.newPprofListener = defaultPprofListener
|
||||||
|
}
|
||||||
|
|
||||||
if options.GracefulShutdownTimeout == nil {
|
if options.GracefulShutdownTimeout == nil {
|
||||||
gracefulShutdownTimeout := defaultGracefulShutdownPeriod
|
gracefulShutdownTimeout := defaultGracefulShutdownPeriod
|
||||||
options.GracefulShutdownTimeout = &gracefulShutdownTimeout
|
options.GracefulShutdownTimeout = &gracefulShutdownTimeout
|
||||||
@ -652,5 +733,14 @@ func setOptionsDefaults(options Options) Options {
|
|||||||
options.BaseContext = defaultBaseContext
|
options.BaseContext = defaultBaseContext
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if options.WebhookServer == nil {
|
||||||
|
options.WebhookServer = webhook.NewServer(webhook.Options{
|
||||||
|
Host: options.Host,
|
||||||
|
Port: options.Port,
|
||||||
|
CertDir: options.CertDir,
|
||||||
|
TLSOpts: options.TLSOpts,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
return options
|
return options
|
||||||
}
|
}
|
||||||
|
2
vendor/sigs.k8s.io/controller-runtime/pkg/manager/runnable_group.go
generated
vendored
2
vendor/sigs.k8s.io/controller-runtime/pkg/manager/runnable_group.go
generated
vendored
@ -56,7 +56,7 @@ func (r *runnables) Add(fn Runnable) error {
|
|||||||
return r.Caches.Add(fn, func(ctx context.Context) bool {
|
return r.Caches.Add(fn, func(ctx context.Context) bool {
|
||||||
return runnable.GetCache().WaitForCacheSync(ctx)
|
return runnable.GetCache().WaitForCacheSync(ctx)
|
||||||
})
|
})
|
||||||
case *webhook.Server:
|
case webhook.Server:
|
||||||
return r.Webhooks.Add(fn, nil)
|
return r.Webhooks.Add(fn, nil)
|
||||||
case LeaderElectionRunnable:
|
case LeaderElectionRunnable:
|
||||||
if !runnable.NeedLeaderElection() {
|
if !runnable.NeedLeaderElection() {
|
||||||
|
61
vendor/sigs.k8s.io/controller-runtime/pkg/manager/server.go
generated
vendored
Normal file
61
vendor/sigs.k8s.io/controller-runtime/pkg/manager/server.go
generated
vendored
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
/*
|
||||||
|
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 manager
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"net"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/go-logr/logr"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 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
|
||||||
|
Listener net.Listener
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *server) Start(ctx context.Context) error {
|
||||||
|
log := s.Log.WithValues("kind", s.Kind, "addr", s.Listener.Addr())
|
||||||
|
|
||||||
|
serverShutdown := make(chan struct{})
|
||||||
|
go func() {
|
||||||
|
<-ctx.Done()
|
||||||
|
log.Info("shutting down server")
|
||||||
|
if err := s.Server.Shutdown(context.Background()); 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) {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
<-serverShutdown
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *server) NeedLeaderElection() bool {
|
||||||
|
return false
|
||||||
|
}
|
89
vendor/sigs.k8s.io/controller-runtime/pkg/metrics/client_go_adapter.go
generated
vendored
89
vendor/sigs.k8s.io/controller-runtime/pkg/metrics/client_go_adapter.go
generated
vendored
@ -18,8 +18,6 @@ package metrics
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"net/url"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
clientmetrics "k8s.io/client-go/tools/metrics"
|
clientmetrics "k8s.io/client-go/tools/metrics"
|
||||||
@ -29,70 +27,9 @@ import (
|
|||||||
// that client-go registers metrics. We copy the names and formats
|
// that client-go registers metrics. We copy the names and formats
|
||||||
// from Kubernetes so that we match the core controllers.
|
// from Kubernetes so that we match the core controllers.
|
||||||
|
|
||||||
// Metrics subsystem and all of the keys used by the rest client.
|
|
||||||
const (
|
|
||||||
RestClientSubsystem = "rest_client"
|
|
||||||
LatencyKey = "request_latency_seconds"
|
|
||||||
ResultKey = "requests_total"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
var (
|
||||||
// client metrics.
|
// client metrics.
|
||||||
|
|
||||||
// RequestLatency reports the request latency in seconds per verb/URL.
|
|
||||||
// Deprecated: This metric is deprecated for removal in a future release: using the URL as a
|
|
||||||
// dimension results in cardinality explosion for some consumers. It was deprecated upstream
|
|
||||||
// in k8s v1.14 and hidden in v1.17 via https://github.com/kubernetes/kubernetes/pull/83836.
|
|
||||||
// It is not registered by default. To register:
|
|
||||||
// import (
|
|
||||||
// clientmetrics "k8s.io/client-go/tools/metrics"
|
|
||||||
// clmetrics "sigs.k8s.io/controller-runtime/metrics"
|
|
||||||
// )
|
|
||||||
//
|
|
||||||
// func init() {
|
|
||||||
// clmetrics.Registry.MustRegister(clmetrics.RequestLatency)
|
|
||||||
// clientmetrics.Register(clientmetrics.RegisterOpts{
|
|
||||||
// RequestLatency: clmetrics.LatencyAdapter
|
|
||||||
// })
|
|
||||||
// }
|
|
||||||
RequestLatency = prometheus.NewHistogramVec(prometheus.HistogramOpts{
|
|
||||||
Subsystem: RestClientSubsystem,
|
|
||||||
Name: LatencyKey,
|
|
||||||
Help: "Request latency in seconds. Broken down by verb and URL.",
|
|
||||||
Buckets: prometheus.ExponentialBuckets(0.001, 2, 10),
|
|
||||||
}, []string{"verb", "url"})
|
|
||||||
|
|
||||||
// requestLatency is a Prometheus Histogram metric type partitioned by
|
|
||||||
// "verb", and "host" labels. It is used for the rest client latency metrics.
|
|
||||||
requestLatency = prometheus.NewHistogramVec(
|
|
||||||
prometheus.HistogramOpts{
|
|
||||||
Name: "rest_client_request_duration_seconds",
|
|
||||||
Help: "Request latency in seconds. Broken down by verb, and host.",
|
|
||||||
Buckets: []float64{0.005, 0.025, 0.1, 0.25, 0.5, 1.0, 2.0, 4.0, 8.0, 15.0, 30.0, 60.0},
|
|
||||||
},
|
|
||||||
[]string{"verb", "host"},
|
|
||||||
)
|
|
||||||
|
|
||||||
requestSize = prometheus.NewHistogramVec(
|
|
||||||
prometheus.HistogramOpts{
|
|
||||||
Name: "rest_client_request_size_bytes",
|
|
||||||
Help: "Request size in bytes. Broken down by verb and host.",
|
|
||||||
// 64 bytes to 16MB
|
|
||||||
Buckets: []float64{64, 256, 512, 1024, 4096, 16384, 65536, 262144, 1048576, 4194304, 16777216},
|
|
||||||
},
|
|
||||||
[]string{"verb", "host"},
|
|
||||||
)
|
|
||||||
|
|
||||||
responseSize = prometheus.NewHistogramVec(
|
|
||||||
prometheus.HistogramOpts{
|
|
||||||
Name: "rest_client_response_size_bytes",
|
|
||||||
Help: "Response size in bytes. Broken down by verb and host.",
|
|
||||||
// 64 bytes to 16MB
|
|
||||||
Buckets: []float64{64, 256, 512, 1024, 4096, 16384, 65536, 262144, 1048576, 4194304, 16777216},
|
|
||||||
},
|
|
||||||
[]string{"verb", "host"},
|
|
||||||
)
|
|
||||||
|
|
||||||
requestResult = prometheus.NewCounterVec(
|
requestResult = prometheus.NewCounterVec(
|
||||||
prometheus.CounterOpts{
|
prometheus.CounterOpts{
|
||||||
Name: "rest_client_requests_total",
|
Name: "rest_client_requests_total",
|
||||||
@ -109,17 +46,11 @@ func init() {
|
|||||||
// registerClientMetrics sets up the client latency metrics from client-go.
|
// registerClientMetrics sets up the client latency metrics from client-go.
|
||||||
func registerClientMetrics() {
|
func registerClientMetrics() {
|
||||||
// register the metrics with our registry
|
// register the metrics with our registry
|
||||||
Registry.MustRegister(requestLatency)
|
|
||||||
Registry.MustRegister(requestSize)
|
|
||||||
Registry.MustRegister(responseSize)
|
|
||||||
Registry.MustRegister(requestResult)
|
Registry.MustRegister(requestResult)
|
||||||
|
|
||||||
// register the metrics with client-go
|
// register the metrics with client-go
|
||||||
clientmetrics.Register(clientmetrics.RegisterOpts{
|
clientmetrics.Register(clientmetrics.RegisterOpts{
|
||||||
RequestLatency: &LatencyAdapter{metric: requestLatency},
|
RequestResult: &resultAdapter{metric: requestResult},
|
||||||
RequestSize: &sizeAdapter{metric: requestSize},
|
|
||||||
ResponseSize: &sizeAdapter{metric: responseSize},
|
|
||||||
RequestResult: &resultAdapter{metric: requestResult},
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -131,24 +62,6 @@ func registerClientMetrics() {
|
|||||||
// copied (more-or-less directly) from k8s.io/kubernetes setup code
|
// copied (more-or-less directly) from k8s.io/kubernetes setup code
|
||||||
// (which isn't anywhere in an easily-importable place).
|
// (which isn't anywhere in an easily-importable place).
|
||||||
|
|
||||||
// LatencyAdapter implements LatencyMetric.
|
|
||||||
type LatencyAdapter struct {
|
|
||||||
metric *prometheus.HistogramVec
|
|
||||||
}
|
|
||||||
|
|
||||||
// Observe increments the request latency metric for the given verb/URL.
|
|
||||||
func (l *LatencyAdapter) Observe(_ context.Context, verb string, u url.URL, latency time.Duration) {
|
|
||||||
l.metric.WithLabelValues(verb, u.String()).Observe(latency.Seconds())
|
|
||||||
}
|
|
||||||
|
|
||||||
type sizeAdapter struct {
|
|
||||||
metric *prometheus.HistogramVec
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *sizeAdapter) Observe(ctx context.Context, verb string, host string, size float64) {
|
|
||||||
s.metric.WithLabelValues(verb, host).Observe(size)
|
|
||||||
}
|
|
||||||
|
|
||||||
type resultAdapter struct {
|
type resultAdapter struct {
|
||||||
metric *prometheus.CounterVec
|
metric *prometheus.CounterVec
|
||||||
}
|
}
|
||||||
|
23
vendor/sigs.k8s.io/controller-runtime/pkg/predicate/predicate.go
generated
vendored
23
vendor/sigs.k8s.io/controller-runtime/pkg/predicate/predicate.go
generated
vendored
@ -24,7 +24,6 @@ import (
|
|||||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||||
"sigs.k8s.io/controller-runtime/pkg/event"
|
"sigs.k8s.io/controller-runtime/pkg/event"
|
||||||
logf "sigs.k8s.io/controller-runtime/pkg/internal/log"
|
logf "sigs.k8s.io/controller-runtime/pkg/internal/log"
|
||||||
"sigs.k8s.io/controller-runtime/pkg/runtime/inject"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var log = logf.RuntimeLog.WithName("predicate").WithName("eventFilters")
|
var log = logf.RuntimeLog.WithName("predicate").WithName("eventFilters")
|
||||||
@ -242,15 +241,6 @@ type and struct {
|
|||||||
predicates []Predicate
|
predicates []Predicate
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a and) InjectFunc(f inject.Func) error {
|
|
||||||
for _, p := range a.predicates {
|
|
||||||
if err := f(p); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a and) Create(e event.CreateEvent) bool {
|
func (a and) Create(e event.CreateEvent) bool {
|
||||||
for _, p := range a.predicates {
|
for _, p := range a.predicates {
|
||||||
if !p.Create(e) {
|
if !p.Create(e) {
|
||||||
@ -296,15 +286,6 @@ type or struct {
|
|||||||
predicates []Predicate
|
predicates []Predicate
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o or) InjectFunc(f inject.Func) error {
|
|
||||||
for _, p := range o.predicates {
|
|
||||||
if err := f(p); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (o or) Create(e event.CreateEvent) bool {
|
func (o or) Create(e event.CreateEvent) bool {
|
||||||
for _, p := range o.predicates {
|
for _, p := range o.predicates {
|
||||||
if p.Create(e) {
|
if p.Create(e) {
|
||||||
@ -350,10 +331,6 @@ type not struct {
|
|||||||
predicate Predicate
|
predicate Predicate
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n not) InjectFunc(f inject.Func) error {
|
|
||||||
return f(n.predicate)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (n not) Create(e event.CreateEvent) bool {
|
func (n not) Create(e event.CreateEvent) bool {
|
||||||
return !n.predicate.Create(e)
|
return !n.predicate.Create(e)
|
||||||
}
|
}
|
||||||
|
24
vendor/sigs.k8s.io/controller-runtime/pkg/reconcile/reconcile.go
generated
vendored
24
vendor/sigs.k8s.io/controller-runtime/pkg/reconcile/reconcile.go
generated
vendored
@ -18,6 +18,7 @@ package reconcile
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"k8s.io/apimachinery/pkg/types"
|
"k8s.io/apimachinery/pkg/types"
|
||||||
@ -100,3 +101,26 @@ var _ Reconciler = Func(nil)
|
|||||||
|
|
||||||
// Reconcile implements Reconciler.
|
// Reconcile implements Reconciler.
|
||||||
func (r Func) Reconcile(ctx context.Context, o Request) (Result, error) { return r(ctx, o) }
|
func (r Func) Reconcile(ctx context.Context, o Request) (Result, error) { return r(ctx, o) }
|
||||||
|
|
||||||
|
// TerminalError is an error that will not be retried but still be logged
|
||||||
|
// and recorded in metrics.
|
||||||
|
func TerminalError(wrapped error) error {
|
||||||
|
return &terminalError{err: wrapped}
|
||||||
|
}
|
||||||
|
|
||||||
|
type terminalError struct {
|
||||||
|
err error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (te *terminalError) Unwrap() error {
|
||||||
|
return te.err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (te *terminalError) Error() string {
|
||||||
|
return "terminal error: " + te.err.Error()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (te *terminalError) Is(target error) bool {
|
||||||
|
tp := &terminalError{}
|
||||||
|
return errors.As(target, &tp)
|
||||||
|
}
|
||||||
|
22
vendor/sigs.k8s.io/controller-runtime/pkg/runtime/inject/doc.go
generated
vendored
22
vendor/sigs.k8s.io/controller-runtime/pkg/runtime/inject/doc.go
generated
vendored
@ -1,22 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright 2018 The Kubernetes Authors.
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
Package inject defines interfaces and functions for propagating dependencies from a ControllerManager to
|
|
||||||
the components registered with it. Dependencies are propagated to Reconciler, Source, EventHandler and Predicate
|
|
||||||
objects which implement the Injectable interfaces.
|
|
||||||
*/
|
|
||||||
package inject
|
|
164
vendor/sigs.k8s.io/controller-runtime/pkg/runtime/inject/inject.go
generated
vendored
164
vendor/sigs.k8s.io/controller-runtime/pkg/runtime/inject/inject.go
generated
vendored
@ -1,164 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright 2018 The Kubernetes Authors.
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Package inject is used by a Manager to inject types into Sources, EventHandlers, Predicates, and Reconciles.
|
|
||||||
// Deprecated: Use manager.Options fields directly. This package will be removed in v0.10.
|
|
||||||
package inject
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/go-logr/logr"
|
|
||||||
"k8s.io/apimachinery/pkg/api/meta"
|
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
|
||||||
"k8s.io/client-go/rest"
|
|
||||||
|
|
||||||
"sigs.k8s.io/controller-runtime/pkg/cache"
|
|
||||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Cache is used by the ControllerManager to inject Cache into Sources, EventHandlers, Predicates, and
|
|
||||||
// Reconciles.
|
|
||||||
type Cache interface {
|
|
||||||
InjectCache(cache cache.Cache) error
|
|
||||||
}
|
|
||||||
|
|
||||||
// CacheInto will set informers on i and return the result if it implements Cache. Returns
|
|
||||||
// false if i does not implement Cache.
|
|
||||||
func CacheInto(c cache.Cache, i interface{}) (bool, error) {
|
|
||||||
if s, ok := i.(Cache); ok {
|
|
||||||
return true, s.InjectCache(c)
|
|
||||||
}
|
|
||||||
return false, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// APIReader is used by the Manager to inject the APIReader into necessary types.
|
|
||||||
type APIReader interface {
|
|
||||||
InjectAPIReader(client.Reader) error
|
|
||||||
}
|
|
||||||
|
|
||||||
// APIReaderInto will set APIReader on i and return the result if it implements APIReaderInto.
|
|
||||||
// Returns false if i does not implement APIReader.
|
|
||||||
func APIReaderInto(reader client.Reader, i interface{}) (bool, error) {
|
|
||||||
if s, ok := i.(APIReader); ok {
|
|
||||||
return true, s.InjectAPIReader(reader)
|
|
||||||
}
|
|
||||||
return false, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Config is used by the ControllerManager to inject Config into Sources, EventHandlers, Predicates, and
|
|
||||||
// Reconciles.
|
|
||||||
type Config interface {
|
|
||||||
InjectConfig(*rest.Config) error
|
|
||||||
}
|
|
||||||
|
|
||||||
// ConfigInto will set config on i and return the result if it implements Config. Returns
|
|
||||||
// false if i does not implement Config.
|
|
||||||
func ConfigInto(config *rest.Config, i interface{}) (bool, error) {
|
|
||||||
if s, ok := i.(Config); ok {
|
|
||||||
return true, s.InjectConfig(config)
|
|
||||||
}
|
|
||||||
return false, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Client is used by the ControllerManager to inject client into Sources, EventHandlers, Predicates, and
|
|
||||||
// Reconciles.
|
|
||||||
type Client interface {
|
|
||||||
InjectClient(client.Client) error
|
|
||||||
}
|
|
||||||
|
|
||||||
// ClientInto will set client on i and return the result if it implements Client. Returns
|
|
||||||
// false if i does not implement Client.
|
|
||||||
func ClientInto(client client.Client, i interface{}) (bool, error) {
|
|
||||||
if s, ok := i.(Client); ok {
|
|
||||||
return true, s.InjectClient(client)
|
|
||||||
}
|
|
||||||
return false, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Scheme is used by the ControllerManager to inject Scheme into Sources, EventHandlers, Predicates, and
|
|
||||||
// Reconciles.
|
|
||||||
type Scheme interface {
|
|
||||||
InjectScheme(scheme *runtime.Scheme) error
|
|
||||||
}
|
|
||||||
|
|
||||||
// SchemeInto will set scheme and return the result on i if it implements Scheme. Returns
|
|
||||||
// false if i does not implement Scheme.
|
|
||||||
func SchemeInto(scheme *runtime.Scheme, i interface{}) (bool, error) {
|
|
||||||
if is, ok := i.(Scheme); ok {
|
|
||||||
return true, is.InjectScheme(scheme)
|
|
||||||
}
|
|
||||||
return false, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Stoppable is used by the ControllerManager to inject stop channel into Sources,
|
|
||||||
// EventHandlers, Predicates, and Reconciles.
|
|
||||||
type Stoppable interface {
|
|
||||||
InjectStopChannel(<-chan struct{}) error
|
|
||||||
}
|
|
||||||
|
|
||||||
// StopChannelInto will set stop channel on i and return the result if it implements Stoppable.
|
|
||||||
// Returns false if i does not implement Stoppable.
|
|
||||||
func StopChannelInto(stop <-chan struct{}, i interface{}) (bool, error) {
|
|
||||||
if s, ok := i.(Stoppable); ok {
|
|
||||||
return true, s.InjectStopChannel(stop)
|
|
||||||
}
|
|
||||||
return false, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Mapper is used to inject the rest mapper to components that may need it.
|
|
||||||
type Mapper interface {
|
|
||||||
InjectMapper(meta.RESTMapper) error
|
|
||||||
}
|
|
||||||
|
|
||||||
// MapperInto will set the rest mapper on i and return the result if it implements Mapper.
|
|
||||||
// Returns false if i does not implement Mapper.
|
|
||||||
func MapperInto(mapper meta.RESTMapper, i interface{}) (bool, error) {
|
|
||||||
if m, ok := i.(Mapper); ok {
|
|
||||||
return true, m.InjectMapper(mapper)
|
|
||||||
}
|
|
||||||
return false, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Func injects dependencies into i.
|
|
||||||
type Func func(i interface{}) error
|
|
||||||
|
|
||||||
// Injector is used by the ControllerManager to inject Func into Controllers.
|
|
||||||
type Injector interface {
|
|
||||||
InjectFunc(f Func) error
|
|
||||||
}
|
|
||||||
|
|
||||||
// InjectorInto will set f and return the result on i if it implements Injector. Returns
|
|
||||||
// false if i does not implement Injector.
|
|
||||||
func InjectorInto(f Func, i interface{}) (bool, error) {
|
|
||||||
if ii, ok := i.(Injector); ok {
|
|
||||||
return true, ii.InjectFunc(f)
|
|
||||||
}
|
|
||||||
return false, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Logger is used to inject Loggers into components that need them
|
|
||||||
// and don't otherwise have opinions.
|
|
||||||
type Logger interface {
|
|
||||||
InjectLogger(l logr.Logger) error
|
|
||||||
}
|
|
||||||
|
|
||||||
// LoggerInto will set the logger on the given object if it implements inject.Logger,
|
|
||||||
// returning true if a InjectLogger was called, and false otherwise.
|
|
||||||
func LoggerInto(l logr.Logger, i interface{}) (bool, error) {
|
|
||||||
if injectable, wantsLogger := i.(Logger); wantsLogger {
|
|
||||||
return true, injectable.InjectLogger(l)
|
|
||||||
}
|
|
||||||
return false, nil
|
|
||||||
}
|
|
183
vendor/sigs.k8s.io/controller-runtime/pkg/source/source.go
generated
vendored
183
vendor/sigs.k8s.io/controller-runtime/pkg/source/source.go
generated
vendored
@ -18,28 +18,19 @@ package source
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
|
||||||
|
|
||||||
"k8s.io/apimachinery/pkg/api/meta"
|
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
|
||||||
"k8s.io/apimachinery/pkg/util/wait"
|
|
||||||
"k8s.io/client-go/util/workqueue"
|
"k8s.io/client-go/util/workqueue"
|
||||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||||
"sigs.k8s.io/controller-runtime/pkg/event"
|
"sigs.k8s.io/controller-runtime/pkg/event"
|
||||||
"sigs.k8s.io/controller-runtime/pkg/handler"
|
"sigs.k8s.io/controller-runtime/pkg/handler"
|
||||||
logf "sigs.k8s.io/controller-runtime/pkg/internal/log"
|
internal "sigs.k8s.io/controller-runtime/pkg/internal/source"
|
||||||
"sigs.k8s.io/controller-runtime/pkg/runtime/inject"
|
|
||||||
"sigs.k8s.io/controller-runtime/pkg/source/internal"
|
|
||||||
|
|
||||||
"sigs.k8s.io/controller-runtime/pkg/cache"
|
"sigs.k8s.io/controller-runtime/pkg/cache"
|
||||||
"sigs.k8s.io/controller-runtime/pkg/predicate"
|
"sigs.k8s.io/controller-runtime/pkg/predicate"
|
||||||
)
|
)
|
||||||
|
|
||||||
var log = logf.RuntimeLog.WithName("source")
|
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// defaultBufferSize is the default number of event notifications that can be buffered.
|
// defaultBufferSize is the default number of event notifications that can be buffered.
|
||||||
defaultBufferSize = 1024
|
defaultBufferSize = 1024
|
||||||
@ -52,8 +43,7 @@ const (
|
|||||||
//
|
//
|
||||||
// * Use Channel for events originating outside the cluster (eh.g. GitHub Webhook callback, Polling external urls).
|
// * Use Channel for events originating outside the cluster (eh.g. GitHub Webhook callback, Polling external urls).
|
||||||
//
|
//
|
||||||
// Users may build their own Source implementations. If their implementations implement any of the inject package
|
// Users may build their own Source implementations.
|
||||||
// interfaces, the dependencies will be injected by the Controller when Watch is called.
|
|
||||||
type Source interface {
|
type Source interface {
|
||||||
// Start is internal and should be called only by the Controller to register an EventHandler with the Informer
|
// Start is internal and should be called only by the Controller to register an EventHandler with the Informer
|
||||||
// to enqueue reconcile.Requests.
|
// to enqueue reconcile.Requests.
|
||||||
@ -67,144 +57,9 @@ type SyncingSource interface {
|
|||||||
WaitForSync(ctx context.Context) error
|
WaitForSync(ctx context.Context) error
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewKindWithCache creates a Source without InjectCache, so that it is assured that the given cache is used
|
// Kind creates a KindSource with the given cache provider.
|
||||||
// and not overwritten. It can be used to watch objects in a different cluster by passing the cache
|
func Kind(cache cache.Cache, object client.Object) SyncingSource {
|
||||||
// from that other cluster.
|
return &internal.Kind{Type: object, Cache: cache}
|
||||||
func NewKindWithCache(object client.Object, cache cache.Cache) SyncingSource {
|
|
||||||
return &kindWithCache{kind: Kind{Type: object, cache: cache}}
|
|
||||||
}
|
|
||||||
|
|
||||||
type kindWithCache struct {
|
|
||||||
kind Kind
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ks *kindWithCache) Start(ctx context.Context, handler handler.EventHandler, queue workqueue.RateLimitingInterface,
|
|
||||||
prct ...predicate.Predicate) error {
|
|
||||||
return ks.kind.Start(ctx, handler, queue, prct...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ks *kindWithCache) String() string {
|
|
||||||
return ks.kind.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ks *kindWithCache) WaitForSync(ctx context.Context) error {
|
|
||||||
return ks.kind.WaitForSync(ctx)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Kind is used to provide a source of events originating inside the cluster from Watches (e.g. Pod Create).
|
|
||||||
type Kind struct {
|
|
||||||
// Type is the type of object to watch. e.g. &v1.Pod{}
|
|
||||||
Type client.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
|
|
||||||
// contain an error, startup and syncing finished.
|
|
||||||
started chan error
|
|
||||||
startCancel func()
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ SyncingSource = &Kind{}
|
|
||||||
|
|
||||||
// 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 {
|
|
||||||
// Type should have been specified by the user.
|
|
||||||
if ks.Type == nil {
|
|
||||||
return fmt.Errorf("must specify Kind.Type")
|
|
||||||
}
|
|
||||||
|
|
||||||
// cache should have been injected before Start was called
|
|
||||||
if ks.cache == nil {
|
|
||||||
return fmt.Errorf("must call CacheInto on Kind before calling Start")
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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)
|
|
||||||
go func() {
|
|
||||||
var (
|
|
||||||
i cache.Informer
|
|
||||||
lastErr error
|
|
||||||
)
|
|
||||||
|
|
||||||
// Tries to get an informer until it returns true,
|
|
||||||
// an error or the specified context is cancelled or expired.
|
|
||||||
if err := wait.PollImmediateUntilWithContext(ctx, 10*time.Second, func(ctx context.Context) (bool, error) {
|
|
||||||
// Lookup the Informer from the Cache and add an EventHandler which populates the Queue
|
|
||||||
i, lastErr = ks.cache.GetInformer(ctx, ks.Type)
|
|
||||||
if lastErr != nil {
|
|
||||||
kindMatchErr := &meta.NoKindMatchError{}
|
|
||||||
switch {
|
|
||||||
case errors.As(lastErr, &kindMatchErr):
|
|
||||||
log.Error(lastErr, "if kind is a CRD, it should be installed before calling Start",
|
|
||||||
"kind", kindMatchErr.GroupKind)
|
|
||||||
case runtime.IsNotRegisteredError(lastErr):
|
|
||||||
log.Error(lastErr, "kind must be registered to the Scheme")
|
|
||||||
default:
|
|
||||||
log.Error(lastErr, "failed to get informer from cache")
|
|
||||||
}
|
|
||||||
return false, nil // Retry.
|
|
||||||
}
|
|
||||||
return true, nil
|
|
||||||
}); err != nil {
|
|
||||||
if lastErr != nil {
|
|
||||||
ks.started <- fmt.Errorf("failed to get informer from cache: %w", lastErr)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
ks.started <- err
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err := i.AddEventHandler(internal.EventHandler{Queue: queue, EventHandler: handler, Predicates: prct})
|
|
||||||
if err != nil {
|
|
||||||
ks.started <- err
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if !ks.cache.WaitForCacheSync(ctx) {
|
|
||||||
// Would be great to return something more informative here
|
|
||||||
ks.started <- errors.New("cache did not sync")
|
|
||||||
}
|
|
||||||
close(ks.started)
|
|
||||||
}()
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ks *Kind) String() string {
|
|
||||||
if ks.Type != nil {
|
|
||||||
return fmt.Sprintf("kind source: %T", ks.Type)
|
|
||||||
}
|
|
||||||
return "kind source: unknown type"
|
|
||||||
}
|
|
||||||
|
|
||||||
// WaitForSync implements SyncingSource to allow controllers to wait with starting
|
|
||||||
// workers until the cache is synced.
|
|
||||||
func (ks *Kind) WaitForSync(ctx context.Context) error {
|
|
||||||
select {
|
|
||||||
case err := <-ks.started:
|
|
||||||
return err
|
|
||||||
case <-ctx.Done():
|
|
||||||
ks.startCancel()
|
|
||||||
if errors.Is(ctx.Err(), context.Canceled) {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return errors.New("timed out waiting for cache to be synced")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ inject.Cache = &Kind{}
|
|
||||||
|
|
||||||
// InjectCache is internal should be called only by the Controller. InjectCache is used to inject
|
|
||||||
// the Cache dependency initialized by the ControllerManager.
|
|
||||||
func (ks *Kind) InjectCache(c cache.Cache) error {
|
|
||||||
if ks.cache == nil {
|
|
||||||
ks.cache = c
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ Source = &Channel{}
|
var _ Source = &Channel{}
|
||||||
@ -219,9 +74,6 @@ type Channel struct {
|
|||||||
// Source is the source channel to fetch GenericEvents
|
// Source is the source channel to fetch GenericEvents
|
||||||
Source <-chan event.GenericEvent
|
Source <-chan event.GenericEvent
|
||||||
|
|
||||||
// stop is to end ongoing goroutine, and close the channels
|
|
||||||
stop <-chan struct{}
|
|
||||||
|
|
||||||
// dest is the destination channels of the added event handlers
|
// dest is the destination channels of the added event handlers
|
||||||
dest []chan event.GenericEvent
|
dest []chan event.GenericEvent
|
||||||
|
|
||||||
@ -237,18 +89,6 @@ func (cs *Channel) String() string {
|
|||||||
return fmt.Sprintf("channel source: %p", cs)
|
return fmt.Sprintf("channel source: %p", cs)
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ inject.Stoppable = &Channel{}
|
|
||||||
|
|
||||||
// InjectStopChannel is internal should be called only by the Controller.
|
|
||||||
// It is used to inject the stop channel initialized by the ControllerManager.
|
|
||||||
func (cs *Channel) InjectStopChannel(stop <-chan struct{}) error {
|
|
||||||
if cs.stop == nil {
|
|
||||||
cs.stop = stop
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Start implements Source and should only be called by the Controller.
|
// Start implements Source and should only be called by the Controller.
|
||||||
func (cs *Channel) Start(
|
func (cs *Channel) Start(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
@ -260,11 +100,6 @@ func (cs *Channel) Start(
|
|||||||
return fmt.Errorf("must specify Channel.Source")
|
return fmt.Errorf("must specify Channel.Source")
|
||||||
}
|
}
|
||||||
|
|
||||||
// stop should have been injected before Start was called
|
|
||||||
if cs.stop == nil {
|
|
||||||
return fmt.Errorf("must call InjectStop on Channel before calling Start")
|
|
||||||
}
|
|
||||||
|
|
||||||
// use default value if DestBufferSize not specified
|
// use default value if DestBufferSize not specified
|
||||||
if cs.DestBufferSize == 0 {
|
if cs.DestBufferSize == 0 {
|
||||||
cs.DestBufferSize = defaultBufferSize
|
cs.DestBufferSize = defaultBufferSize
|
||||||
@ -292,7 +127,11 @@ func (cs *Channel) Start(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if shouldHandle {
|
if shouldHandle {
|
||||||
handler.Generic(evt, queue)
|
func() {
|
||||||
|
ctx, cancel := context.WithCancel(ctx)
|
||||||
|
defer cancel()
|
||||||
|
handler.Generic(ctx, evt, queue)
|
||||||
|
}()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
@ -359,7 +198,7 @@ func (is *Informer) Start(ctx context.Context, handler handler.EventHandler, que
|
|||||||
return fmt.Errorf("must specify Informer.Informer")
|
return fmt.Errorf("must specify Informer.Informer")
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err := is.Informer.AddEventHandler(internal.EventHandler{Queue: queue, EventHandler: handler, Predicates: prct})
|
_, err := is.Informer.AddEventHandler(internal.NewEventHandler(ctx, queue, handler, prct).HandlerFuncs())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
16
vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/decode.go
generated
vendored
16
vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/decode.go
generated
vendored
@ -19,7 +19,6 @@ package admission
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
"k8s.io/apimachinery/pkg/runtime/serializer"
|
"k8s.io/apimachinery/pkg/runtime/serializer"
|
||||||
"k8s.io/apimachinery/pkg/util/json"
|
"k8s.io/apimachinery/pkg/util/json"
|
||||||
@ -32,8 +31,11 @@ type Decoder struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NewDecoder creates a Decoder given the runtime.Scheme.
|
// NewDecoder creates a Decoder given the runtime.Scheme.
|
||||||
func NewDecoder(scheme *runtime.Scheme) (*Decoder, error) {
|
func NewDecoder(scheme *runtime.Scheme) *Decoder {
|
||||||
return &Decoder{codecs: serializer.NewCodecFactory(scheme)}, nil
|
if scheme == nil {
|
||||||
|
panic("scheme should never be nil")
|
||||||
|
}
|
||||||
|
return &Decoder{codecs: serializer.NewCodecFactory(scheme)}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Decode decodes the inlined object in the AdmissionRequest into the passed-in runtime.Object.
|
// Decode decodes the inlined object in the AdmissionRequest into the passed-in runtime.Object.
|
||||||
@ -62,9 +64,13 @@ func (d *Decoder) DecodeRaw(rawObj runtime.RawExtension, into runtime.Object) er
|
|||||||
if len(rawObj.Raw) == 0 {
|
if len(rawObj.Raw) == 0 {
|
||||||
return fmt.Errorf("there is no content to decode")
|
return fmt.Errorf("there is no content to decode")
|
||||||
}
|
}
|
||||||
if unstructuredInto, isUnstructured := into.(*unstructured.Unstructured); isUnstructured {
|
if unstructuredInto, isUnstructured := into.(runtime.Unstructured); isUnstructured {
|
||||||
// unmarshal into unstructured's underlying object to avoid calling the decoder
|
// unmarshal into unstructured's underlying object to avoid calling the decoder
|
||||||
return json.Unmarshal(rawObj.Raw, &unstructuredInto.Object)
|
var object map[string]interface{}
|
||||||
|
if err := json.Unmarshal(rawObj.Raw, &object); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
unstructuredInto.SetUnstructuredContent(object)
|
||||||
}
|
}
|
||||||
|
|
||||||
deserializer := d.codecs.UniversalDeserializer()
|
deserializer := d.codecs.UniversalDeserializer()
|
||||||
|
15
vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/defaulter.go
generated
vendored
15
vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/defaulter.go
generated
vendored
@ -33,9 +33,9 @@ type Defaulter interface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// DefaultingWebhookFor creates a new Webhook for Defaulting the provided type.
|
// DefaultingWebhookFor creates a new Webhook for Defaulting the provided type.
|
||||||
func DefaultingWebhookFor(defaulter Defaulter) *Webhook {
|
func DefaultingWebhookFor(scheme *runtime.Scheme, defaulter Defaulter) *Webhook {
|
||||||
return &Webhook{
|
return &Webhook{
|
||||||
Handler: &mutatingHandler{defaulter: defaulter},
|
Handler: &mutatingHandler{defaulter: defaulter, decoder: NewDecoder(scheme)},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -44,16 +44,11 @@ type mutatingHandler struct {
|
|||||||
decoder *Decoder
|
decoder *Decoder
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ DecoderInjector = &mutatingHandler{}
|
|
||||||
|
|
||||||
// InjectDecoder injects the decoder into a mutatingHandler.
|
|
||||||
func (h *mutatingHandler) InjectDecoder(d *Decoder) error {
|
|
||||||
h.decoder = d
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle handles admission requests.
|
// Handle handles admission requests.
|
||||||
func (h *mutatingHandler) Handle(ctx context.Context, req Request) Response {
|
func (h *mutatingHandler) Handle(ctx context.Context, req Request) Response {
|
||||||
|
if h.decoder == nil {
|
||||||
|
panic("decoder should never be nil")
|
||||||
|
}
|
||||||
if h.defaulter == nil {
|
if h.defaulter == nil {
|
||||||
panic("defaulter should never be nil")
|
panic("defaulter should never be nil")
|
||||||
}
|
}
|
||||||
|
14
vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/defaulter_custom.go
generated
vendored
14
vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/defaulter_custom.go
generated
vendored
@ -34,9 +34,9 @@ type CustomDefaulter interface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// WithCustomDefaulter creates a new Webhook for a CustomDefaulter interface.
|
// WithCustomDefaulter creates a new Webhook for a CustomDefaulter interface.
|
||||||
func WithCustomDefaulter(obj runtime.Object, defaulter CustomDefaulter) *Webhook {
|
func WithCustomDefaulter(scheme *runtime.Scheme, obj runtime.Object, defaulter CustomDefaulter) *Webhook {
|
||||||
return &Webhook{
|
return &Webhook{
|
||||||
Handler: &defaulterForType{object: obj, defaulter: defaulter},
|
Handler: &defaulterForType{object: obj, defaulter: defaulter, decoder: NewDecoder(scheme)},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -46,15 +46,11 @@ type defaulterForType struct {
|
|||||||
decoder *Decoder
|
decoder *Decoder
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ DecoderInjector = &defaulterForType{}
|
|
||||||
|
|
||||||
func (h *defaulterForType) InjectDecoder(d *Decoder) error {
|
|
||||||
h.decoder = d
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle handles admission requests.
|
// Handle handles admission requests.
|
||||||
func (h *defaulterForType) Handle(ctx context.Context, req Request) Response {
|
func (h *defaulterForType) Handle(ctx context.Context, req Request) Response {
|
||||||
|
if h.decoder == nil {
|
||||||
|
panic("decoder should never be nil")
|
||||||
|
}
|
||||||
if h.defaulter == nil {
|
if h.defaulter == nil {
|
||||||
panic("defaulter should never be nil")
|
panic("defaulter should never be nil")
|
||||||
}
|
}
|
||||||
|
6
vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/doc.go
generated
vendored
6
vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/doc.go
generated
vendored
@ -20,9 +20,3 @@ Package admission provides implementation for admission webhook and methods to i
|
|||||||
See examples/mutatingwebhook.go and examples/validatingwebhook.go for examples of admission webhooks.
|
See examples/mutatingwebhook.go and examples/validatingwebhook.go for examples of admission webhooks.
|
||||||
*/
|
*/
|
||||||
package admission
|
package admission
|
||||||
|
|
||||||
import (
|
|
||||||
logf "sigs.k8s.io/controller-runtime/pkg/internal/log"
|
|
||||||
)
|
|
||||||
|
|
||||||
var log = logf.RuntimeLog.WithName("admission")
|
|
||||||
|
20
vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/http.go
generated
vendored
20
vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/http.go
generated
vendored
@ -52,7 +52,7 @@ func (wh *Webhook) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|||||||
var reviewResponse Response
|
var reviewResponse Response
|
||||||
if r.Body == nil {
|
if r.Body == nil {
|
||||||
err = errors.New("request body is empty")
|
err = errors.New("request body is empty")
|
||||||
wh.log.Error(err, "bad request")
|
wh.getLogger(nil).Error(err, "bad request")
|
||||||
reviewResponse = Errored(http.StatusBadRequest, err)
|
reviewResponse = Errored(http.StatusBadRequest, err)
|
||||||
wh.writeResponse(w, reviewResponse)
|
wh.writeResponse(w, reviewResponse)
|
||||||
return
|
return
|
||||||
@ -60,7 +60,7 @@ func (wh *Webhook) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|||||||
|
|
||||||
defer r.Body.Close()
|
defer r.Body.Close()
|
||||||
if body, err = io.ReadAll(r.Body); err != nil {
|
if body, err = io.ReadAll(r.Body); err != nil {
|
||||||
wh.log.Error(err, "unable to read the body from the incoming request")
|
wh.getLogger(nil).Error(err, "unable to read the body from the incoming request")
|
||||||
reviewResponse = Errored(http.StatusBadRequest, err)
|
reviewResponse = Errored(http.StatusBadRequest, err)
|
||||||
wh.writeResponse(w, reviewResponse)
|
wh.writeResponse(w, reviewResponse)
|
||||||
return
|
return
|
||||||
@ -69,7 +69,7 @@ func (wh *Webhook) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|||||||
// verify the content type is accurate
|
// verify the content type is accurate
|
||||||
if contentType := r.Header.Get("Content-Type"); contentType != "application/json" {
|
if contentType := r.Header.Get("Content-Type"); contentType != "application/json" {
|
||||||
err = fmt.Errorf("contentType=%s, expected application/json", contentType)
|
err = fmt.Errorf("contentType=%s, expected application/json", contentType)
|
||||||
wh.log.Error(err, "unable to process a request with an unknown content type", "content type", contentType)
|
wh.getLogger(nil).Error(err, "unable to process a request with unknown content type")
|
||||||
reviewResponse = Errored(http.StatusBadRequest, err)
|
reviewResponse = Errored(http.StatusBadRequest, err)
|
||||||
wh.writeResponse(w, reviewResponse)
|
wh.writeResponse(w, reviewResponse)
|
||||||
return
|
return
|
||||||
@ -88,12 +88,12 @@ func (wh *Webhook) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|||||||
ar.SetGroupVersionKind(v1.SchemeGroupVersion.WithKind("AdmissionReview"))
|
ar.SetGroupVersionKind(v1.SchemeGroupVersion.WithKind("AdmissionReview"))
|
||||||
_, actualAdmRevGVK, err := admissionCodecs.UniversalDeserializer().Decode(body, nil, &ar)
|
_, actualAdmRevGVK, err := admissionCodecs.UniversalDeserializer().Decode(body, nil, &ar)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
wh.log.Error(err, "unable to decode the request")
|
wh.getLogger(nil).Error(err, "unable to decode the request")
|
||||||
reviewResponse = Errored(http.StatusBadRequest, err)
|
reviewResponse = Errored(http.StatusBadRequest, err)
|
||||||
wh.writeResponse(w, reviewResponse)
|
wh.writeResponse(w, reviewResponse)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
wh.log.V(1).Info("received request", "UID", req.UID, "kind", req.Kind, "resource", req.Resource)
|
wh.getLogger(&req).V(4).Info("received request")
|
||||||
|
|
||||||
reviewResponse = wh.Handle(ctx, req)
|
reviewResponse = wh.Handle(ctx, req)
|
||||||
wh.writeResponseTyped(w, reviewResponse, actualAdmRevGVK)
|
wh.writeResponseTyped(w, reviewResponse, actualAdmRevGVK)
|
||||||
@ -124,7 +124,7 @@ func (wh *Webhook) writeResponseTyped(w io.Writer, response Response, admRevGVK
|
|||||||
// writeAdmissionResponse writes ar to w.
|
// writeAdmissionResponse writes ar to w.
|
||||||
func (wh *Webhook) writeAdmissionResponse(w io.Writer, ar v1.AdmissionReview) {
|
func (wh *Webhook) writeAdmissionResponse(w io.Writer, ar v1.AdmissionReview) {
|
||||||
if err := json.NewEncoder(w).Encode(ar); err != nil {
|
if err := json.NewEncoder(w).Encode(ar); err != nil {
|
||||||
wh.log.Error(err, "unable to encode and write the response")
|
wh.getLogger(nil).Error(err, "unable to encode and write the response")
|
||||||
// Since the `ar v1.AdmissionReview` is a clear and legal object,
|
// Since the `ar v1.AdmissionReview` is a clear and legal object,
|
||||||
// it should not have problem to be marshalled into bytes.
|
// it should not have problem to be marshalled into bytes.
|
||||||
// The error here is probably caused by the abnormal HTTP connection,
|
// The error here is probably caused by the abnormal HTTP connection,
|
||||||
@ -132,15 +132,15 @@ func (wh *Webhook) writeAdmissionResponse(w io.Writer, ar v1.AdmissionReview) {
|
|||||||
// to avoid endless circular calling.
|
// to avoid endless circular calling.
|
||||||
serverError := Errored(http.StatusInternalServerError, err)
|
serverError := Errored(http.StatusInternalServerError, err)
|
||||||
if err = json.NewEncoder(w).Encode(v1.AdmissionReview{Response: &serverError.AdmissionResponse}); err != nil {
|
if err = json.NewEncoder(w).Encode(v1.AdmissionReview{Response: &serverError.AdmissionResponse}); err != nil {
|
||||||
wh.log.Error(err, "still unable to encode and write the InternalServerError response")
|
wh.getLogger(nil).Error(err, "still unable to encode and write the InternalServerError response")
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
res := ar.Response
|
res := ar.Response
|
||||||
if log := wh.log; log.V(1).Enabled() {
|
if log := wh.getLogger(nil); log.V(4).Enabled() {
|
||||||
if res.Result != nil {
|
if res.Result != nil {
|
||||||
log = log.WithValues("code", res.Result.Code, "reason", res.Result.Reason)
|
log = log.WithValues("code", res.Result.Code, "reason", res.Result.Reason, "message", res.Result.Message)
|
||||||
}
|
}
|
||||||
log.V(1).Info("wrote response", "UID", res.UID, "allowed", res.Allowed)
|
log.V(4).Info("wrote response", "requestID", res.UID, "allowed", res.Allowed)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
31
vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/inject.go
generated
vendored
31
vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/inject.go
generated
vendored
@ -1,31 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright 2019 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 admission
|
|
||||||
|
|
||||||
// DecoderInjector is used by the ControllerManager to inject decoder into webhook handlers.
|
|
||||||
type DecoderInjector interface {
|
|
||||||
InjectDecoder(*Decoder) error
|
|
||||||
}
|
|
||||||
|
|
||||||
// InjectDecoderInto will set decoder on i and return the result if it implements Decoder. Returns
|
|
||||||
// false if i does not implement Decoder.
|
|
||||||
func InjectDecoderInto(decoder *Decoder, i interface{}) (bool, error) {
|
|
||||||
if s, ok := i.(DecoderInjector); ok {
|
|
||||||
return true, s.InjectDecoder(decoder)
|
|
||||||
}
|
|
||||||
return false, nil
|
|
||||||
}
|
|
52
vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/multi.go
generated
vendored
52
vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/multi.go
generated
vendored
@ -25,8 +25,6 @@ import (
|
|||||||
jsonpatch "gomodules.xyz/jsonpatch/v2"
|
jsonpatch "gomodules.xyz/jsonpatch/v2"
|
||||||
admissionv1 "k8s.io/api/admission/v1"
|
admissionv1 "k8s.io/api/admission/v1"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
|
||||||
"sigs.k8s.io/controller-runtime/pkg/runtime/inject"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type multiMutating []Handler
|
type multiMutating []Handler
|
||||||
@ -62,31 +60,6 @@ func (hs multiMutating) Handle(ctx context.Context, req Request) Response {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// InjectFunc injects the field setter into the handlers.
|
|
||||||
func (hs multiMutating) InjectFunc(f inject.Func) error {
|
|
||||||
// inject directly into the handlers. It would be more correct
|
|
||||||
// to do this in a sync.Once in Handle (since we don't have some
|
|
||||||
// other start/finalize-type method), but it's more efficient to
|
|
||||||
// do it here, presumably.
|
|
||||||
for _, handler := range hs {
|
|
||||||
if err := f(handler); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// InjectDecoder injects the decoder into the handlers.
|
|
||||||
func (hs multiMutating) InjectDecoder(d *Decoder) error {
|
|
||||||
for _, handler := range hs {
|
|
||||||
if _, err := InjectDecoderInto(d, handler); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// MultiMutatingHandler combines multiple mutating webhook handlers into a single
|
// MultiMutatingHandler combines multiple mutating webhook handlers into a single
|
||||||
// mutating webhook handler. Handlers are called in sequential order, and the first
|
// mutating webhook handler. Handlers are called in sequential order, and the first
|
||||||
// `allowed: false` response may short-circuit the rest. Users must take care to
|
// `allowed: false` response may short-circuit the rest. Users must take care to
|
||||||
@ -120,28 +93,3 @@ func (hs multiValidating) Handle(ctx context.Context, req Request) Response {
|
|||||||
func MultiValidatingHandler(handlers ...Handler) Handler {
|
func MultiValidatingHandler(handlers ...Handler) Handler {
|
||||||
return multiValidating(handlers)
|
return multiValidating(handlers)
|
||||||
}
|
}
|
||||||
|
|
||||||
// InjectFunc injects the field setter into the handlers.
|
|
||||||
func (hs multiValidating) InjectFunc(f inject.Func) error {
|
|
||||||
// inject directly into the handlers. It would be more correct
|
|
||||||
// to do this in a sync.Once in Handle (since we don't have some
|
|
||||||
// other start/finalize-type method), but it's more efficient to
|
|
||||||
// do it here, presumably.
|
|
||||||
for _, handler := range hs {
|
|
||||||
if err := f(handler); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// InjectDecoder injects the decoder into the handlers.
|
|
||||||
func (hs multiValidating) InjectDecoder(d *Decoder) error {
|
|
||||||
for _, handler := range hs {
|
|
||||||
if _, err := InjectDecoderInto(d, handler); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
23
vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/response.go
generated
vendored
23
vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/response.go
generated
vendored
@ -26,21 +26,21 @@ import (
|
|||||||
|
|
||||||
// Allowed constructs a response indicating that the given operation
|
// Allowed constructs a response indicating that the given operation
|
||||||
// is allowed (without any patches).
|
// is allowed (without any patches).
|
||||||
func Allowed(reason string) Response {
|
func Allowed(message string) Response {
|
||||||
return ValidationResponse(true, reason)
|
return ValidationResponse(true, message)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Denied constructs a response indicating that the given operation
|
// Denied constructs a response indicating that the given operation
|
||||||
// is not allowed.
|
// is not allowed.
|
||||||
func Denied(reason string) Response {
|
func Denied(message string) Response {
|
||||||
return ValidationResponse(false, reason)
|
return ValidationResponse(false, message)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Patched constructs a response indicating that the given operation is
|
// Patched constructs a response indicating that the given operation is
|
||||||
// allowed, and that the target object should be modified by the given
|
// allowed, and that the target object should be modified by the given
|
||||||
// JSONPatch operations.
|
// JSONPatch operations.
|
||||||
func Patched(reason string, patches ...jsonpatch.JsonPatchOperation) Response {
|
func Patched(message string, patches ...jsonpatch.JsonPatchOperation) Response {
|
||||||
resp := Allowed(reason)
|
resp := Allowed(message)
|
||||||
resp.Patches = patches
|
resp.Patches = patches
|
||||||
|
|
||||||
return resp
|
return resp
|
||||||
@ -60,21 +60,24 @@ func Errored(code int32, err error) Response {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ValidationResponse returns a response for admitting a request.
|
// ValidationResponse returns a response for admitting a request.
|
||||||
func ValidationResponse(allowed bool, reason string) Response {
|
func ValidationResponse(allowed bool, message string) Response {
|
||||||
code := http.StatusForbidden
|
code := http.StatusForbidden
|
||||||
|
reason := metav1.StatusReasonForbidden
|
||||||
if allowed {
|
if allowed {
|
||||||
code = http.StatusOK
|
code = http.StatusOK
|
||||||
|
reason = ""
|
||||||
}
|
}
|
||||||
resp := Response{
|
resp := Response{
|
||||||
AdmissionResponse: admissionv1.AdmissionResponse{
|
AdmissionResponse: admissionv1.AdmissionResponse{
|
||||||
Allowed: allowed,
|
Allowed: allowed,
|
||||||
Result: &metav1.Status{
|
Result: &metav1.Status{
|
||||||
Code: int32(code),
|
Code: int32(code),
|
||||||
|
Reason: reason,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
if len(reason) > 0 {
|
if len(message) > 0 {
|
||||||
resp.Result.Reason = metav1.StatusReason(reason)
|
resp.Result.Message = message
|
||||||
}
|
}
|
||||||
return resp
|
return resp
|
||||||
}
|
}
|
||||||
|
105
vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/validator.go
generated
vendored
105
vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/validator.go
generated
vendored
@ -18,7 +18,8 @@ package admission
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
goerrors "errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
v1 "k8s.io/api/admission/v1"
|
v1 "k8s.io/api/admission/v1"
|
||||||
@ -26,18 +27,35 @@ import (
|
|||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Warnings represents warning messages.
|
||||||
|
type Warnings []string
|
||||||
|
|
||||||
// Validator defines functions for validating an operation.
|
// Validator defines functions for validating an operation.
|
||||||
|
// The custom resource kind which implements this interface can validate itself.
|
||||||
|
// To validate the custom resource with another specific struct, use CustomValidator instead.
|
||||||
type Validator interface {
|
type Validator interface {
|
||||||
runtime.Object
|
runtime.Object
|
||||||
ValidateCreate() error
|
|
||||||
ValidateUpdate(old runtime.Object) error
|
// ValidateCreate validates the object on creation.
|
||||||
ValidateDelete() error
|
// The optional warnings will be added to the response as warning messages.
|
||||||
|
// Return an error if the object is invalid.
|
||||||
|
ValidateCreate() (warnings Warnings, err error)
|
||||||
|
|
||||||
|
// ValidateUpdate validates the object on update. The oldObj is the object before the update.
|
||||||
|
// The optional warnings will be added to the response as warning messages.
|
||||||
|
// Return an error if the object is invalid.
|
||||||
|
ValidateUpdate(old runtime.Object) (warnings Warnings, err error)
|
||||||
|
|
||||||
|
// ValidateDelete validates the object on deletion.
|
||||||
|
// The optional warnings will be added to the response as warning messages.
|
||||||
|
// Return an error if the object is invalid.
|
||||||
|
ValidateDelete() (warnings Warnings, err error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ValidatingWebhookFor creates a new Webhook for validating the provided type.
|
// ValidatingWebhookFor creates a new Webhook for validating the provided type.
|
||||||
func ValidatingWebhookFor(validator Validator) *Webhook {
|
func ValidatingWebhookFor(scheme *runtime.Scheme, validator Validator) *Webhook {
|
||||||
return &Webhook{
|
return &Webhook{
|
||||||
Handler: &validatingHandler{validator: validator},
|
Handler: &validatingHandler{validator: validator, decoder: NewDecoder(scheme)},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -46,42 +64,34 @@ type validatingHandler struct {
|
|||||||
decoder *Decoder
|
decoder *Decoder
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ DecoderInjector = &validatingHandler{}
|
|
||||||
|
|
||||||
// InjectDecoder injects the decoder into a validatingHandler.
|
|
||||||
func (h *validatingHandler) InjectDecoder(d *Decoder) error {
|
|
||||||
h.decoder = d
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle handles admission requests.
|
// Handle handles admission requests.
|
||||||
func (h *validatingHandler) Handle(ctx context.Context, req Request) Response {
|
func (h *validatingHandler) Handle(ctx context.Context, req Request) Response {
|
||||||
|
if h.decoder == nil {
|
||||||
|
panic("decoder should never be nil")
|
||||||
|
}
|
||||||
if h.validator == nil {
|
if h.validator == nil {
|
||||||
panic("validator should never be nil")
|
panic("validator should never be nil")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the object in the request
|
// Get the object in the request
|
||||||
obj := h.validator.DeepCopyObject().(Validator)
|
obj := h.validator.DeepCopyObject().(Validator)
|
||||||
if req.Operation == v1.Create {
|
|
||||||
err := h.decoder.Decode(req, obj)
|
var err error
|
||||||
if err != nil {
|
var warnings []string
|
||||||
|
|
||||||
|
switch req.Operation {
|
||||||
|
case v1.Connect:
|
||||||
|
// No validation for connect requests.
|
||||||
|
// TODO(vincepri): Should we validate CONNECT requests? In what cases?
|
||||||
|
case v1.Create:
|
||||||
|
if err = h.decoder.Decode(req, obj); err != nil {
|
||||||
return Errored(http.StatusBadRequest, err)
|
return Errored(http.StatusBadRequest, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = obj.ValidateCreate()
|
warnings, err = obj.ValidateCreate()
|
||||||
if err != nil {
|
case v1.Update:
|
||||||
var apiStatus apierrors.APIStatus
|
|
||||||
if goerrors.As(err, &apiStatus) {
|
|
||||||
return validationResponseFromStatus(false, apiStatus.Status())
|
|
||||||
}
|
|
||||||
return Denied(err.Error())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if req.Operation == v1.Update {
|
|
||||||
oldObj := obj.DeepCopyObject()
|
oldObj := obj.DeepCopyObject()
|
||||||
|
|
||||||
err := h.decoder.DecodeRaw(req.Object, obj)
|
err = h.decoder.DecodeRaw(req.Object, obj)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return Errored(http.StatusBadRequest, err)
|
return Errored(http.StatusBadRequest, err)
|
||||||
}
|
}
|
||||||
@ -90,33 +100,26 @@ func (h *validatingHandler) Handle(ctx context.Context, req Request) Response {
|
|||||||
return Errored(http.StatusBadRequest, err)
|
return Errored(http.StatusBadRequest, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = obj.ValidateUpdate(oldObj)
|
warnings, err = obj.ValidateUpdate(oldObj)
|
||||||
if err != nil {
|
case v1.Delete:
|
||||||
var apiStatus apierrors.APIStatus
|
|
||||||
if goerrors.As(err, &apiStatus) {
|
|
||||||
return validationResponseFromStatus(false, apiStatus.Status())
|
|
||||||
}
|
|
||||||
return Denied(err.Error())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if req.Operation == v1.Delete {
|
|
||||||
// In reference to PR: https://github.com/kubernetes/kubernetes/pull/76346
|
// In reference to PR: https://github.com/kubernetes/kubernetes/pull/76346
|
||||||
// OldObject contains the object being deleted
|
// OldObject contains the object being deleted
|
||||||
err := h.decoder.DecodeRaw(req.OldObject, obj)
|
err = h.decoder.DecodeRaw(req.OldObject, obj)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return Errored(http.StatusBadRequest, err)
|
return Errored(http.StatusBadRequest, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = obj.ValidateDelete()
|
warnings, err = obj.ValidateDelete()
|
||||||
if err != nil {
|
default:
|
||||||
var apiStatus apierrors.APIStatus
|
return Errored(http.StatusBadRequest, fmt.Errorf("unknown operation %q", req.Operation))
|
||||||
if goerrors.As(err, &apiStatus) {
|
|
||||||
return validationResponseFromStatus(false, apiStatus.Status())
|
|
||||||
}
|
|
||||||
return Denied(err.Error())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return Allowed("")
|
if err != nil {
|
||||||
|
var apiStatus apierrors.APIStatus
|
||||||
|
if errors.As(err, &apiStatus) {
|
||||||
|
return validationResponseFromStatus(false, apiStatus.Status()).WithWarnings(warnings...)
|
||||||
|
}
|
||||||
|
return Denied(err.Error()).WithWarnings(warnings...)
|
||||||
|
}
|
||||||
|
return Allowed("").WithWarnings(warnings...)
|
||||||
}
|
}
|
||||||
|
53
vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/validator_custom.go
generated
vendored
53
vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/validator_custom.go
generated
vendored
@ -28,16 +28,29 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// CustomValidator defines functions for validating an operation.
|
// CustomValidator defines functions for validating an operation.
|
||||||
|
// The object to be validated is passed into methods as a parameter.
|
||||||
type CustomValidator interface {
|
type CustomValidator interface {
|
||||||
ValidateCreate(ctx context.Context, obj runtime.Object) error
|
|
||||||
ValidateUpdate(ctx context.Context, oldObj, newObj runtime.Object) error
|
// ValidateCreate validates the object on creation.
|
||||||
ValidateDelete(ctx context.Context, obj runtime.Object) error
|
// The optional warnings will be added to the response as warning messages.
|
||||||
|
// Return an error if the object is invalid.
|
||||||
|
ValidateCreate(ctx context.Context, obj runtime.Object) (warnings Warnings, err error)
|
||||||
|
|
||||||
|
// ValidateUpdate validates the object on update.
|
||||||
|
// The optional warnings will be added to the response as warning messages.
|
||||||
|
// Return an error if the object is invalid.
|
||||||
|
ValidateUpdate(ctx context.Context, oldObj, newObj runtime.Object) (warnings Warnings, err error)
|
||||||
|
|
||||||
|
// ValidateDelete validates the object on deletion.
|
||||||
|
// The optional warnings will be added to the response as warning messages.
|
||||||
|
// Return an error if the object is invalid.
|
||||||
|
ValidateDelete(ctx context.Context, obj runtime.Object) (warnings Warnings, err error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithCustomValidator creates a new Webhook for validating the provided type.
|
// WithCustomValidator creates a new Webhook for validating the provided type.
|
||||||
func WithCustomValidator(obj runtime.Object, validator CustomValidator) *Webhook {
|
func WithCustomValidator(scheme *runtime.Scheme, obj runtime.Object, validator CustomValidator) *Webhook {
|
||||||
return &Webhook{
|
return &Webhook{
|
||||||
Handler: &validatorForType{object: obj, validator: validator},
|
Handler: &validatorForType{object: obj, validator: validator, decoder: NewDecoder(scheme)},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -47,16 +60,11 @@ type validatorForType struct {
|
|||||||
decoder *Decoder
|
decoder *Decoder
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ DecoderInjector = &validatorForType{}
|
|
||||||
|
|
||||||
// InjectDecoder injects the decoder into a validatingHandler.
|
|
||||||
func (h *validatorForType) InjectDecoder(d *Decoder) error {
|
|
||||||
h.decoder = d
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle handles admission requests.
|
// Handle handles admission requests.
|
||||||
func (h *validatorForType) Handle(ctx context.Context, req Request) Response {
|
func (h *validatorForType) Handle(ctx context.Context, req Request) Response {
|
||||||
|
if h.decoder == nil {
|
||||||
|
panic("decoder should never be nil")
|
||||||
|
}
|
||||||
if h.validator == nil {
|
if h.validator == nil {
|
||||||
panic("validator should never be nil")
|
panic("validator should never be nil")
|
||||||
}
|
}
|
||||||
@ -70,13 +78,18 @@ func (h *validatorForType) Handle(ctx context.Context, req Request) Response {
|
|||||||
obj := h.object.DeepCopyObject()
|
obj := h.object.DeepCopyObject()
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
|
var warnings []string
|
||||||
|
|
||||||
switch req.Operation {
|
switch req.Operation {
|
||||||
|
case v1.Connect:
|
||||||
|
// No validation for connect requests.
|
||||||
|
// TODO(vincepri): Should we validate CONNECT requests? In what cases?
|
||||||
case v1.Create:
|
case v1.Create:
|
||||||
if err := h.decoder.Decode(req, obj); err != nil {
|
if err := h.decoder.Decode(req, obj); err != nil {
|
||||||
return Errored(http.StatusBadRequest, err)
|
return Errored(http.StatusBadRequest, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = h.validator.ValidateCreate(ctx, obj)
|
warnings, err = h.validator.ValidateCreate(ctx, obj)
|
||||||
case v1.Update:
|
case v1.Update:
|
||||||
oldObj := obj.DeepCopyObject()
|
oldObj := obj.DeepCopyObject()
|
||||||
if err := h.decoder.DecodeRaw(req.Object, obj); err != nil {
|
if err := h.decoder.DecodeRaw(req.Object, obj); err != nil {
|
||||||
@ -86,7 +99,7 @@ func (h *validatorForType) Handle(ctx context.Context, req Request) Response {
|
|||||||
return Errored(http.StatusBadRequest, err)
|
return Errored(http.StatusBadRequest, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = h.validator.ValidateUpdate(ctx, oldObj, obj)
|
warnings, err = h.validator.ValidateUpdate(ctx, oldObj, obj)
|
||||||
case v1.Delete:
|
case v1.Delete:
|
||||||
// In reference to PR: https://github.com/kubernetes/kubernetes/pull/76346
|
// In reference to PR: https://github.com/kubernetes/kubernetes/pull/76346
|
||||||
// OldObject contains the object being deleted
|
// OldObject contains the object being deleted
|
||||||
@ -94,20 +107,20 @@ func (h *validatorForType) Handle(ctx context.Context, req Request) Response {
|
|||||||
return Errored(http.StatusBadRequest, err)
|
return Errored(http.StatusBadRequest, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = h.validator.ValidateDelete(ctx, obj)
|
warnings, err = h.validator.ValidateDelete(ctx, obj)
|
||||||
default:
|
default:
|
||||||
return Errored(http.StatusBadRequest, fmt.Errorf("unknown operation request %q", req.Operation))
|
return Errored(http.StatusBadRequest, fmt.Errorf("unknown operation %q", req.Operation))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check the error message first.
|
// Check the error message first.
|
||||||
if err != nil {
|
if err != nil {
|
||||||
var apiStatus apierrors.APIStatus
|
var apiStatus apierrors.APIStatus
|
||||||
if errors.As(err, &apiStatus) {
|
if errors.As(err, &apiStatus) {
|
||||||
return validationResponseFromStatus(false, apiStatus.Status())
|
return validationResponseFromStatus(false, apiStatus.Status()).WithWarnings(warnings...)
|
||||||
}
|
}
|
||||||
return Denied(err.Error())
|
return Denied(err.Error()).WithWarnings(warnings...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return allowed if everything succeeded.
|
// Return allowed if everything succeeded.
|
||||||
return Allowed("")
|
return Allowed("").WithWarnings(warnings...)
|
||||||
}
|
}
|
||||||
|
119
vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/webhook.go
generated
vendored
119
vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/webhook.go
generated
vendored
@ -21,18 +21,17 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"sync"
|
||||||
|
|
||||||
"github.com/go-logr/logr"
|
"github.com/go-logr/logr"
|
||||||
jsonpatch "gomodules.xyz/jsonpatch/v2"
|
"gomodules.xyz/jsonpatch/v2"
|
||||||
admissionv1 "k8s.io/api/admission/v1"
|
admissionv1 "k8s.io/api/admission/v1"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
|
||||||
"k8s.io/apimachinery/pkg/util/json"
|
"k8s.io/apimachinery/pkg/util/json"
|
||||||
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
|
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
|
||||||
"k8s.io/client-go/kubernetes/scheme"
|
"k8s.io/klog/v2"
|
||||||
|
|
||||||
logf "sigs.k8s.io/controller-runtime/pkg/internal/log"
|
logf "sigs.k8s.io/controller-runtime/pkg/log"
|
||||||
"sigs.k8s.io/controller-runtime/pkg/runtime/inject"
|
|
||||||
"sigs.k8s.io/controller-runtime/pkg/webhook/internal/metrics"
|
"sigs.k8s.io/controller-runtime/pkg/webhook/internal/metrics"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -131,16 +130,14 @@ type Webhook struct {
|
|||||||
// headers thus allowing you to read them from within the handler
|
// headers thus allowing you to read them from within the handler
|
||||||
WithContextFunc func(context.Context, *http.Request) context.Context
|
WithContextFunc func(context.Context, *http.Request) context.Context
|
||||||
|
|
||||||
// decoder is constructed on receiving a scheme and passed down to then handler
|
// LogConstructor is used to construct a logger for logging messages during webhook calls
|
||||||
decoder *Decoder
|
// based on the given base logger (which might carry more values like the webhook's path).
|
||||||
|
// Note: LogConstructor has to be able to handle nil requests as we are also using it
|
||||||
|
// outside the context of requests.
|
||||||
|
LogConstructor func(base logr.Logger, req *Request) logr.Logger
|
||||||
|
|
||||||
log logr.Logger
|
setupLogOnce sync.Once
|
||||||
}
|
log logr.Logger
|
||||||
|
|
||||||
// InjectLogger gets a handle to a logging instance, hopefully with more info about this particular webhook.
|
|
||||||
func (wh *Webhook) InjectLogger(l logr.Logger) error {
|
|
||||||
wh.log = l
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithRecoverPanic takes a bool flag which indicates whether the panic caused by webhook should be recovered.
|
// WithRecoverPanic takes a bool flag which indicates whether the panic caused by webhook should be recovered.
|
||||||
@ -166,79 +163,47 @@ func (wh *Webhook) Handle(ctx context.Context, req Request) (response Response)
|
|||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
reqLog := wh.getLogger(&req)
|
||||||
|
ctx = logf.IntoContext(ctx, reqLog)
|
||||||
|
|
||||||
resp := wh.Handler.Handle(ctx, req)
|
resp := wh.Handler.Handle(ctx, req)
|
||||||
if err := resp.Complete(req); err != nil {
|
if err := resp.Complete(req); err != nil {
|
||||||
wh.log.Error(err, "unable to encode response")
|
reqLog.Error(err, "unable to encode response")
|
||||||
return Errored(http.StatusInternalServerError, errUnableToEncodeResponse)
|
return Errored(http.StatusInternalServerError, errUnableToEncodeResponse)
|
||||||
}
|
}
|
||||||
|
|
||||||
return resp
|
return resp
|
||||||
}
|
}
|
||||||
|
|
||||||
// InjectScheme injects a scheme into the webhook, in order to construct a Decoder.
|
// getLogger constructs a logger from the injected log and LogConstructor.
|
||||||
func (wh *Webhook) InjectScheme(s *runtime.Scheme) error {
|
func (wh *Webhook) getLogger(req *Request) logr.Logger {
|
||||||
// TODO(directxman12): we should have a better way to pass this down
|
wh.setupLogOnce.Do(func() {
|
||||||
|
if wh.log.GetSink() == nil {
|
||||||
var err error
|
wh.log = logf.Log.WithName("admission")
|
||||||
wh.decoder, err = NewDecoder(s)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// inject the decoder here too, just in case the order of calling this is not
|
|
||||||
// scheme first, then inject func
|
|
||||||
if wh.Handler != nil {
|
|
||||||
if _, err := InjectDecoderInto(wh.GetDecoder(), wh.Handler); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
|
|
||||||
return nil
|
logConstructor := wh.LogConstructor
|
||||||
|
if logConstructor == nil {
|
||||||
|
logConstructor = DefaultLogConstructor
|
||||||
|
}
|
||||||
|
return logConstructor(wh.log, req)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetDecoder returns a decoder to decode the objects embedded in admission requests.
|
// DefaultLogConstructor adds some commonly interesting fields to the given logger.
|
||||||
// It may be nil if we haven't received a scheme to use to determine object types yet.
|
func DefaultLogConstructor(base logr.Logger, req *Request) logr.Logger {
|
||||||
func (wh *Webhook) GetDecoder() *Decoder {
|
if req != nil {
|
||||||
return wh.decoder
|
return base.WithValues("object", klog.KRef(req.Namespace, req.Name),
|
||||||
}
|
"namespace", req.Namespace, "name", req.Name,
|
||||||
|
"resource", req.Resource, "user", req.UserInfo.Username,
|
||||||
// InjectFunc injects the field setter into the webhook.
|
"requestID", req.UID,
|
||||||
func (wh *Webhook) InjectFunc(f inject.Func) error {
|
)
|
||||||
// inject directly into the handlers. It would be more correct
|
|
||||||
// to do this in a sync.Once in Handle (since we don't have some
|
|
||||||
// other start/finalize-type method), but it's more efficient to
|
|
||||||
// do it here, presumably.
|
|
||||||
|
|
||||||
// also inject a decoder, and wrap this so that we get a setFields
|
|
||||||
// that injects a decoder (hopefully things don't ignore the duplicate
|
|
||||||
// InjectorInto call).
|
|
||||||
|
|
||||||
var setFields inject.Func
|
|
||||||
setFields = func(target interface{}) error {
|
|
||||||
if err := f(target); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, err := inject.InjectorInto(setFields, target); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, err := InjectDecoderInto(wh.GetDecoder(), target); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
return base
|
||||||
return setFields(wh.Handler)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// StandaloneOptions let you configure a StandaloneWebhook.
|
// StandaloneOptions let you configure a StandaloneWebhook.
|
||||||
type StandaloneOptions struct {
|
type StandaloneOptions struct {
|
||||||
// Scheme is the scheme used to resolve runtime.Objects to GroupVersionKinds / Resources
|
|
||||||
// Defaults to the kubernetes/client-go scheme.Scheme, but it's almost always better
|
|
||||||
// idea to pass your own scheme in. See the documentation in pkg/scheme for more information.
|
|
||||||
Scheme *runtime.Scheme
|
|
||||||
// Logger to be used by the webhook.
|
// Logger to be used by the webhook.
|
||||||
// If none is set, it defaults to log.Log global logger.
|
// If none is set, it defaults to log.Log global logger.
|
||||||
Logger logr.Logger
|
Logger logr.Logger
|
||||||
@ -258,19 +223,9 @@ type StandaloneOptions struct {
|
|||||||
// in your own server/mux. In order to be accessed by a kubernetes cluster,
|
// in your own server/mux. In order to be accessed by a kubernetes cluster,
|
||||||
// all webhook servers require TLS.
|
// all webhook servers require TLS.
|
||||||
func StandaloneWebhook(hook *Webhook, opts StandaloneOptions) (http.Handler, error) {
|
func StandaloneWebhook(hook *Webhook, opts StandaloneOptions) (http.Handler, error) {
|
||||||
if opts.Scheme == nil {
|
if opts.Logger.GetSink() != nil {
|
||||||
opts.Scheme = scheme.Scheme
|
hook.log = opts.Logger
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := hook.InjectScheme(opts.Scheme); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if opts.Logger.GetSink() == nil {
|
|
||||||
opts.Logger = logf.RuntimeLog.WithName("webhook")
|
|
||||||
}
|
|
||||||
hook.log = opts.Logger
|
|
||||||
|
|
||||||
if opts.MetricsPath == "" {
|
if opts.MetricsPath == "" {
|
||||||
return hook, nil
|
return hook, nil
|
||||||
}
|
}
|
||||||
|
237
vendor/sigs.k8s.io/controller-runtime/pkg/webhook/server.go
generated
vendored
237
vendor/sigs.k8s.io/controller-runtime/pkg/webhook/server.go
generated
vendored
@ -29,12 +29,9 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
|
||||||
kscheme "k8s.io/client-go/kubernetes/scheme"
|
|
||||||
"sigs.k8s.io/controller-runtime/pkg/certwatcher"
|
"sigs.k8s.io/controller-runtime/pkg/certwatcher"
|
||||||
"sigs.k8s.io/controller-runtime/pkg/healthz"
|
"sigs.k8s.io/controller-runtime/pkg/healthz"
|
||||||
"sigs.k8s.io/controller-runtime/pkg/internal/httpserver"
|
"sigs.k8s.io/controller-runtime/pkg/internal/httpserver"
|
||||||
"sigs.k8s.io/controller-runtime/pkg/runtime/inject"
|
|
||||||
"sigs.k8s.io/controller-runtime/pkg/webhook/internal/metrics"
|
"sigs.k8s.io/controller-runtime/pkg/webhook/internal/metrics"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -49,7 +46,29 @@ var DefaultPort = 9443
|
|||||||
// at the default locations (tls.crt and tls.key). If you do not
|
// at the default locations (tls.crt and tls.key). If you do not
|
||||||
// want to configure TLS (i.e for testing purposes) run an
|
// want to configure TLS (i.e for testing purposes) run an
|
||||||
// admission.StandaloneWebhook in your own server.
|
// admission.StandaloneWebhook in your own server.
|
||||||
type Server struct {
|
type Server interface {
|
||||||
|
// NeedLeaderElection implements the LeaderElectionRunnable interface, which indicates
|
||||||
|
// the webhook server doesn't need leader election.
|
||||||
|
NeedLeaderElection() bool
|
||||||
|
|
||||||
|
// Register marks the given webhook as being served at the given path.
|
||||||
|
// It panics if two hooks are registered on the same path.
|
||||||
|
Register(path string, hook http.Handler)
|
||||||
|
|
||||||
|
// Start runs the server.
|
||||||
|
// It will install the webhook related resources depend on the server configuration.
|
||||||
|
Start(ctx context.Context) error
|
||||||
|
|
||||||
|
// StartedChecker returns an healthz.Checker which is healthy after the
|
||||||
|
// server has been started.
|
||||||
|
StartedChecker() healthz.Checker
|
||||||
|
|
||||||
|
// WebhookMux returns the servers WebhookMux
|
||||||
|
WebhookMux() *http.ServeMux
|
||||||
|
}
|
||||||
|
|
||||||
|
// Options are all the available options for a webhook.Server
|
||||||
|
type Options struct {
|
||||||
// Host is the address that the server will listen on.
|
// Host is the address that the server will listen on.
|
||||||
// Defaults to "" - all addresses.
|
// Defaults to "" - all addresses.
|
||||||
Host string
|
Host string
|
||||||
@ -63,9 +82,13 @@ type Server struct {
|
|||||||
CertDir string
|
CertDir string
|
||||||
|
|
||||||
// CertName is the server certificate name. Defaults to tls.crt.
|
// CertName is the server certificate name. Defaults to tls.crt.
|
||||||
|
//
|
||||||
|
// Note: This option should only be set when TLSOpts does not override GetCertificate.
|
||||||
CertName string
|
CertName string
|
||||||
|
|
||||||
// KeyName is the server key name. Defaults to tls.key.
|
// KeyName is the server key name. Defaults to tls.key.
|
||||||
|
//
|
||||||
|
// Note: This option should only be set when TLSOpts does not override GetCertificate.
|
||||||
KeyName string
|
KeyName string
|
||||||
|
|
||||||
// ClientCAName is the CA certificate name which server used to verify remote(client)'s certificate.
|
// ClientCAName is the CA certificate name which server used to verify remote(client)'s certificate.
|
||||||
@ -82,14 +105,22 @@ type Server struct {
|
|||||||
|
|
||||||
// WebhookMux is the multiplexer that handles different webhooks.
|
// WebhookMux is the multiplexer that handles different webhooks.
|
||||||
WebhookMux *http.ServeMux
|
WebhookMux *http.ServeMux
|
||||||
|
}
|
||||||
|
|
||||||
// webhooks keep track of all registered webhooks for dependency injection,
|
// NewServer constructs a new Server from the provided options.
|
||||||
// and to provide better panic messages on duplicate webhook registration.
|
func NewServer(o Options) Server {
|
||||||
|
return &DefaultServer{
|
||||||
|
Options: o,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DefaultServer is the default implementation used for Server.
|
||||||
|
type DefaultServer struct {
|
||||||
|
Options Options
|
||||||
|
|
||||||
|
// webhooks keep track of all registered webhooks
|
||||||
webhooks map[string]http.Handler
|
webhooks map[string]http.Handler
|
||||||
|
|
||||||
// setFields allows injecting dependencies from an external source
|
|
||||||
setFields inject.Func
|
|
||||||
|
|
||||||
// defaultingOnce ensures that the default fields are only ever set once.
|
// defaultingOnce ensures that the default fields are only ever set once.
|
||||||
defaultingOnce sync.Once
|
defaultingOnce sync.Once
|
||||||
|
|
||||||
@ -99,41 +130,49 @@ type Server struct {
|
|||||||
|
|
||||||
// mu protects access to the webhook map & setFields for Start, Register, etc
|
// mu protects access to the webhook map & setFields for Start, Register, etc
|
||||||
mu sync.Mutex
|
mu sync.Mutex
|
||||||
|
|
||||||
|
webhookMux *http.ServeMux
|
||||||
}
|
}
|
||||||
|
|
||||||
// setDefaults does defaulting for the Server.
|
// setDefaults does defaulting for the Server.
|
||||||
func (s *Server) setDefaults() {
|
func (o *Options) setDefaults() {
|
||||||
|
if o.WebhookMux == nil {
|
||||||
|
o.WebhookMux = http.NewServeMux()
|
||||||
|
}
|
||||||
|
|
||||||
|
if o.Port <= 0 {
|
||||||
|
o.Port = DefaultPort
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(o.CertDir) == 0 {
|
||||||
|
o.CertDir = filepath.Join(os.TempDir(), "k8s-webhook-server", "serving-certs")
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(o.CertName) == 0 {
|
||||||
|
o.CertName = "tls.crt"
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(o.KeyName) == 0 {
|
||||||
|
o.KeyName = "tls.key"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *DefaultServer) setDefaults() {
|
||||||
s.webhooks = map[string]http.Handler{}
|
s.webhooks = map[string]http.Handler{}
|
||||||
if s.WebhookMux == nil {
|
s.Options.setDefaults()
|
||||||
s.WebhookMux = http.NewServeMux()
|
|
||||||
}
|
|
||||||
|
|
||||||
if s.Port <= 0 {
|
s.webhookMux = s.Options.WebhookMux
|
||||||
s.Port = DefaultPort
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(s.CertDir) == 0 {
|
|
||||||
s.CertDir = filepath.Join(os.TempDir(), "k8s-webhook-server", "serving-certs")
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(s.CertName) == 0 {
|
|
||||||
s.CertName = "tls.crt"
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(s.KeyName) == 0 {
|
|
||||||
s.KeyName = "tls.key"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NeedLeaderElection implements the LeaderElectionRunnable interface, which indicates
|
// NeedLeaderElection implements the LeaderElectionRunnable interface, which indicates
|
||||||
// the webhook server doesn't need leader election.
|
// the webhook server doesn't need leader election.
|
||||||
func (*Server) NeedLeaderElection() bool {
|
func (*DefaultServer) NeedLeaderElection() bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// Register marks the given webhook as being served at the given path.
|
// Register marks the given webhook as being served at the given path.
|
||||||
// It panics if two hooks are registered on the same path.
|
// It panics if two hooks are registered on the same path.
|
||||||
func (s *Server) Register(path string, hook http.Handler) {
|
func (s *DefaultServer) Register(path string, hook http.Handler) {
|
||||||
s.mu.Lock()
|
s.mu.Lock()
|
||||||
defer s.mu.Unlock()
|
defer s.mu.Unlock()
|
||||||
|
|
||||||
@ -141,51 +180,11 @@ func (s *Server) Register(path string, hook http.Handler) {
|
|||||||
if _, found := s.webhooks[path]; found {
|
if _, found := s.webhooks[path]; found {
|
||||||
panic(fmt.Errorf("can't register duplicate path: %v", path))
|
panic(fmt.Errorf("can't register duplicate path: %v", path))
|
||||||
}
|
}
|
||||||
// TODO(directxman12): call setfields if we've already started the server
|
|
||||||
s.webhooks[path] = hook
|
s.webhooks[path] = hook
|
||||||
s.WebhookMux.Handle(path, metrics.InstrumentedHook(path, hook))
|
s.webhookMux.Handle(path, metrics.InstrumentedHook(path, hook))
|
||||||
|
|
||||||
regLog := log.WithValues("path", path)
|
regLog := log.WithValues("path", path)
|
||||||
regLog.Info("Registering webhook")
|
regLog.Info("Registering webhook")
|
||||||
|
|
||||||
// we've already been "started", inject dependencies here.
|
|
||||||
// Otherwise, InjectFunc will do this for us later.
|
|
||||||
if s.setFields != nil {
|
|
||||||
if err := s.setFields(hook); err != nil {
|
|
||||||
// TODO(directxman12): swallowing this error isn't great, but we'd have to
|
|
||||||
// change the signature to fix that
|
|
||||||
regLog.Error(err, "unable to inject fields into webhook during registration")
|
|
||||||
}
|
|
||||||
|
|
||||||
baseHookLog := log.WithName("webhooks")
|
|
||||||
|
|
||||||
// NB(directxman12): we don't propagate this further by wrapping setFields because it's
|
|
||||||
// unclear if this is how we want to deal with log propagation. In this specific instance,
|
|
||||||
// we want to be able to pass a logger to webhooks because they don't know their own path.
|
|
||||||
if _, err := inject.LoggerInto(baseHookLog.WithValues("webhook", path), hook); err != nil {
|
|
||||||
regLog.Error(err, "unable to logger into webhook during registration")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// StartStandalone runs a webhook server without
|
|
||||||
// a controller manager.
|
|
||||||
func (s *Server) StartStandalone(ctx context.Context, scheme *runtime.Scheme) error {
|
|
||||||
// Use the Kubernetes client-go scheme if none is specified
|
|
||||||
if scheme == nil {
|
|
||||||
scheme = kscheme.Scheme
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := s.InjectFunc(func(i interface{}) error {
|
|
||||||
if _, err := inject.SchemeInto(scheme, i); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return s.Start(ctx)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// tlsVersion converts from human-readable TLS version (for example "1.1")
|
// tlsVersion converts from human-readable TLS version (for example "1.1")
|
||||||
@ -210,41 +209,49 @@ func tlsVersion(version string) (uint16, error) {
|
|||||||
|
|
||||||
// Start runs the server.
|
// Start runs the server.
|
||||||
// It will install the webhook related resources depend on the server configuration.
|
// It will install the webhook related resources depend on the server configuration.
|
||||||
func (s *Server) Start(ctx context.Context) error {
|
func (s *DefaultServer) Start(ctx context.Context) error {
|
||||||
s.defaultingOnce.Do(s.setDefaults)
|
s.defaultingOnce.Do(s.setDefaults)
|
||||||
|
|
||||||
baseHookLog := log.WithName("webhooks")
|
baseHookLog := log.WithName("webhooks")
|
||||||
baseHookLog.Info("Starting webhook server")
|
baseHookLog.Info("Starting webhook server")
|
||||||
|
|
||||||
certPath := filepath.Join(s.CertDir, s.CertName)
|
tlsMinVersion, err := tlsVersion(s.Options.TLSMinVersion)
|
||||||
keyPath := filepath.Join(s.CertDir, s.KeyName)
|
|
||||||
|
|
||||||
certWatcher, err := certwatcher.New(certPath, keyPath)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
go func() {
|
|
||||||
if err := certWatcher.Start(ctx); err != nil {
|
|
||||||
log.Error(err, "certificate watcher error")
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
tlsMinVersion, err := tlsVersion(s.TLSMinVersion)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg := &tls.Config{ //nolint:gosec
|
cfg := &tls.Config{ //nolint:gosec
|
||||||
NextProtos: []string{"h2"},
|
NextProtos: []string{"h2"},
|
||||||
GetCertificate: certWatcher.GetCertificate,
|
MinVersion: tlsMinVersion,
|
||||||
MinVersion: tlsMinVersion,
|
}
|
||||||
|
// fallback TLS config ready, will now mutate if passer wants full control over it
|
||||||
|
for _, op := range s.Options.TLSOpts {
|
||||||
|
op(cfg)
|
||||||
}
|
}
|
||||||
|
|
||||||
// load CA to verify client certificate
|
if cfg.GetCertificate == nil {
|
||||||
if s.ClientCAName != "" {
|
certPath := filepath.Join(s.Options.CertDir, s.Options.CertName)
|
||||||
|
keyPath := filepath.Join(s.Options.CertDir, s.Options.KeyName)
|
||||||
|
|
||||||
|
// Create the certificate watcher and
|
||||||
|
// set the config's GetCertificate on the TLSConfig
|
||||||
|
certWatcher, err := certwatcher.New(certPath, keyPath)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
cfg.GetCertificate = certWatcher.GetCertificate
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
if err := certWatcher.Start(ctx); err != nil {
|
||||||
|
log.Error(err, "certificate watcher error")
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load CA to verify client certificate, if configured.
|
||||||
|
if s.Options.ClientCAName != "" {
|
||||||
certPool := x509.NewCertPool()
|
certPool := x509.NewCertPool()
|
||||||
clientCABytes, err := os.ReadFile(filepath.Join(s.CertDir, s.ClientCAName))
|
clientCABytes, err := os.ReadFile(filepath.Join(s.Options.CertDir, s.Options.ClientCAName))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to read client CA cert: %w", err)
|
return fmt.Errorf("failed to read client CA cert: %w", err)
|
||||||
}
|
}
|
||||||
@ -258,27 +265,23 @@ func (s *Server) Start(ctx context.Context) error {
|
|||||||
cfg.ClientAuth = tls.RequireAndVerifyClientCert
|
cfg.ClientAuth = tls.RequireAndVerifyClientCert
|
||||||
}
|
}
|
||||||
|
|
||||||
// fallback TLS config ready, will now mutate if passer wants full control over it
|
listener, err := tls.Listen("tcp", net.JoinHostPort(s.Options.Host, strconv.Itoa(s.Options.Port)), cfg)
|
||||||
for _, op := range s.TLSOpts {
|
|
||||||
op(cfg)
|
|
||||||
}
|
|
||||||
|
|
||||||
listener, err := tls.Listen("tcp", net.JoinHostPort(s.Host, strconv.Itoa(s.Port)), cfg)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Info("Serving webhook server", "host", s.Host, "port", s.Port)
|
log.Info("Serving webhook server", "host", s.Options.Host, "port", s.Options.Port)
|
||||||
|
|
||||||
srv := httpserver.New(s.WebhookMux)
|
srv := httpserver.New(s.webhookMux)
|
||||||
|
|
||||||
idleConnsClosed := make(chan struct{})
|
idleConnsClosed := make(chan struct{})
|
||||||
go func() {
|
go func() {
|
||||||
<-ctx.Done()
|
<-ctx.Done()
|
||||||
log.Info("shutting down webhook server")
|
log.Info("Shutting down webhook server with timeout of 1 minute")
|
||||||
|
|
||||||
// TODO: use a context with reasonable timeout
|
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Minute)
|
||||||
if err := srv.Shutdown(context.Background()); err != nil {
|
defer cancel()
|
||||||
|
if err := srv.Shutdown(ctx); err != nil {
|
||||||
// Error from closing listeners, or context timeout
|
// Error from closing listeners, or context timeout
|
||||||
log.Error(err, "error shutting down the HTTP server")
|
log.Error(err, "error shutting down the HTTP server")
|
||||||
}
|
}
|
||||||
@ -298,7 +301,7 @@ func (s *Server) Start(ctx context.Context) error {
|
|||||||
|
|
||||||
// StartedChecker returns an healthz.Checker which is healthy after the
|
// StartedChecker returns an healthz.Checker which is healthy after the
|
||||||
// server has been started.
|
// server has been started.
|
||||||
func (s *Server) StartedChecker() healthz.Checker {
|
func (s *DefaultServer) StartedChecker() healthz.Checker {
|
||||||
config := &tls.Config{
|
config := &tls.Config{
|
||||||
InsecureSkipVerify: true, //nolint:gosec // config is used to connect to our own webhook port.
|
InsecureSkipVerify: true, //nolint:gosec // config is used to connect to our own webhook port.
|
||||||
}
|
}
|
||||||
@ -311,7 +314,7 @@ func (s *Server) StartedChecker() healthz.Checker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
d := &net.Dialer{Timeout: 10 * time.Second}
|
d := &net.Dialer{Timeout: 10 * time.Second}
|
||||||
conn, err := tls.DialWithDialer(d, "tcp", net.JoinHostPort(s.Host, strconv.Itoa(s.Port)), config)
|
conn, err := tls.DialWithDialer(d, "tcp", net.JoinHostPort(s.Options.Host, strconv.Itoa(s.Options.Port)), config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("webhook server is not reachable: %w", err)
|
return fmt.Errorf("webhook server is not reachable: %w", err)
|
||||||
}
|
}
|
||||||
@ -324,23 +327,7 @@ func (s *Server) StartedChecker() healthz.Checker {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// InjectFunc injects the field setter into the server.
|
// WebhookMux returns the servers WebhookMux
|
||||||
func (s *Server) InjectFunc(f inject.Func) error {
|
func (s *DefaultServer) WebhookMux() *http.ServeMux {
|
||||||
s.setFields = f
|
return s.webhookMux
|
||||||
|
|
||||||
// inject fields here that weren't injected in Register because we didn't have setFields yet.
|
|
||||||
baseHookLog := log.WithName("webhooks")
|
|
||||||
for hookPath, webhook := range s.webhooks {
|
|
||||||
if err := s.setFields(webhook); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// NB(directxman12): we don't propagate this further by wrapping setFields because it's
|
|
||||||
// unclear if this is how we want to deal with log propagation. In this specific instance,
|
|
||||||
// we want to be able to pass a logger to webhooks because they don't know their own path.
|
|
||||||
if _, err := inject.LoggerInto(baseHookLog.WithValues("webhook", hookPath), webhook); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user