summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--go.mod5
-rw-r--r--go.sum35
-rw-r--r--vendor/github.com/nxadm/tail/.gitignore3
-rw-r--r--vendor/github.com/nxadm/tail/.travis.yml16
-rw-r--r--vendor/github.com/nxadm/tail/CHANGES.md12
-rw-r--r--vendor/github.com/nxadm/tail/README.md40
-rw-r--r--vendor/github.com/nxadm/tail/appveyor.yml11
-rw-r--r--vendor/github.com/nxadm/tail/go.mod3
-rw-r--r--vendor/github.com/nxadm/tail/go.sum8
-rw-r--r--vendor/github.com/nxadm/tail/tail.go73
-rw-r--r--vendor/github.com/nxadm/tail/tail_posix.go6
-rw-r--r--vendor/github.com/nxadm/tail/tail_windows.go9
-rw-r--r--vendor/github.com/nxadm/tail/util/util.go1
-rw-r--r--vendor/github.com/nxadm/tail/watch/filechanges.go1
-rw-r--r--vendor/github.com/nxadm/tail/watch/inotify.go1
-rw-r--r--vendor/github.com/nxadm/tail/watch/inotify_tracker.go1
-rw-r--r--vendor/github.com/nxadm/tail/watch/polling.go1
-rw-r--r--vendor/github.com/nxadm/tail/watch/watch.go1
-rw-r--r--vendor/github.com/nxadm/tail/winfile/winfile.go1
-rw-r--r--vendor/github.com/onsi/ginkgo/.travis.yml13
-rw-r--r--vendor/github.com/onsi/ginkgo/CHANGELOG.md65
-rw-r--r--vendor/github.com/onsi/ginkgo/README.md22
-rw-r--r--vendor/github.com/onsi/ginkgo/RELEASING.md11
-rw-r--r--vendor/github.com/onsi/ginkgo/config/config.go37
-rw-r--r--vendor/github.com/onsi/ginkgo/formatter/formatter.go190
-rw-r--r--vendor/github.com/onsi/ginkgo/ginkgo_dsl.go71
-rw-r--r--vendor/github.com/onsi/ginkgo/go.mod12
-rw-r--r--vendor/github.com/onsi/ginkgo/go.sum53
-rw-r--r--vendor/github.com/onsi/ginkgo/internal/remote/output_interceptor_darwin.go11
-rw-r--r--vendor/github.com/onsi/ginkgo/internal/remote/output_interceptor_dragonfly.go11
-rw-r--r--vendor/github.com/onsi/ginkgo/internal/remote/output_interceptor_freebsd.go11
-rw-r--r--vendor/github.com/onsi/ginkgo/internal/remote/output_interceptor_linux.go12
-rw-r--r--vendor/github.com/onsi/ginkgo/internal/remote/output_interceptor_linux_mips64le.go12
-rw-r--r--vendor/github.com/onsi/ginkgo/internal/remote/output_interceptor_netbsd.go11
-rw-r--r--vendor/github.com/onsi/ginkgo/internal/remote/output_interceptor_openbsd.go11
-rw-r--r--vendor/github.com/onsi/ginkgo/internal/remote/output_interceptor_solaris.go11
-rw-r--r--vendor/github.com/onsi/ginkgo/internal/remote/output_interceptor_unix.go7
-rw-r--r--vendor/github.com/onsi/ginkgo/internal/spec/specs.go20
-rw-r--r--vendor/github.com/onsi/ginkgo/internal/suite/suite.go2
-rw-r--r--vendor/github.com/onsi/ginkgo/internal/testingtproxy/testing_t_proxy.go42
-rw-r--r--vendor/github.com/onsi/ginkgo/reporters/junit_reporter.go9
-rw-r--r--vendor/github.com/onsi/ginkgo/types/deprecation_support.go150
-rw-r--r--vendor/github.com/onsi/gomega/.travis.yml17
-rw-r--r--vendor/github.com/onsi/gomega/CHANGELOG.md73
-rw-r--r--vendor/github.com/onsi/gomega/Dockerfile1
-rw-r--r--vendor/github.com/onsi/gomega/Makefile37
-rw-r--r--vendor/github.com/onsi/gomega/README.md2
-rw-r--r--vendor/github.com/onsi/gomega/docker-compose.yaml10
-rw-r--r--vendor/github.com/onsi/gomega/format/format.go119
-rw-r--r--vendor/github.com/onsi/gomega/go.mod9
-rw-r--r--vendor/github.com/onsi/gomega/go.sum72
-rw-r--r--vendor/github.com/onsi/gomega/gomega_dsl.go530
-rw-r--r--vendor/github.com/onsi/gomega/internal/assertion.go (renamed from vendor/github.com/onsi/gomega/internal/assertion/assertion.go)28
-rw-r--r--vendor/github.com/onsi/gomega/internal/async_assertion.go (renamed from vendor/github.com/onsi/gomega/internal/asyncassertion/async_assertion.go)140
-rw-r--r--vendor/github.com/onsi/gomega/internal/duration_bundle.go71
-rw-r--r--vendor/github.com/onsi/gomega/internal/gomega.go102
-rw-r--r--vendor/github.com/onsi/gomega/internal/oraclematcher/oracle_matcher.go25
-rw-r--r--vendor/github.com/onsi/gomega/internal/testingtsupport/testing_t_support.go60
-rw-r--r--vendor/github.com/onsi/gomega/matchers.go8
-rw-r--r--vendor/github.com/onsi/gomega/matchers/and.go5
-rw-r--r--vendor/github.com/onsi/gomega/matchers/be_element_of_matcher.go22
-rw-r--r--vendor/github.com/onsi/gomega/matchers/be_numerically_matcher.go2
-rw-r--r--vendor/github.com/onsi/gomega/matchers/consist_of.go53
-rw-r--r--vendor/github.com/onsi/gomega/matchers/contain_elements_matcher.go4
-rw-r--r--vendor/github.com/onsi/gomega/matchers/match_error_matcher.go4
-rw-r--r--vendor/github.com/onsi/gomega/matchers/not.go3
-rw-r--r--vendor/github.com/onsi/gomega/matchers/or.go5
-rw-r--r--vendor/github.com/onsi/gomega/matchers/satisfy_matcher.go66
-rw-r--r--vendor/github.com/onsi/gomega/matchers/with_transform.go22
-rw-r--r--vendor/github.com/onsi/gomega/types/types.go69
-rw-r--r--vendor/github.com/prometheus/client_golang/prometheus/collectors/collectors.go16
-rw-r--r--vendor/github.com/prometheus/client_golang/prometheus/collectors/dbstats_collector.go119
-rw-r--r--vendor/github.com/prometheus/client_golang/prometheus/collectors/dbstats_collector_go115.go30
-rw-r--r--vendor/github.com/prometheus/client_golang/prometheus/collectors/dbstats_collector_pre_go115.go26
-rw-r--r--vendor/github.com/prometheus/client_golang/prometheus/collectors/expvar_collector.go57
-rw-r--r--vendor/github.com/prometheus/client_golang/prometheus/collectors/go_collector.go69
-rw-r--r--vendor/github.com/prometheus/client_golang/prometheus/collectors/process_collector.go56
-rw-r--r--vendor/go.uber.org/zap/CHANGELOG.md44
-rw-r--r--vendor/go.uber.org/zap/buffer/buffer.go18
-rw-r--r--vendor/go.uber.org/zap/go.mod2
-rw-r--r--vendor/go.uber.org/zap/go.sum26
-rw-r--r--vendor/go.uber.org/zap/logger.go9
-rw-r--r--vendor/go.uber.org/zap/options.go8
-rw-r--r--vendor/go.uber.org/zap/sugar.go4
-rw-r--r--vendor/go.uber.org/zap/zapcore/buffered_write_syncer.go188
-rw-r--r--vendor/go.uber.org/zap/zapcore/clock.go50
-rw-r--r--vendor/go.uber.org/zap/zapcore/entry.go10
-rw-r--r--vendor/go.uber.org/zap/zapcore/error.go2
-rw-r--r--vendor/go.uber.org/zap/zapcore/sampler.go14
-rw-r--r--vendor/gomodules.xyz/jsonpatch/v2/LICENSE202
-rw-r--r--vendor/gomodules.xyz/jsonpatch/v2/go.mod8
-rw-r--r--vendor/gomodules.xyz/jsonpatch/v2/go.sum12
-rw-r--r--vendor/gomodules.xyz/jsonpatch/v2/jsonpatch.go334
-rw-r--r--vendor/k8s.io/client-go/metadata/interface.go49
-rw-r--r--vendor/k8s.io/client-go/metadata/metadata.go307
-rw-r--r--vendor/k8s.io/client-go/tools/leaderelection/OWNERS12
-rw-r--r--vendor/k8s.io/client-go/tools/leaderelection/healthzadaptor.go69
-rw-r--r--vendor/k8s.io/client-go/tools/leaderelection/leaderelection.go418
-rw-r--r--vendor/k8s.io/client-go/tools/leaderelection/metrics.go109
-rw-r--r--vendor/k8s.io/client-go/tools/leaderelection/resourcelock/configmaplock.go122
-rw-r--r--vendor/k8s.io/client-go/tools/leaderelection/resourcelock/endpointslock.go117
-rw-r--r--vendor/k8s.io/client-go/tools/leaderelection/resourcelock/interface.go161
-rw-r--r--vendor/k8s.io/client-go/tools/leaderelection/resourcelock/leaselock.go135
-rw-r--r--vendor/k8s.io/client-go/tools/leaderelection/resourcelock/multilock.go104
-rw-r--r--vendor/modules.txt61
-rw-r--r--vendor/sigs.k8s.io/controller-runtime/.gitignore24
-rw-r--r--vendor/sigs.k8s.io/controller-runtime/.golangci.yml130
-rw-r--r--vendor/sigs.k8s.io/controller-runtime/CONTRIBUTING.md19
-rw-r--r--vendor/sigs.k8s.io/controller-runtime/FAQ.md81
-rw-r--r--vendor/sigs.k8s.io/controller-runtime/LICENSE201
-rw-r--r--vendor/sigs.k8s.io/controller-runtime/Makefile123
-rw-r--r--vendor/sigs.k8s.io/controller-runtime/OWNERS10
-rw-r--r--vendor/sigs.k8s.io/controller-runtime/OWNERS_ALIASES40
-rw-r--r--vendor/sigs.k8s.io/controller-runtime/README.md66
-rw-r--r--vendor/sigs.k8s.io/controller-runtime/SECURITY_CONTACTS14
-rw-r--r--vendor/sigs.k8s.io/controller-runtime/TMP-LOGGING.md169
-rw-r--r--vendor/sigs.k8s.io/controller-runtime/VERSIONING.md30
-rw-r--r--vendor/sigs.k8s.io/controller-runtime/alias.go150
-rw-r--r--vendor/sigs.k8s.io/controller-runtime/code-of-conduct.md3
-rw-r--r--vendor/sigs.k8s.io/controller-runtime/doc.go127
-rw-r--r--vendor/sigs.k8s.io/controller-runtime/go.mod28
-rw-r--r--vendor/sigs.k8s.io/controller-runtime/go.sum769
-rw-r--r--vendor/sigs.k8s.io/controller-runtime/pkg/builder/controller.go316
-rw-r--r--vendor/sigs.k8s.io/controller-runtime/pkg/builder/doc.go28
-rw-r--r--vendor/sigs.k8s.io/controller-runtime/pkg/builder/options.go117
-rw-r--r--vendor/sigs.k8s.io/controller-runtime/pkg/builder/webhook.go209
-rw-r--r--vendor/sigs.k8s.io/controller-runtime/pkg/cache/cache.go231
-rw-r--r--vendor/sigs.k8s.io/controller-runtime/pkg/cache/doc.go19
-rw-r--r--vendor/sigs.k8s.io/controller-runtime/pkg/cache/informer_cache.go217
-rw-r--r--vendor/sigs.k8s.io/controller-runtime/pkg/cache/internal/cache_reader.go218
-rw-r--r--vendor/sigs.k8s.io/controller-runtime/pkg/cache/internal/deleg_map.go125
-rw-r--r--vendor/sigs.k8s.io/controller-runtime/pkg/cache/internal/disabledeepcopy.go35
-rw-r--r--vendor/sigs.k8s.io/controller-runtime/pkg/cache/internal/informers_map.go478
-rw-r--r--vendor/sigs.k8s.io/controller-runtime/pkg/cache/internal/selector.go43
-rw-r--r--vendor/sigs.k8s.io/controller-runtime/pkg/cache/multi_namespace_cache.go331
-rw-r--r--vendor/sigs.k8s.io/controller-runtime/pkg/certwatcher/certwatcher.go163
-rw-r--r--vendor/sigs.k8s.io/controller-runtime/pkg/certwatcher/doc.go23
-rw-r--r--vendor/sigs.k8s.io/controller-runtime/pkg/client/apiutil/apimachinery.go196
-rw-r--r--vendor/sigs.k8s.io/controller-runtime/pkg/client/apiutil/dynamicrestmapper.go285
-rw-r--r--vendor/sigs.k8s.io/controller-runtime/pkg/client/client.go328
-rw-r--r--vendor/sigs.k8s.io/controller-runtime/pkg/client/client_cache.go150
-rw-r--r--vendor/sigs.k8s.io/controller-runtime/pkg/client/codec.go40
-rw-r--r--vendor/sigs.k8s.io/controller-runtime/pkg/client/config/config.go157
-rw-r--r--vendor/sigs.k8s.io/controller-runtime/pkg/client/config/doc.go18
-rw-r--r--vendor/sigs.k8s.io/controller-runtime/pkg/client/doc.go49
-rw-r--r--vendor/sigs.k8s.io/controller-runtime/pkg/client/dryrun.go106
-rw-r--r--vendor/sigs.k8s.io/controller-runtime/pkg/client/interfaces.go145
-rw-r--r--vendor/sigs.k8s.io/controller-runtime/pkg/client/metadata_client.go195
-rw-r--r--vendor/sigs.k8s.io/controller-runtime/pkg/client/namespaced_client.go213
-rw-r--r--vendor/sigs.k8s.io/controller-runtime/pkg/client/object.go77
-rw-r--r--vendor/sigs.k8s.io/controller-runtime/pkg/client/options.go697
-rw-r--r--vendor/sigs.k8s.io/controller-runtime/pkg/client/patch.go213
-rw-r--r--vendor/sigs.k8s.io/controller-runtime/pkg/client/split.go141
-rw-r--r--vendor/sigs.k8s.io/controller-runtime/pkg/client/typed_client.go205
-rw-r--r--vendor/sigs.k8s.io/controller-runtime/pkg/client/unstructured_client.go277
-rw-r--r--vendor/sigs.k8s.io/controller-runtime/pkg/client/watch.go118
-rw-r--r--vendor/sigs.k8s.io/controller-runtime/pkg/cluster/cluster.go270
-rw-r--r--vendor/sigs.k8s.io/controller-runtime/pkg/cluster/internal.go128
-rw-r--r--vendor/sigs.k8s.io/controller-runtime/pkg/config/config.go112
-rw-r--r--vendor/sigs.k8s.io/controller-runtime/pkg/config/doc.go25
-rw-r--r--vendor/sigs.k8s.io/controller-runtime/pkg/config/v1alpha1/doc.go20
-rw-r--r--vendor/sigs.k8s.io/controller-runtime/pkg/config/v1alpha1/register.go37
-rw-r--r--vendor/sigs.k8s.io/controller-runtime/pkg/config/v1alpha1/types.go157
-rw-r--r--vendor/sigs.k8s.io/controller-runtime/pkg/config/v1alpha1/zz_generated.deepcopy.go152
-rw-r--r--vendor/sigs.k8s.io/controller-runtime/pkg/controller/controller.go141
-rw-r--r--vendor/sigs.k8s.io/controller-runtime/pkg/controller/controllerutil/controllerutil.go389
-rw-r--r--vendor/sigs.k8s.io/controller-runtime/pkg/controller/controllerutil/doc.go20
-rw-r--r--vendor/sigs.k8s.io/controller-runtime/pkg/controller/doc.go25
-rw-r--r--vendor/sigs.k8s.io/controller-runtime/pkg/conversion/conversion.go40
-rw-r--r--vendor/sigs.k8s.io/controller-runtime/pkg/event/doc.go28
-rw-r--r--vendor/sigs.k8s.io/controller-runtime/pkg/event/event.go55
-rw-r--r--vendor/sigs.k8s.io/controller-runtime/pkg/handler/doc.go38
-rw-r--r--vendor/sigs.k8s.io/controller-runtime/pkg/handler/enqueue.go90
-rw-r--r--vendor/sigs.k8s.io/controller-runtime/pkg/handler/enqueue_mapped.go97
-rw-r--r--vendor/sigs.k8s.io/controller-runtime/pkg/handler/enqueue_owner.go189
-rw-r--r--vendor/sigs.k8s.io/controller-runtime/pkg/handler/eventhandler.go104
-rw-r--r--vendor/sigs.k8s.io/controller-runtime/pkg/healthz/doc.go32
-rw-r--r--vendor/sigs.k8s.io/controller-runtime/pkg/healthz/healthz.go206
-rw-r--r--vendor/sigs.k8s.io/controller-runtime/pkg/internal/controller/controller.go351
-rw-r--r--vendor/sigs.k8s.io/controller-runtime/pkg/internal/controller/metrics/metrics.go78
-rw-r--r--vendor/sigs.k8s.io/controller-runtime/pkg/internal/log/log.go32
-rw-r--r--vendor/sigs.k8s.io/controller-runtime/pkg/internal/objectutil/objectutil.go78
-rw-r--r--vendor/sigs.k8s.io/controller-runtime/pkg/internal/recorder/recorder.go176
-rw-r--r--vendor/sigs.k8s.io/controller-runtime/pkg/leaderelection/doc.go24
-rw-r--r--vendor/sigs.k8s.io/controller-runtime/pkg/leaderelection/leader_election.go126
-rw-r--r--vendor/sigs.k8s.io/controller-runtime/pkg/log/deleg.go216
-rw-r--r--vendor/sigs.k8s.io/controller-runtime/pkg/log/log.go99
-rw-r--r--vendor/sigs.k8s.io/controller-runtime/pkg/log/null.go60
-rw-r--r--vendor/sigs.k8s.io/controller-runtime/pkg/log/warning_handler.go76
-rw-r--r--vendor/sigs.k8s.io/controller-runtime/pkg/manager/doc.go21
-rw-r--r--vendor/sigs.k8s.io/controller-runtime/pkg/manager/internal.go709
-rw-r--r--vendor/sigs.k8s.io/controller-runtime/pkg/manager/manager.go579
-rw-r--r--vendor/sigs.k8s.io/controller-runtime/pkg/manager/signals/doc.go20
-rw-r--r--vendor/sigs.k8s.io/controller-runtime/pkg/manager/signals/signal.go45
-rw-r--r--vendor/sigs.k8s.io/controller-runtime/pkg/manager/signals/signal_posix.go26
-rw-r--r--vendor/sigs.k8s.io/controller-runtime/pkg/manager/signals/signal_windows.go23
-rw-r--r--vendor/sigs.k8s.io/controller-runtime/pkg/metrics/client_go_adapter.go231
-rw-r--r--vendor/sigs.k8s.io/controller-runtime/pkg/metrics/doc.go20
-rw-r--r--vendor/sigs.k8s.io/controller-runtime/pkg/metrics/listener.go52
-rw-r--r--vendor/sigs.k8s.io/controller-runtime/pkg/metrics/registry.go30
-rw-r--r--vendor/sigs.k8s.io/controller-runtime/pkg/metrics/workqueue.go130
-rw-r--r--vendor/sigs.k8s.io/controller-runtime/pkg/predicate/doc.go20
-rw-r--r--vendor/sigs.k8s.io/controller-runtime/pkg/predicate/predicate.go333
-rw-r--r--vendor/sigs.k8s.io/controller-runtime/pkg/ratelimiter/doc.go22
-rw-r--r--vendor/sigs.k8s.io/controller-runtime/pkg/ratelimiter/ratelimiter.go30
-rw-r--r--vendor/sigs.k8s.io/controller-runtime/pkg/reconcile/doc.go21
-rw-r--r--vendor/sigs.k8s.io/controller-runtime/pkg/reconcile/reconcile.go102
-rw-r--r--vendor/sigs.k8s.io/controller-runtime/pkg/recorder/recorder.go31
-rw-r--r--vendor/sigs.k8s.io/controller-runtime/pkg/runtime/inject/doc.go22
-rw-r--r--vendor/sigs.k8s.io/controller-runtime/pkg/runtime/inject/inject.go164
-rw-r--r--vendor/sigs.k8s.io/controller-runtime/pkg/scheme/scheme.go94
-rw-r--r--vendor/sigs.k8s.io/controller-runtime/pkg/source/doc.go22
-rw-r--r--vendor/sigs.k8s.io/controller-runtime/pkg/source/internal/eventsource.go138
-rw-r--r--vendor/sigs.k8s.io/controller-runtime/pkg/source/source.go366
-rw-r--r--vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/decode.go72
-rw-r--r--vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/defaulter.go74
-rw-r--r--vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/defaulter_custom.go85
-rw-r--r--vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/doc.go28
-rw-r--r--vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/http.go146
-rw-r--r--vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/inject.go31
-rw-r--r--vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/multi.go147
-rw-r--r--vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/response.go121
-rw-r--r--vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/validator.go122
-rw-r--r--vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/validator_custom.go111
-rw-r--r--vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/webhook.go255
-rw-r--r--vendor/sigs.k8s.io/controller-runtime/pkg/webhook/alias.go79
-rw-r--r--vendor/sigs.k8s.io/controller-runtime/pkg/webhook/conversion/conversion.go345
-rw-r--r--vendor/sigs.k8s.io/controller-runtime/pkg/webhook/conversion/decoder.go47
-rw-r--r--vendor/sigs.k8s.io/controller-runtime/pkg/webhook/doc.go28
-rw-r--r--vendor/sigs.k8s.io/controller-runtime/pkg/webhook/internal/metrics/metrics.go85
-rw-r--r--vendor/sigs.k8s.io/controller-runtime/pkg/webhook/server.go339
231 files changed, 21851 insertions, 882 deletions
diff --git a/go.mod b/go.mod
index b9c3d90b4..42a773d9e 100644
--- a/go.mod
+++ b/go.mod
@@ -28,8 +28,8 @@ require (
github.com/kubernetes-csi/csi-lib-utils v0.6.1
github.com/mattn/go-sqlite3 v1.14.9
github.com/mitchellh/go-ps v0.0.0-20190716172923-621e5597135b
- github.com/onsi/ginkgo v1.14.0
- github.com/onsi/gomega v1.10.3
+ github.com/onsi/ginkgo v1.16.4
+ github.com/onsi/gomega v1.15.0
github.com/opencontainers/runc v1.0.3 // indirect
github.com/paypal/gatt v0.0.0-20151011220935-4ae819d591cf
github.com/prometheus/client_golang v1.11.0
@@ -62,6 +62,7 @@ require (
k8s.io/utils v0.0.0-20210819203725-bdf08cb9a70a
sigs.k8s.io/apiserver-network-proxy v0.0.27
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.27
+ sigs.k8s.io/controller-runtime v0.10.3
sigs.k8s.io/yaml v1.2.0
)
diff --git a/go.sum b/go.sum
index f02f698e7..32c5d826e 100644
--- a/go.sum
+++ b/go.sum
@@ -154,8 +154,9 @@ github.com/aws/aws-sdk-go v1.38.49 h1:E31vxjCe6a5I+mJLmUGaZobiWmg9KdWaud9IfceYeY
github.com/aws/aws-sdk-go v1.38.49/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro=
github.com/beego/goyaml2 v0.0.0-20130207012346-5545475820dd/go.mod h1:1b+Y/CofkYwXMUU0OhQqGvsY2Bvgr4j6jfT699wyZKQ=
github.com/beego/x2j v0.0.0-20131220205130-a0352aadc542/go.mod h1:kSeGC/p1AbBiEp5kat81+DSQrZenVBZXklMLaELspWU=
-github.com/benbjohnson/clock v1.0.3 h1:vkLuvpK4fmtSCuo60+yC63p7y0BmQ8gm5ZXGuBCJyXg=
github.com/benbjohnson/clock v1.0.3/go.mod h1:bGMdMPoPVvcYyt1gHDf4J2KE153Yf9BuiUKYMaxlTDM=
+github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8=
+github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
github.com/beorn7/perks v0.0.0-20160804104726-4c0e84591b9a/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
@@ -413,6 +414,7 @@ github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/euank/go-kmsg-parser v2.0.0+incompatible h1:cHD53+PLQuuQyLZeriD1V/esuG4MuU0Pjs5y6iknohY=
github.com/euank/go-kmsg-parser v2.0.0+incompatible/go.mod h1:MhmAMZ8V4CYH4ybgdRwPr2TU5ThnS43puaKEMpja1uw=
+github.com/evanphx/json-patch v0.5.2/go.mod h1:ZWS5hhDbVDyob71nXKNL0+PWn6ToqBHMikGIFbs31qQ=
github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
github.com/evanphx/json-patch v4.11.0+incompatible h1:glyUF9yIYtMHzn8xaKw5rMhdWcwsYV8dZHIq5567/xs=
github.com/evanphx/json-patch v4.11.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
@@ -458,6 +460,8 @@ github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7
github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU=
github.com/go-logr/logr v0.4.0 h1:K7/B1jt6fIBQVd4Owv2MqGQClcgf0R266+7C/QjRcLc=
github.com/go-logr/logr v0.4.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU=
+github.com/go-logr/zapr v0.4.0 h1:uc1uML3hRYL9/ZZPdgHS/n8Nzo+eaYL/Efxkkamf7OM=
+github.com/go-logr/zapr v0.4.0/go.mod h1:tabnROwaDl0UNxkVeFRbY8bwB37GwRv0P8lg6aAiEnk=
github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg=
@@ -479,6 +483,7 @@ github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG
github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs=
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
+github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
github.com/gobuffalo/logger v1.0.3 h1:YaXOTHNPCvkqqA7w05A4v0k2tCdpr+sgFlgINbQ6gqc=
github.com/gobuffalo/logger v1.0.3/go.mod h1:SoeejUwldiS7ZsyCBphOGURmWdwUFXs0J7TCjEhjKxM=
github.com/gobuffalo/packd v1.0.0 h1:6ERZvJHfe24rfFmA9OaoKBdC7+c9sydrytMg8SdFGBM=
@@ -668,6 +673,7 @@ github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NH
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/ishidawataru/sctp v0.0.0-20190723014705-7c296d48a2b5/go.mod h1:DM4VvS+hD/kDi1U1QsX2fnZowwBhqD0Dk3bRPKF/Oc8=
github.com/j-keck/arping v0.0.0-20160618110441-2cf9dc699c56/go.mod h1:ymszkNOg6tORTn+6F6j+Jc8TOr5osrynvN6ivFWZ2GA=
+github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
github.com/jmespath/go-jmespath v0.0.0-20160803190731-bd40a432e4c7/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
github.com/jmespath/go-jmespath v0.3.0/go.mod h1:9QtRXoHjLGCJ5IBSaohpXITPlowMeeYCZ7fLUTSywik=
@@ -839,8 +845,9 @@ github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f h1:y5//uYreIhSUg3J
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw=
github.com/ncw/swift v1.0.47/go.mod h1:23YIA4yWVnGwv2dQlN4bB7egfYX6YLn0Yo/S6zZO/ZM=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
-github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78=
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
+github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
+github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=
github.com/olekukonko/tablewriter v0.0.4/go.mod h1:zq6QwlOf5SlnkVbMSr5EoBv3636FWnp+qbPhuoO21uA=
github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
@@ -851,16 +858,18 @@ github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+
github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
-github.com/onsi/ginkgo v1.14.0 h1:2mOpI4JVVPBN+WQRa0WKH2eXR+Ey+uK4n7Zj0aYpIQA=
github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY=
+github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc=
+github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
github.com/onsi/gomega v0.0.0-20151007035656-2152b45fa28a/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
github.com/onsi/gomega v1.8.1/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA=
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
-github.com/onsi/gomega v1.10.3 h1:gph6h/qe9GSUw1NhH1gp+qb+h8rXD8Cy60Z32Qw3ELA=
github.com/onsi/gomega v1.10.3/go.mod h1:V9xEwhxec5O8UDM77eCW8vLymOMltsqPVYWrpDsH8xc=
+github.com/onsi/gomega v1.15.0 h1:WjP/FQ/sk43MRmnEcT+MlDw2TFvkrXlprrPST/IudjU=
+github.com/onsi/gomega v1.15.0/go.mod h1:cIuvLEne0aoVhAgh/O6ac0Op8WWw9H6eYCriF+tEHG0=
github.com/opencontainers/go-digest v0.0.0-20170106003457-a6d0ee40d420/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
github.com/opencontainers/go-digest v0.0.0-20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
@@ -1146,8 +1155,9 @@ go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/
go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4=
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
-go.uber.org/zap v1.17.0 h1:MTjgFu6ZLKvY6Pvaqk97GlxNBuMpV4Hy/3P6tRGlI2U=
go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo=
+go.uber.org/zap v1.19.0 h1:mZQZefskPPCMIBCSEH0v2/iUqqLrYtaeqwD6FUGUnFE=
+go.uber.org/zap v1.19.0/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI=
golang.org/x/crypto v0.0.0-20171113213409-9f005a07e0d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20181009213950-7c1a557ab941/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
@@ -1271,6 +1281,7 @@ golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
+golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
golang.org/x/net v0.0.0-20210520170846-37e1c6afe023/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211209124913-491a49abca63 h1:iocB37TsdFuN6IBRZ+ry36wrkoV51/tl5vOWqkcPGvY=
golang.org/x/net v0.0.0-20211209124913-491a49abca63/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
@@ -1374,6 +1385,7 @@ golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201202213521-69691e467435/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -1388,6 +1400,7 @@ golang.org/x/sys v0.0.0-20210426230700-d19ff857e887/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20210817190340-bfb29a6856f2/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27 h1:XDXtA5hveEEV8JB2l7nhMTp3t3cHp9ZpwcdjqyEWLlo=
golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
@@ -1468,6 +1481,7 @@ golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82u
golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
+golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
@@ -1479,6 +1493,8 @@ golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8T
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+gomodules.xyz/jsonpatch/v2 v2.2.0 h1:4pT439QV83L+G9FkcCriY6EkpcK6r6bK+A5FBUMI7qY=
+gomodules.xyz/jsonpatch/v2 v2.2.0/go.mod h1:WXp+iVDkoLQqPudfQ9GBlwB2eZ5DKOnjQZCYdOS8GPY=
gonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo=
gonum.org/v1/gonum v0.0.0-20190331200053-3d26580ed485/go.mod h1:2ltnJ7xHfj0zHS40VVPYEAAMTa3ZGguvHGBSJeRWqE0=
gonum.org/v1/gonum v0.6.2/go.mod h1:9mxDZsDKxgMAuccQkewq682L+0eCu4dCN2yonUJTCLU=
@@ -1671,9 +1687,11 @@ k8s.io/api v0.20.1/go.mod h1:KqwcCVogGxQY3nBlRpwt+wpAMF/KjaCc7RpywacvqUo=
k8s.io/api v0.20.4/go.mod h1:++lNL1AJMkDymriNniQsWRkMDzRaX2Y/POTUi8yvqYQ=
k8s.io/api v0.20.6/go.mod h1:X9e8Qag6JV/bL5G6bU8sdVRltWKmdHsFUGS3eVndqE8=
k8s.io/api v0.20.10/go.mod h1:0kei3F6biGjtRQBo5dUeujq6Ji3UCh9aOSfp/THYd7I=
+k8s.io/api v0.22.2/go.mod h1:y3ydYpLJAaDI+BbSe2xmGcqxiWHmWjkEeIbiwHvnPR8=
k8s.io/api v0.22.4/go.mod h1:Rgs+9gIGYC5laXQSZZ9JqT5NevNgoGiOdVWi1BAB3qk=
k8s.io/api v0.22.6 h1:acjE5ABt0KpsBI9QCtLqaQEPSF94jOtE/LoFxSYasSE=
k8s.io/api v0.22.6/go.mod h1:q1F7IfaNrbi/83ebLy3YFQYLjPSNyunZ/IXQxMmbwCg=
+k8s.io/apiextensions-apiserver v0.22.2/go.mod h1:2E0Ve/isxNl7tWLSUDgi6+cmwHi5fQRdwGVCxbC+KFA=
k8s.io/apiextensions-apiserver v0.22.4/go.mod h1:kH9lxD8dbJ+k0ZizGET55lFgdGjO8t45fgZnCVdZEpw=
k8s.io/apiextensions-apiserver v0.22.6 h1:TH+9+EGtoVzzbrlfSDnObzFTnyXKqw1NBfT5XFATeJI=
k8s.io/apiextensions-apiserver v0.22.6/go.mod h1:wNsLwy8mfIkGThiv4Qq/Hy4qRazViKXqmH5pfYiRKyY=
@@ -1681,12 +1699,14 @@ k8s.io/apimachinery v0.20.1/go.mod h1:WlLqWAHZGg07AeltaI0MV5uk1Omp8xaN0JGLY6gkRp
k8s.io/apimachinery v0.20.4/go.mod h1:WlLqWAHZGg07AeltaI0MV5uk1Omp8xaN0JGLY6gkRpU=
k8s.io/apimachinery v0.20.6/go.mod h1:ejZXtW1Ra6V1O5H8xPBGz+T3+4gfkTCeExAHKU57MAc=
k8s.io/apimachinery v0.20.10/go.mod h1:kQa//VOAwyVwJ2+L9kOREbsnryfsGSkSM1przND4+mw=
+k8s.io/apimachinery v0.22.2/go.mod h1:O3oNtNadZdeOMxHFVxOreoznohCpy0z6mocxbZr7oJ0=
k8s.io/apimachinery v0.22.4/go.mod h1:yU6oA6Gnax9RrxGzVvPFFJ+mpnW6PBSqp0sx0I0HHW0=
k8s.io/apimachinery v0.22.6 h1:z7vxNRkFX0NToA+8D17kzLZ/T4t+DqwzUlqqbqRepRs=
k8s.io/apimachinery v0.22.6/go.mod h1:ZvVLP5iLhwVFg2Yx9Gh5W0um0DUauExbRhe+2Z8I1EU=
k8s.io/apiserver v0.20.1/go.mod h1:ro5QHeQkgMS7ZGpvf4tSMx6bBOgPfE+f52KwvXfScaU=
k8s.io/apiserver v0.20.4/go.mod h1:Mc80thBKOyy7tbvFtB4kJv1kbdD0eIH8k8vianJcbFM=
k8s.io/apiserver v0.20.6/go.mod h1:QIJXNt6i6JB+0YQRNcS0hdRHJlMhflFmsBDeSgT1r8Q=
+k8s.io/apiserver v0.22.2/go.mod h1:vrpMmbyjWrgdyOvZTSpsusQq5iigKNWv9o9KlDAbBHI=
k8s.io/apiserver v0.22.4/go.mod h1:38WmcUZiiy41A7Aty8/VorWRa8vDGqoUzDf2XYlku0E=
k8s.io/apiserver v0.22.6 h1:5MXAa5zBEd7dvCmaqrYV5GohA5jvNAmJX3Hy78JAGDY=
k8s.io/apiserver v0.22.6/go.mod h1:OlL1rGa2kKWGj2JEXnwBcul/BwC9Twe95gm4ohtiIIs=
@@ -1697,6 +1717,7 @@ k8s.io/client-go v0.20.1/go.mod h1:/zcHdt1TeWSd5HoUe6elJmHSQ6uLLgp4bIJHVEuy+/Y=
k8s.io/client-go v0.20.4/go.mod h1:LiMv25ND1gLUdBeYxBIwKpkSC5IsozMMmOOeSJboP+k=
k8s.io/client-go v0.20.6/go.mod h1:nNQMnOvEUEsOzRRFIIkdmYOjAZrC8bgq0ExboWSU1I0=
k8s.io/client-go v0.20.10/go.mod h1:fFg+aLoasv/R+xiVaWjxeqGFYltzgQcOQzkFaSRfnJ0=
+k8s.io/client-go v0.22.2/go.mod h1:sAlhrkVDf50ZHx6z4K0S40wISNTarf1r800F+RlCF6U=
k8s.io/client-go v0.22.4/go.mod h1:Yzw4e5e7h1LNHA4uqnMVrpEpUs1hJOiuBsJKIlRCHDA=
k8s.io/client-go v0.22.6 h1:ugAXeC312xeGXsn7zTRz+btgtLBnW3qYhtUUpVQL7YE=
k8s.io/client-go v0.22.6/go.mod h1:TffU4AV2idZGeP+g3kdFZP+oHVHWPL1JYFySOALriw0=
@@ -1704,6 +1725,7 @@ k8s.io/cloud-provider v0.22.6 h1:KGKfTVdw7xCWn+SztgsloO2/wUbVlcjj/+xYaFIYFYk=
k8s.io/cloud-provider v0.22.6/go.mod h1:qKWDzOCIsSWlPvC4txa9X+IuxeJX8LWf9jz/ClpBIPQ=
k8s.io/cluster-bootstrap v0.22.6 h1:Jm1MDTPSxHRQp9m4jT44fVv9S2BiEivZ+R8JjEEdTdQ=
k8s.io/cluster-bootstrap v0.22.6/go.mod h1:G8vRWaBElK/3fk3UsnqFKO4Sr8LyX6urLqdkuPXOC8k=
+k8s.io/code-generator v0.22.2/go.mod h1:eV77Y09IopzeXOJzndrDyCI88UBok2h6WxAlBwpxa+o=
k8s.io/code-generator v0.22.4/go.mod h1:qjYl54pQ/emhkT0UxbufbREYJMWsHNNV/jSVwhYZQGw=
k8s.io/code-generator v0.22.6 h1:nskDbd+etRmWhB/WoaevaFIJfL+lDt5HI7wAIvA4CcQ=
k8s.io/code-generator v0.22.6/go.mod h1:iOZwYADSgFPNGWfqHFfg1V0TNJnl1t0WyZluQp4baqU=
@@ -1711,6 +1733,7 @@ k8s.io/component-base v0.20.1/go.mod h1:guxkoJnNoh8LNrbtiQOlyp2Y2XFCZQmrcg2n/DeY
k8s.io/component-base v0.20.4/go.mod h1:t4p9EdiagbVCJKrQ1RsA5/V4rFQNDfRlevJajlGwgjI=
k8s.io/component-base v0.20.6/go.mod h1:6f1MPBAeI+mvuts3sIdtpjljHWBQ2cIy38oBIWMYnrM=
k8s.io/component-base v0.20.10/go.mod h1:ZKOEin1xu68aJzxgzl5DZSp5J1IrjAOPlPN90/t6OI8=
+k8s.io/component-base v0.22.2/go.mod h1:5Br2QhI9OTe79p+TzPe9JKNQYvEKbq9rTJDWllunGug=
k8s.io/component-base v0.22.4/go.mod h1:MrSaQy4a3tFVViff8TZL6JHYSewNCLshZCwHYM58v5A=
k8s.io/component-base v0.22.6 h1:YgGMDVnr97rhn0eljuYIU/9XFyz8JVDM30slMYrDgPc=
k8s.io/component-base v0.22.6/go.mod h1:ngHLefY4J5fq2fApNdbWyj4yh0lvw36do4aAjNN8rc8=
@@ -1779,6 +1802,8 @@ sigs.k8s.io/apiserver-network-proxy v0.0.27 h1:SE5JOrvIMty/rRW64k+4wfoH6V04V5If3
sigs.k8s.io/apiserver-network-proxy v0.0.27/go.mod h1:du+Uh7WMRMVMnDwJDx2EahhL+pKqPHLwbWqkNHtlU+o=
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.27 h1:KQOkVzXrLNb0EP6W0FD6u3CCPAwgXFYwZitbj7K0P0Y=
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.27/go.mod h1:tq2nT0Kx7W+/f2JVE+zxYtUhdjuELJkVpNz+x/QN5R4=
+sigs.k8s.io/controller-runtime v0.10.3 h1:s5Ttmw/B4AuIbwrXD3sfBkXwnPMMWrqpVj4WRt1dano=
+sigs.k8s.io/controller-runtime v0.10.3/go.mod h1:CQp8eyUQZ/Q7PJvnIrB6/hgfTC1kBkGylwsLgOQi1WY=
sigs.k8s.io/kustomize/api v0.8.11 h1:LzQzlq6Z023b+mBtc6v72N2mSHYmN8x7ssgbf/hv0H8=
sigs.k8s.io/kustomize/api v0.8.11/go.mod h1:a77Ls36JdfCWojpUqR6m60pdGY1AYFix4AH83nJtY1g=
sigs.k8s.io/kustomize/cmd/config v0.9.13/go.mod h1:7547FLF8W/lTaDf0BDqFTbZxM9zqwEJqCKN9sSR0xSs=
diff --git a/vendor/github.com/nxadm/tail/.gitignore b/vendor/github.com/nxadm/tail/.gitignore
index fa81aa93a..35d9351d3 100644
--- a/vendor/github.com/nxadm/tail/.gitignore
+++ b/vendor/github.com/nxadm/tail/.gitignore
@@ -1,2 +1,3 @@
.idea/
-.test/ \ No newline at end of file
+.test/
+examples/_* \ No newline at end of file
diff --git a/vendor/github.com/nxadm/tail/.travis.yml b/vendor/github.com/nxadm/tail/.travis.yml
deleted file mode 100644
index 95dd3bd78..000000000
--- a/vendor/github.com/nxadm/tail/.travis.yml
+++ /dev/null
@@ -1,16 +0,0 @@
-language: go
-
-script:
- - go test -race -v ./...
-
-go:
- - "1.9"
- - "1.10"
- - "1.11"
- - "1.12"
- - "1.13"
- - tip
-
-matrix:
- allow_failures:
- - go: tip
diff --git a/vendor/github.com/nxadm/tail/CHANGES.md b/vendor/github.com/nxadm/tail/CHANGES.md
index ef1b5fbed..224e54b44 100644
--- a/vendor/github.com/nxadm/tail/CHANGES.md
+++ b/vendor/github.com/nxadm/tail/CHANGES.md
@@ -1,4 +1,14 @@
-# Version v1.4.4
+# Version v1.4.7-v1.4.8
+* Documentation updates.
+* Small linter cleanups.
+* Added example in test.
+
+# Version v1.4.6
+
+* Document the usage of Cleanup when re-reading a file (thanks to @lesovsky) for issue #18.
+* Add example directories with example and tests for issues.
+
+# Version v1.4.4-v1.4.5
* Fix of checksum problem because of forced tag. No changes to the code.
diff --git a/vendor/github.com/nxadm/tail/README.md b/vendor/github.com/nxadm/tail/README.md
index dbb6c1727..f47939c74 100644
--- a/vendor/github.com/nxadm/tail/README.md
+++ b/vendor/github.com/nxadm/tail/README.md
@@ -1,36 +1,44 @@
-[![Build Status](https://travis-ci.org/nxadm/tail.svg?branch=master)](https://travis-ci.org/nxadm/tail)
+![ci](https://github.com/nxadm/tail/workflows/ci/badge.svg)[![Go Reference](https://pkg.go.dev/badge/github.com/nxadm/tail.svg)](https://pkg.go.dev/github.com/nxadm/tail)
-This is repo is forked from the dormant upstream repo at
-[hpcloud](https://github.com/hpcloud/tail). This fork adds support for go
-modules, updates the dependencies, adds features and fixes bugs. Go 1.9 is
-the oldest compiler release supported.
+# tail functionality in Go
-# Go package for tail-ing files
+nxadm/tail provides a Go library that emulates the features of the BSD `tail`
+program. The library comes with full support for truncation/move detection as
+it is designed to work with log rotation tools. The library works on all
+operating systems supported by Go, including POSIX systems like Linux and
+*BSD, and MS Windows. Go 1.9 is the oldest compiler release supported.
-A Go package striving to emulate the features of the BSD `tail` program.
+A simple example:
```Go
-t, err := tail.TailFile("/var/log/nginx.log", tail.Config{Follow: true})
+// Create a tail
+t, err := tail.TailFile(
+ "/var/log/nginx.log", tail.Config{Follow: true, ReOpen: true})
if err != nil {
panic(err)
}
+// Print the text of each received line
for line := range t.Lines {
fmt.Println(line.Text)
}
```
-See [API documentation](http://godoc.org/github.com/nxadm/tail).
-
-## Log rotation
-
-Tail comes with full support for truncation/move detection as it is
-designed to work with log rotation tools.
+See [API documentation](https://pkg.go.dev/github.com/nxadm/tail).
## Installing
go get github.com/nxadm/tail/...
-## Windows support
+## History
+
+This project is an active, drop-in replacement for the
+[abandoned](https://en.wikipedia.org/wiki/HPE_Helion) Go tail library at
+[hpcloud](https://github.com/hpcloud/tail). Next to
+[addressing open issues/PRs of the original project](https://github.com/nxadm/tail/issues/6),
+nxadm/tail continues the development by keeping up to date with the Go toolchain
+(e.g. go modules) and dependencies, completing the documentation, adding features
+and fixing bugs.
-This package [needs assistance](https://github.com/nxadm/tail/labels/Windows) for full Windows support.
+## Examples
+Examples, e.g. used to debug an issue, are kept in the [examples directory](/examples). \ No newline at end of file
diff --git a/vendor/github.com/nxadm/tail/appveyor.yml b/vendor/github.com/nxadm/tail/appveyor.yml
deleted file mode 100644
index e149bc62d..000000000
--- a/vendor/github.com/nxadm/tail/appveyor.yml
+++ /dev/null
@@ -1,11 +0,0 @@
-version: 0.{build}
-skip_tags: true
-cache: C:\Users\appveyor\AppData\Local\NuGet\Cache
-build_script:
-- SET GOPATH=c:\workspace
-- go test -v -race ./...
-test: off
-clone_folder: c:\workspace\src\github.com\nxadm\tail
-branches:
- only:
- - master
diff --git a/vendor/github.com/nxadm/tail/go.mod b/vendor/github.com/nxadm/tail/go.mod
index fb10d42af..5de9a6061 100644
--- a/vendor/github.com/nxadm/tail/go.mod
+++ b/vendor/github.com/nxadm/tail/go.mod
@@ -3,7 +3,6 @@ module github.com/nxadm/tail
go 1.13
require (
- github.com/fsnotify/fsnotify v1.4.7
- golang.org/x/sys v0.0.0-20190904154756-749cb33beabd // indirect
+ github.com/fsnotify/fsnotify v1.4.9
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7
)
diff --git a/vendor/github.com/nxadm/tail/go.sum b/vendor/github.com/nxadm/tail/go.sum
index b391f1904..3485daedb 100644
--- a/vendor/github.com/nxadm/tail/go.sum
+++ b/vendor/github.com/nxadm/tail/go.sum
@@ -1,6 +1,6 @@
-github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
-github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
-golang.org/x/sys v0.0.0-20190904154756-749cb33beabd h1:DBH9mDw0zluJT/R+nGuV3jWFWLFaHyYZWD4tOT+cjn0=
-golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
+github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
+golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9 h1:L2auWcuQIvxz9xSEqzESnV/QN/gNRXNApHi3fYwl2w0=
+golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
diff --git a/vendor/github.com/nxadm/tail/tail.go b/vendor/github.com/nxadm/tail/tail.go
index 58d3c4b95..37ea4411e 100644
--- a/vendor/github.com/nxadm/tail/tail.go
+++ b/vendor/github.com/nxadm/tail/tail.go
@@ -1,6 +1,12 @@
+// Copyright (c) 2019 FOSS contributors of https://github.com/nxadm/tail
// Copyright (c) 2015 HPE Software Inc. All rights reserved.
// Copyright (c) 2013 ActiveState Software Inc. All rights reserved.
+//nxadm/tail provides a Go library that emulates the features of the BSD `tail`
+//program. The library comes with full support for truncation/move detection as
+//it is designed to work with log rotation tools. The library works on all
+//operating systems supported by Go, including POSIX systems like Linux and
+//*BSD, and MS Windows. Go 1.9 is the oldest compiler release supported.
package tail
import (
@@ -22,26 +28,31 @@ import (
)
var (
+ // ErrStop is returned when the tail of a file has been marked to be stopped.
ErrStop = errors.New("tail should now stop")
)
type Line struct {
- Text string
- Num int
- SeekInfo SeekInfo
- Time time.Time
- Err error // Error from tail
+ Text string // The contents of the file
+ Num int // The line number
+ SeekInfo SeekInfo // SeekInfo
+ Time time.Time // Present time
+ Err error // Error from tail
}
-// NewLine returns a Line with present time.
+// Deprecated: this function is no longer used internally and it has little of no
+// use in the API. As such, it will be removed from the API in a future major
+// release.
+//
+// NewLine returns a * pointer to a Line struct.
func NewLine(text string, lineNum int) *Line {
return &Line{text, lineNum, SeekInfo{}, time.Now(), nil}
}
-// SeekInfo represents arguments to `io.Seek`
+// SeekInfo represents arguments to io.Seek. See: https://golang.org/pkg/io/#SectionReader.Seek
type SeekInfo struct {
Offset int64
- Whence int // io.Seek*
+ Whence int
}
type logger interface {
@@ -59,26 +70,28 @@ type logger interface {
// Config is used to specify how a file must be tailed.
type Config struct {
// File-specifc
- Location *SeekInfo // Seek to this location before tailing
- ReOpen bool // Reopen recreated files (tail -F)
- MustExist bool // Fail early if the file does not exist
- Poll bool // Poll for file changes instead of using inotify
- Pipe bool // Is a named pipe (mkfifo)
- RateLimiter *ratelimiter.LeakyBucket
+ Location *SeekInfo // Tail from this location. If nil, start at the beginning of the file
+ ReOpen bool // Reopen recreated files (tail -F)
+ MustExist bool // Fail early if the file does not exist
+ Poll bool // Poll for file changes instead of using the default inotify
+ Pipe bool // The file is a named pipe (mkfifo)
// Generic IO
Follow bool // Continue looking for new lines (tail -f)
MaxLineSize int // If non-zero, split longer lines into multiple lines
- // Logger, when nil, is set to tail.DefaultLogger
- // To disable logging: set field to tail.DiscardingLogger
+ // Optionally, use a ratelimiter (e.g. created by the ratelimiter/NewLeakyBucket function)
+ RateLimiter *ratelimiter.LeakyBucket
+
+ // Optionally use a Logger. When nil, the Logger is set to tail.DefaultLogger.
+ // To disable logging, set it to tail.DiscardingLogger
Logger logger
}
type Tail struct {
- Filename string
- Lines chan *Line
- Config
+ Filename string // The filename
+ Lines chan *Line // A consumable channel of *Line
+ Config // Tail.Configuration
file *os.File
reader *bufio.Reader
@@ -93,16 +106,17 @@ type Tail struct {
}
var (
- // DefaultLogger is used when Config.Logger == nil
+ // DefaultLogger logs to os.Stderr and it is used when Config.Logger == nil
DefaultLogger = log.New(os.Stderr, "", log.LstdFlags)
// DiscardingLogger can be used to disable logging output
DiscardingLogger = log.New(ioutil.Discard, "", 0)
)
-// TailFile begins tailing the file. Output stream is made available
-// via the `Tail.Lines` channel. To handle errors during tailing,
-// invoke the `Wait` or `Err` method after finishing reading from the
-// `Lines` channel.
+// TailFile begins tailing the file. And returns a pointer to a Tail struct
+// and an error. An output stream is made available via the Tail.Lines
+// channel (e.g. to be looped and printed). To handle errors during tailing,
+// after finishing reading from the Lines channel, invoke the `Wait` or `Err`
+// method on the returned *Tail.
func TailFile(filename string, config Config) (*Tail, error) {
if config.ReOpen && !config.Follow {
util.Fatal("cannot set ReOpen without Follow.")
@@ -138,10 +152,9 @@ func TailFile(filename string, config Config) (*Tail, error) {
return t, nil
}
-// Tell returns the file's current position, like stdio's ftell().
-// But this value is not very accurate.
-// One line from the chan(tail.Lines) may have been read,
-// so it may have lost one line.
+// Tell returns the file's current position, like stdio's ftell() and an error.
+// Beware that this value may not be completely accurate because one line from
+// the chan(tail.Lines) may have been read already.
func (tail *Tail) Tell() (offset int64, err error) {
if tail.file == nil {
return
@@ -167,7 +180,8 @@ func (tail *Tail) Stop() error {
return tail.Wait()
}
-// StopAtEOF stops tailing as soon as the end of the file is reached.
+// StopAtEOF stops tailing as soon as the end of the file is reached. The function
+// returns an error,
func (tail *Tail) StopAtEOF() error {
tail.Kill(errStopAtEOF)
return tail.Wait()
@@ -435,6 +449,7 @@ func (tail *Tail) sendLine(line string) bool {
// Cleanup removes inotify watches added by the tail package. This function is
// meant to be invoked from a process's exit handler. Linux kernel may not
// automatically remove inotify watches after the process exits.
+// If you plan to re-read a file, don't call Cleanup in between.
func (tail *Tail) Cleanup() {
watch.Cleanup(tail.Filename)
}
diff --git a/vendor/github.com/nxadm/tail/tail_posix.go b/vendor/github.com/nxadm/tail/tail_posix.go
index 1b94520ec..23e071dea 100644
--- a/vendor/github.com/nxadm/tail/tail_posix.go
+++ b/vendor/github.com/nxadm/tail/tail_posix.go
@@ -1,3 +1,4 @@
+// Copyright (c) 2019 FOSS contributors of https://github.com/nxadm/tail
// +build !windows
package tail
@@ -6,6 +7,11 @@ import (
"os"
)
+// Deprecated: this function is only useful internally and, as such,
+// it will be removed from the API in a future major release.
+//
+// OpenFile proxies a os.Open call for a file so it can be correctly tailed
+// on POSIX and non-POSIX OSes like MS Windows.
func OpenFile(name string) (file *os.File, err error) {
return os.Open(name)
}
diff --git a/vendor/github.com/nxadm/tail/tail_windows.go b/vendor/github.com/nxadm/tail/tail_windows.go
index 4aaceea28..da0d2f39c 100644
--- a/vendor/github.com/nxadm/tail/tail_windows.go
+++ b/vendor/github.com/nxadm/tail/tail_windows.go
@@ -1,12 +1,19 @@
+// Copyright (c) 2019 FOSS contributors of https://github.com/nxadm/tail
// +build windows
package tail
import (
- "github.com/nxadm/tail/winfile"
"os"
+
+ "github.com/nxadm/tail/winfile"
)
+// Deprecated: this function is only useful internally and, as such,
+// it will be removed from the API in a future major release.
+//
+// OpenFile proxies a os.Open call for a file so it can be correctly tailed
+// on POSIX and non-POSIX OSes like MS Windows.
func OpenFile(name string) (file *os.File, err error) {
return winfile.OpenFile(name, os.O_RDONLY, 0)
}
diff --git a/vendor/github.com/nxadm/tail/util/util.go b/vendor/github.com/nxadm/tail/util/util.go
index 2ba0ed71c..b64caa212 100644
--- a/vendor/github.com/nxadm/tail/util/util.go
+++ b/vendor/github.com/nxadm/tail/util/util.go
@@ -1,3 +1,4 @@
+// Copyright (c) 2019 FOSS contributors of https://github.com/nxadm/tail
// Copyright (c) 2015 HPE Software Inc. All rights reserved.
// Copyright (c) 2013 ActiveState Software Inc. All rights reserved.
diff --git a/vendor/github.com/nxadm/tail/watch/filechanges.go b/vendor/github.com/nxadm/tail/watch/filechanges.go
index f80aead9a..5b65f42ae 100644
--- a/vendor/github.com/nxadm/tail/watch/filechanges.go
+++ b/vendor/github.com/nxadm/tail/watch/filechanges.go
@@ -1,3 +1,4 @@
+// Copyright (c) 2019 FOSS contributors of https://github.com/nxadm/tail
package watch
type FileChanges struct {
diff --git a/vendor/github.com/nxadm/tail/watch/inotify.go b/vendor/github.com/nxadm/tail/watch/inotify.go
index 439921810..cbd11ad8d 100644
--- a/vendor/github.com/nxadm/tail/watch/inotify.go
+++ b/vendor/github.com/nxadm/tail/watch/inotify.go
@@ -1,3 +1,4 @@
+// Copyright (c) 2019 FOSS contributors of https://github.com/nxadm/tail
// Copyright (c) 2015 HPE Software Inc. All rights reserved.
// Copyright (c) 2013 ActiveState Software Inc. All rights reserved.
diff --git a/vendor/github.com/nxadm/tail/watch/inotify_tracker.go b/vendor/github.com/nxadm/tail/watch/inotify_tracker.go
index a94bcd4cb..cb9572a03 100644
--- a/vendor/github.com/nxadm/tail/watch/inotify_tracker.go
+++ b/vendor/github.com/nxadm/tail/watch/inotify_tracker.go
@@ -1,3 +1,4 @@
+// Copyright (c) 2019 FOSS contributors of https://github.com/nxadm/tail
// Copyright (c) 2015 HPE Software Inc. All rights reserved.
// Copyright (c) 2013 ActiveState Software Inc. All rights reserved.
diff --git a/vendor/github.com/nxadm/tail/watch/polling.go b/vendor/github.com/nxadm/tail/watch/polling.go
index fb1706908..74e10aa42 100644
--- a/vendor/github.com/nxadm/tail/watch/polling.go
+++ b/vendor/github.com/nxadm/tail/watch/polling.go
@@ -1,3 +1,4 @@
+// Copyright (c) 2019 FOSS contributors of https://github.com/nxadm/tail
// Copyright (c) 2015 HPE Software Inc. All rights reserved.
// Copyright (c) 2013 ActiveState Software Inc. All rights reserved.
diff --git a/vendor/github.com/nxadm/tail/watch/watch.go b/vendor/github.com/nxadm/tail/watch/watch.go
index 2e1783ef0..2b5112805 100644
--- a/vendor/github.com/nxadm/tail/watch/watch.go
+++ b/vendor/github.com/nxadm/tail/watch/watch.go
@@ -1,3 +1,4 @@
+// Copyright (c) 2019 FOSS contributors of https://github.com/nxadm/tail
// Copyright (c) 2015 HPE Software Inc. All rights reserved.
// Copyright (c) 2013 ActiveState Software Inc. All rights reserved.
diff --git a/vendor/github.com/nxadm/tail/winfile/winfile.go b/vendor/github.com/nxadm/tail/winfile/winfile.go
index aa7e7bc5d..4562ac7c2 100644
--- a/vendor/github.com/nxadm/tail/winfile/winfile.go
+++ b/vendor/github.com/nxadm/tail/winfile/winfile.go
@@ -1,3 +1,4 @@
+// Copyright (c) 2019 FOSS contributors of https://github.com/nxadm/tail
// +build windows
package winfile
diff --git a/vendor/github.com/onsi/ginkgo/.travis.yml b/vendor/github.com/onsi/ginkgo/.travis.yml
index 079af2431..ea0966d5b 100644
--- a/vendor/github.com/onsi/ginkgo/.travis.yml
+++ b/vendor/github.com/onsi/ginkgo/.travis.yml
@@ -1,8 +1,8 @@
language: go
go:
- - 1.13.x
- - 1.14.x
- tip
+ - 1.16.x
+ - 1.15.x
cache:
directories:
@@ -16,10 +16,9 @@ install:
- GO111MODULE="off" go get golang.org/x/tools/cmd/cover
- GO111MODULE="off" go get github.com/onsi/gomega
- GO111MODULE="off" go install github.com/onsi/ginkgo/ginkgo
- - export PATH=$PATH:$HOME/gopath/bin
+ - export PATH=$GOPATH/bin:$PATH
script:
- - GO111MODULE="on" go mod tidy
- - diff -u <(echo -n) <(git diff go.mod)
- - diff -u <(echo -n) <(git diff go.sum)
- - $HOME/gopath/bin/ginkgo -r --randomizeAllSpecs --randomizeSuites --race --trace && go vet
+ - GO111MODULE="on" go mod tidy && git diff --exit-code go.mod go.sum
+ - go vet
+ - ginkgo -r --randomizeAllSpecs --randomizeSuites --race --trace
diff --git a/vendor/github.com/onsi/ginkgo/CHANGELOG.md b/vendor/github.com/onsi/ginkgo/CHANGELOG.md
index bdf18327e..494abdbfb 100644
--- a/vendor/github.com/onsi/ginkgo/CHANGELOG.md
+++ b/vendor/github.com/onsi/ginkgo/CHANGELOG.md
@@ -1,3 +1,68 @@
+## 1.16.4
+
+### Fixes
+1.16.4 retracts 1.16.3. There are no code changes. The 1.16.3 tag was associated with the wrong commit and an attempt to change it after-the-fact has proven problematic. 1.16.4 retracts 1.16.3 in Ginkgo's go.mod and creates a new, correctly tagged, release.
+
+## 1.16.3
+
+### Features
+- Measure is now deprecated and emits a deprecation warning.
+
+## 1.16.2
+
+### Fixes
+- Deprecations can be suppressed by setting an `ACK_GINKGO_DEPRECATIONS=<semver>` environment variable.
+
+## 1.16.1
+
+### Fixes
+- Supress --stream deprecation warning on windows (#793)
+
+## 1.16.0
+
+### Features
+- Advertise Ginkgo 2.0. Introduce deprecations. [9ef1913]
+ - Update README.md to advertise that Ginkgo 2.0 is coming.
+ - Backport the 2.0 DeprecationTracker and start alerting users
+ about upcoming deprecations.
+
+- Add slim-sprig template functions to bootstrap/generate (#775) [9162b86]
+
+### Fixes
+- Fix accidental reference to 1488 (#784) [9fb7fe4]
+
+## 1.15.2
+
+### Fixes
+- ignore blank `-focus` and `-skip` flags (#780) [e90a4a0]
+
+## 1.15.1
+
+### Fixes
+- reporters/junit: Use `system-out` element instead of `passed` (#769) [9eda305]
+
+## 1.15.0
+
+### Features
+- Adds 'outline' command to print the outline of specs/containers in a file (#754) [071c369] [6803cc3] [935b538] [06744e8] [0c40583]
+- Add support for using template to generate tests (#752) [efb9e69]
+- Add a Chinese Doc #755 (#756) [5207632]
+- cli: allow multiple -focus and -skip flags (#736) [9a782fb]
+
+### Fixes
+- Add _internal to filename of tests created with internal flag (#751) [43c12da]
+
+## 1.14.2
+
+### Fixes
+- correct handling windows backslash in import path (#721) [97f3d51]
+- Add additional methods to GinkgoT() to improve compatibility with the testing.TB interface [b5fe44d]
+
+## 1.14.1
+
+### Fixes
+- Discard exported method declaration when running ginkgo bootstrap (#558) [f4b0240]
+
## 1.14.0
### Features
diff --git a/vendor/github.com/onsi/ginkgo/README.md b/vendor/github.com/onsi/ginkgo/README.md
index fab114580..05321e6ea 100644
--- a/vendor/github.com/onsi/ginkgo/README.md
+++ b/vendor/github.com/onsi/ginkgo/README.md
@@ -1,11 +1,24 @@
![Ginkgo: A Go BDD Testing Framework](https://onsi.github.io/ginkgo/images/ginkgo.png)
[![Build Status](https://travis-ci.org/onsi/ginkgo.svg?branch=master)](https://travis-ci.org/onsi/ginkgo)
+[![test](https://github.com/onsi/ginkgo/workflows/test/badge.svg?branch=master)](https://github.com/onsi/ginkgo/actions?query=workflow%3Atest+branch%3Amaster)
-Jump to the [docs](https://onsi.github.io/ginkgo/) to learn more. To start rolling your Ginkgo tests *now* [keep reading](#set-me-up)!
+Jump to the [docs](https://onsi.github.io/ginkgo/) | [中文文档](https://ke-chain.github.io/ginkgodoc) to learn more. To start rolling your Ginkgo tests *now* [keep reading](#set-me-up)!
If you have a question, comment, bug report, feature request, etc. please open a GitHub issue, or visit the [Ginkgo Slack channel](https://app.slack.com/client/T029RQSE6/CQQ50BBNW).
+# Ginkgo 2.0 is coming soon!
+
+An effort is underway to develop and deliver Ginkgo 2.0. The work is happening in the [v2](https://github.com/onsi/ginkgo/tree/v2) branch and a changelog and migration guide is being maintained on that branch [here](https://github.com/onsi/ginkgo/blob/v2/docs/MIGRATING_TO_V2.md). Issue [#711](https://github.com/onsi/ginkgo/issues/711) is the central place for discussion and links to the original [proposal doc](https://docs.google.com/document/d/1h28ZknXRsTLPNNiOjdHIO-F2toCzq4xoZDXbfYaBdoQ/edit#).
+
+As described in the [changelog](https://github.com/onsi/ginkgo/blob/v2/docs/MIGRATING_TO_V2.md) and [proposal](https://docs.google.com/document/d/1h28ZknXRsTLPNNiOjdHIO-F2toCzq4xoZDXbfYaBdoQ/edit#), Ginkgo 2.0 will clean up the Ginkgo codebase, deprecate and remove some v1 functionality, and add several new much-requested features. To help users get ready for the migration, Ginkgo v1 has started emitting deprecation warnings for features that will no longer be supported with links to documentation for how to migrate away from these features. If you have concerns or comments please chime in on [#711](https://github.com/onsi/ginkgo/issues/711).
+
+The current timeline for completion of 2.0 looks like:
+
+- Early April 2021: first public release of 2.0, deprecation warnings land in v1.
+- May 2021: first beta/rc of 2.0 with most new functionality in place.
+- June/July 2021: 2.0 ships and fully replaces the 1.x codebase on master.
+
## TLDR
Ginkgo builds on Go's `testing` package, allowing expressive [Behavior-Driven Development](https://en.wikipedia.org/wiki/Behavior-driven_development) ("BDD") style tests.
It is typically (and optionally) paired with the [Gomega](https://github.com/onsi/gomega) matcher library.
@@ -61,6 +74,8 @@ Describe("the strings package", func() {
- [Completions for VSCode](https://github.com/onsi/vscode-ginkgo): just use VSCode's extension installer to install `vscode-ginkgo`.
+- [Ginkgo tools for VSCode](https://marketplace.visualstudio.com/items?itemName=joselitofilho.ginkgotestexplorer): just use VSCode's extension installer to install `ginkgoTestExplorer`.
+
- Straightforward support for third-party testing libraries such as [Gomock](https://code.google.com/p/gomock/) and [Testify](https://github.com/stretchr/testify). Check out the [docs](https://onsi.github.io/ginkgo/#third-party-integrations) for details.
- A modular architecture that lets you easily:
@@ -80,10 +95,11 @@ Agouti allows you run WebDriver integration tests. Learn more about Agouti [her
You'll need the Go command-line tools. Follow the [installation instructions](https://golang.org/doc/install) if you don't have it installed.
### Global installation
-To install the Ginkgo command line interface into the `$PATH` (actually to `$GOBIN`):
+To install the Ginkgo command line interface:
```bash
go get -u github.com/onsi/ginkgo/ginkgo
```
+Note that this will install it to `$GOBIN`, which will need to be in the `$PATH` (or equivalent). Run `go help install` for more information.
### Go module ["tools package"](https://github.com/golang/go/issues/25922):
Create (or update) a file called `tools/tools.go` with the following contents:
@@ -93,7 +109,7 @@ Create (or update) a file called `tools/tools.go` with the following contents:
package tools
import (
- _ "github.com/onsi/ginkgo"
+ _ "github.com/onsi/ginkgo/ginkgo"
)
// This file imports packages that are used when running go generate, or used
diff --git a/vendor/github.com/onsi/ginkgo/RELEASING.md b/vendor/github.com/onsi/ginkgo/RELEASING.md
index 1e298c2da..db3d234c1 100644
--- a/vendor/github.com/onsi/ginkgo/RELEASING.md
+++ b/vendor/github.com/onsi/ginkgo/RELEASING.md
@@ -8,7 +8,10 @@ A Ginkgo release is a tagged git sha and a GitHub release. To cut a release:
- Fixes (fix version)
- Maintenance (which in general should not be mentioned in `CHANGELOG.md` as they have no user impact)
1. Update `VERSION` in `config/config.go`
-1. Create a commit with the version number as the commit message (e.g. `v1.3.0`)
-1. Tag the commit with the version number as the tag name (e.g. `v1.3.0`)
-1. Push the commit and tag to GitHub
-1. Create a new [GitHub release](https://help.github.com/articles/creating-releases/) with the version number as the tag (e.g. `v1.3.0`). List the key changes in the release notes.
+1. Commit, push, and release:
+ ```
+ git commit -m "vM.m.p"
+ git push
+ gh release create "vM.m.p"
+ git fetch --tags origin master
+ ``` \ No newline at end of file
diff --git a/vendor/github.com/onsi/ginkgo/config/config.go b/vendor/github.com/onsi/ginkgo/config/config.go
index 2ae48b804..5f3f43969 100644
--- a/vendor/github.com/onsi/ginkgo/config/config.go
+++ b/vendor/github.com/onsi/ginkgo/config/config.go
@@ -20,14 +20,14 @@ import (
"fmt"
)
-const VERSION = "1.14.0"
+const VERSION = "1.16.4"
type GinkgoConfigType struct {
RandomSeed int64
RandomizeAllSpecs bool
RegexScansFilePath bool
- FocusString string
- SkipString string
+ FocusStrings []string
+ SkipStrings []string
SkipMeasurements bool
FailOnPending bool
FailFast bool
@@ -65,6 +65,11 @@ func processPrefix(prefix string) string {
return prefix
}
+type flagFunc func(string)
+
+func (f flagFunc) String() string { return "" }
+func (f flagFunc) Set(s string) error { f(s); return nil }
+
func Flags(flagSet *flag.FlagSet, prefix string, includeParallelFlags bool) {
prefix = processPrefix(prefix)
flagSet.Int64Var(&(GinkgoConfig.RandomSeed), prefix+"seed", time.Now().Unix(), "The seed used to randomize the spec suite.")
@@ -75,8 +80,8 @@ func Flags(flagSet *flag.FlagSet, prefix string, includeParallelFlags bool) {
flagSet.BoolVar(&(GinkgoConfig.DryRun), prefix+"dryRun", false, "If set, ginkgo will walk the test hierarchy without actually running anything. Best paired with -v.")
- flagSet.StringVar(&(GinkgoConfig.FocusString), prefix+"focus", "", "If set, ginkgo will only run specs that match this regular expression.")
- flagSet.StringVar(&(GinkgoConfig.SkipString), prefix+"skip", "", "If set, ginkgo will only run specs that do not match this regular expression.")
+ flagSet.Var(flagFunc(flagFocus), prefix+"focus", "If set, ginkgo will only run specs that match this regular expression. Can be specified multiple times, values are ORed.")
+ flagSet.Var(flagFunc(flagSkip), prefix+"skip", "If set, ginkgo will only run specs that do not match this regular expression. Can be specified multiple times, values are ORed.")
flagSet.BoolVar(&(GinkgoConfig.RegexScansFilePath), prefix+"regexScansFilePath", false, "If set, ginkgo regex matching also will look at the file path (code location).")
@@ -133,12 +138,12 @@ func BuildFlagArgs(prefix string, ginkgo GinkgoConfigType, reporter DefaultRepor
result = append(result, fmt.Sprintf("--%sdryRun", prefix))
}
- if ginkgo.FocusString != "" {
- result = append(result, fmt.Sprintf("--%sfocus=%s", prefix, ginkgo.FocusString))
+ for _, s := range ginkgo.FocusStrings {
+ result = append(result, fmt.Sprintf("--%sfocus=%s", prefix, s))
}
- if ginkgo.SkipString != "" {
- result = append(result, fmt.Sprintf("--%sskip=%s", prefix, ginkgo.SkipString))
+ for _, s := range ginkgo.SkipStrings {
+ result = append(result, fmt.Sprintf("--%sskip=%s", prefix, s))
}
if ginkgo.FlakeAttempts > 1 {
@@ -211,3 +216,17 @@ func BuildFlagArgs(prefix string, ginkgo GinkgoConfigType, reporter DefaultRepor
return result
}
+
+// flagFocus implements the -focus flag.
+func flagFocus(arg string) {
+ if arg != "" {
+ GinkgoConfig.FocusStrings = append(GinkgoConfig.FocusStrings, arg)
+ }
+}
+
+// flagSkip implements the -skip flag.
+func flagSkip(arg string) {
+ if arg != "" {
+ GinkgoConfig.SkipStrings = append(GinkgoConfig.SkipStrings, arg)
+ }
+}
diff --git a/vendor/github.com/onsi/ginkgo/formatter/formatter.go b/vendor/github.com/onsi/ginkgo/formatter/formatter.go
new file mode 100644
index 000000000..30d7cbe12
--- /dev/null
+++ b/vendor/github.com/onsi/ginkgo/formatter/formatter.go
@@ -0,0 +1,190 @@
+package formatter
+
+import (
+ "fmt"
+ "regexp"
+ "strings"
+)
+
+const COLS = 80
+
+type ColorMode uint8
+
+const (
+ ColorModeNone ColorMode = iota
+ ColorModeTerminal
+ ColorModePassthrough
+)
+
+var SingletonFormatter = New(ColorModeTerminal)
+
+func F(format string, args ...interface{}) string {
+ return SingletonFormatter.F(format, args...)
+}
+
+func Fi(indentation uint, format string, args ...interface{}) string {
+ return SingletonFormatter.Fi(indentation, format, args...)
+}
+
+func Fiw(indentation uint, maxWidth uint, format string, args ...interface{}) string {
+ return SingletonFormatter.Fiw(indentation, maxWidth, format, args...)
+}
+
+type Formatter struct {
+ ColorMode ColorMode
+ colors map[string]string
+ styleRe *regexp.Regexp
+ preserveColorStylingTags bool
+}
+
+func NewWithNoColorBool(noColor bool) Formatter {
+ if noColor {
+ return New(ColorModeNone)
+ }
+ return New(ColorModeTerminal)
+}
+
+func New(colorMode ColorMode) Formatter {
+ f := Formatter{
+ ColorMode: colorMode,
+ colors: map[string]string{
+ "/": "\x1b[0m",
+ "bold": "\x1b[1m",
+ "underline": "\x1b[4m",
+
+ "red": "\x1b[38;5;9m",
+ "orange": "\x1b[38;5;214m",
+ "coral": "\x1b[38;5;204m",
+ "magenta": "\x1b[38;5;13m",
+ "green": "\x1b[38;5;10m",
+ "dark-green": "\x1b[38;5;28m",
+ "yellow": "\x1b[38;5;11m",
+ "light-yellow": "\x1b[38;5;228m",
+ "cyan": "\x1b[38;5;14m",
+ "gray": "\x1b[38;5;243m",
+ "light-gray": "\x1b[38;5;246m",
+ "blue": "\x1b[38;5;12m",
+ },
+ }
+ colors := []string{}
+ for color := range f.colors {
+ colors = append(colors, color)
+ }
+ f.styleRe = regexp.MustCompile("{{(" + strings.Join(colors, "|") + ")}}")
+ return f
+}
+
+func (f Formatter) F(format string, args ...interface{}) string {
+ return f.Fi(0, format, args...)
+}
+
+func (f Formatter) Fi(indentation uint, format string, args ...interface{}) string {
+ return f.Fiw(indentation, 0, format, args...)
+}
+
+func (f Formatter) Fiw(indentation uint, maxWidth uint, format string, args ...interface{}) string {
+ out := fmt.Sprintf(f.style(format), args...)
+
+ if indentation == 0 && maxWidth == 0 {
+ return out
+ }
+
+ lines := strings.Split(out, "\n")
+
+ if maxWidth != 0 {
+ outLines := []string{}
+
+ maxWidth = maxWidth - indentation*2
+ for _, line := range lines {
+ if f.length(line) <= maxWidth {
+ outLines = append(outLines, line)
+ continue
+ }
+ outWords := []string{}
+ length := uint(0)
+ words := strings.Split(line, " ")
+ for _, word := range words {
+ wordLength := f.length(word)
+ if length+wordLength <= maxWidth {
+ length += wordLength
+ outWords = append(outWords, word)
+ continue
+ }
+ outLines = append(outLines, strings.Join(outWords, " "))
+ outWords = []string{word}
+ length = wordLength
+ }
+ if len(outWords) > 0 {
+ outLines = append(outLines, strings.Join(outWords, " "))
+ }
+ }
+
+ lines = outLines
+ }
+
+ if indentation == 0 {
+ return strings.Join(lines, "\n")
+ }
+
+ padding := strings.Repeat(" ", int(indentation))
+ for i := range lines {
+ if lines[i] != "" {
+ lines[i] = padding + lines[i]
+ }
+ }
+
+ return strings.Join(lines, "\n")
+}
+
+func (f Formatter) length(styled string) uint {
+ n := uint(0)
+ inStyle := false
+ for _, b := range styled {
+ if inStyle {
+ if b == 'm' {
+ inStyle = false
+ }
+ continue
+ }
+ if b == '\x1b' {
+ inStyle = true
+ continue
+ }
+ n += 1
+ }
+ return n
+}
+
+func (f Formatter) CycleJoin(elements []string, joiner string, cycle []string) string {
+ if len(elements) == 0 {
+ return ""
+ }
+ n := len(cycle)
+ out := ""
+ for i, text := range elements {
+ out += cycle[i%n] + text
+ if i < len(elements)-1 {
+ out += joiner
+ }
+ }
+ out += "{{/}}"
+ return f.style(out)
+}
+
+func (f Formatter) style(s string) string {
+ switch f.ColorMode {
+ case ColorModeNone:
+ return f.styleRe.ReplaceAllString(s, "")
+ case ColorModePassthrough:
+ return s
+ case ColorModeTerminal:
+ return f.styleRe.ReplaceAllStringFunc(s, func(match string) string {
+ if out, ok := f.colors[strings.Trim(match, "{}")]; ok {
+ return out
+ }
+ return match
+ })
+ }
+
+ return ""
+}
diff --git a/vendor/github.com/onsi/ginkgo/ginkgo_dsl.go b/vendor/github.com/onsi/ginkgo/ginkgo_dsl.go
index 30ff86f59..4a6e1e1ee 100644
--- a/vendor/github.com/onsi/ginkgo/ginkgo_dsl.go
+++ b/vendor/github.com/onsi/ginkgo/ginkgo_dsl.go
@@ -17,6 +17,7 @@ import (
"io"
"net/http"
"os"
+ "reflect"
"strings"
"time"
@@ -32,6 +33,8 @@ import (
"github.com/onsi/ginkgo/types"
)
+var deprecationTracker = types.NewDeprecationTracker()
+
const GINKGO_VERSION = config.VERSION
const GINKGO_PANIC = `
Your test failed.
@@ -93,26 +96,36 @@ func GinkgoT(optionalOffset ...int) GinkgoTInterface {
if len(optionalOffset) > 0 {
offset = optionalOffset[0]
}
- return testingtproxy.New(GinkgoWriter, Fail, offset)
+ failedFunc := func() bool {
+ return CurrentGinkgoTestDescription().Failed
+ }
+ nameFunc := func() string {
+ return CurrentGinkgoTestDescription().FullTestText
+ }
+ return testingtproxy.New(GinkgoWriter, Fail, Skip, failedFunc, nameFunc, offset)
}
//The interface returned by GinkgoT(). This covers most of the methods
//in the testing package's T.
type GinkgoTInterface interface {
- Fail()
+ Cleanup(func())
Error(args ...interface{})
Errorf(format string, args ...interface{})
+ Fail()
FailNow()
+ Failed() bool
Fatal(args ...interface{})
Fatalf(format string, args ...interface{})
+ Helper()
Log(args ...interface{})
Logf(format string, args ...interface{})
- Failed() bool
+ Name() string
Parallel()
Skip(args ...interface{})
- Skipf(format string, args ...interface{})
SkipNow()
+ Skipf(format string, args ...interface{})
Skipped() bool
+ TempDir() string
}
//Custom Ginkgo test reporters must implement the Reporter interface.
@@ -195,21 +208,27 @@ func RunSpecs(t GinkgoTestingT, description string) bool {
if config.DefaultReporterConfig.ReportFile != "" {
reportFile := config.DefaultReporterConfig.ReportFile
specReporters[0] = reporters.NewJUnitReporter(reportFile)
- return RunSpecsWithDefaultAndCustomReporters(t, description, specReporters)
+ specReporters = append(specReporters, buildDefaultReporter())
}
- return RunSpecsWithCustomReporters(t, description, specReporters)
+ return runSpecsWithCustomReporters(t, description, specReporters)
}
//To run your tests with Ginkgo's default reporter and your custom reporter(s), replace
//RunSpecs() with this method.
func RunSpecsWithDefaultAndCustomReporters(t GinkgoTestingT, description string, specReporters []Reporter) bool {
+ deprecationTracker.TrackDeprecation(types.Deprecations.CustomReporter())
specReporters = append(specReporters, buildDefaultReporter())
- return RunSpecsWithCustomReporters(t, description, specReporters)
+ return runSpecsWithCustomReporters(t, description, specReporters)
}
//To run your tests with your custom reporter(s) (and *not* Ginkgo's default reporter), replace
//RunSpecs() with this method. Note that parallel tests will not work correctly without the default reporter
func RunSpecsWithCustomReporters(t GinkgoTestingT, description string, specReporters []Reporter) bool {
+ deprecationTracker.TrackDeprecation(types.Deprecations.CustomReporter())
+ return runSpecsWithCustomReporters(t, description, specReporters)
+}
+
+func runSpecsWithCustomReporters(t GinkgoTestingT, description string, specReporters []Reporter) bool {
writer := GinkgoWriter.(*writer.Writer)
writer.SetStream(config.DefaultReporterConfig.Verbose)
reporters := make([]reporters.Reporter, len(specReporters))
@@ -217,6 +236,11 @@ func RunSpecsWithCustomReporters(t GinkgoTestingT, description string, specRepor
reporters[i] = reporter
}
passed, hasFocusedTests := global.Suite.Run(t, description, reporters, writer, config.GinkgoConfig)
+
+ if deprecationTracker.DidTrackDeprecations() {
+ fmt.Fprintln(colorable.NewColorableStderr(), deprecationTracker.DeprecationsReport())
+ }
+
if passed && hasFocusedTests && strings.TrimSpace(os.Getenv("GINKGO_EDITOR_INTEGRATION")) == "" {
fmt.Println("PASS | FOCUSED")
os.Exit(types.GINKGO_FOCUS_EXIT_CODE)
@@ -370,12 +394,14 @@ func XWhen(text string, body func()) bool {
//Ginkgo will normally run It blocks synchronously. To perform asynchronous tests, pass a
//function that accepts a Done channel. When you do this, you can also provide an optional timeout.
func It(text string, body interface{}, timeout ...float64) bool {
+ validateBodyFunc(body, codelocation.New(1))
global.Suite.PushItNode(text, body, types.FlagTypeNone, codelocation.New(1), parseTimeout(timeout...))
return true
}
//You can focus individual Its using FIt
func FIt(text string, body interface{}, timeout ...float64) bool {
+ validateBodyFunc(body, codelocation.New(1))
global.Suite.PushItNode(text, body, types.FlagTypeFocused, codelocation.New(1), parseTimeout(timeout...))
return true
}
@@ -396,12 +422,14 @@ func XIt(text string, _ ...interface{}) bool {
//which "It" does not fit into a natural sentence flow. All the same protocols apply for Specify blocks
//which apply to It blocks.
func Specify(text string, body interface{}, timeout ...float64) bool {
+ validateBodyFunc(body, codelocation.New(1))
global.Suite.PushItNode(text, body, types.FlagTypeNone, codelocation.New(1), parseTimeout(timeout...))
return true
}
//You can focus individual Specifys using FSpecify
func FSpecify(text string, body interface{}, timeout ...float64) bool {
+ validateBodyFunc(body, codelocation.New(1))
global.Suite.PushItNode(text, body, types.FlagTypeFocused, codelocation.New(1), parseTimeout(timeout...))
return true
}
@@ -445,24 +473,28 @@ func By(text string, callbacks ...func()) {
//The body function must have the signature:
// func(b Benchmarker)
func Measure(text string, body interface{}, samples int) bool {
+ deprecationTracker.TrackDeprecation(types.Deprecations.Measure(), codelocation.New(1))
global.Suite.PushMeasureNode(text, body, types.FlagTypeNone, codelocation.New(1), samples)
return true
}
//You can focus individual Measures using FMeasure
func FMeasure(text string, body interface{}, samples int) bool {
+ deprecationTracker.TrackDeprecation(types.Deprecations.Measure(), codelocation.New(1))
global.Suite.PushMeasureNode(text, body, types.FlagTypeFocused, codelocation.New(1), samples)
return true
}
//You can mark Measurements as pending using PMeasure
func PMeasure(text string, _ ...interface{}) bool {
+ deprecationTracker.TrackDeprecation(types.Deprecations.Measure(), codelocation.New(1))
global.Suite.PushMeasureNode(text, func(b Benchmarker) {}, types.FlagTypePending, codelocation.New(1), 0)
return true
}
//You can mark Measurements as pending using XMeasure
func XMeasure(text string, _ ...interface{}) bool {
+ deprecationTracker.TrackDeprecation(types.Deprecations.Measure(), codelocation.New(1))
global.Suite.PushMeasureNode(text, func(b Benchmarker) {}, types.FlagTypePending, codelocation.New(1), 0)
return true
}
@@ -474,6 +506,7 @@ func XMeasure(text string, _ ...interface{}) bool {
//
//You may only register *one* BeforeSuite handler per test suite. You typically do so in your bootstrap file at the top level.
func BeforeSuite(body interface{}, timeout ...float64) bool {
+ validateBodyFunc(body, codelocation.New(1))
global.Suite.SetBeforeSuiteNode(body, codelocation.New(1), parseTimeout(timeout...))
return true
}
@@ -487,6 +520,7 @@ func BeforeSuite(body interface{}, timeout ...float64) bool {
//
//You may only register *one* AfterSuite handler per test suite. You typically do so in your bootstrap file at the top level.
func AfterSuite(body interface{}, timeout ...float64) bool {
+ validateBodyFunc(body, codelocation.New(1))
global.Suite.SetAfterSuiteNode(body, codelocation.New(1), parseTimeout(timeout...))
return true
}
@@ -574,6 +608,7 @@ func SynchronizedAfterSuite(allNodesBody interface{}, node1Body interface{}, tim
//Like It blocks, BeforeEach blocks can be made asynchronous by providing a body function that accepts
//a Done channel
func BeforeEach(body interface{}, timeout ...float64) bool {
+ validateBodyFunc(body, codelocation.New(1))
global.Suite.PushBeforeEachNode(body, codelocation.New(1), parseTimeout(timeout...))
return true
}
@@ -584,6 +619,7 @@ func BeforeEach(body interface{}, timeout ...float64) bool {
//Like It blocks, BeforeEach blocks can be made asynchronous by providing a body function that accepts
//a Done channel
func JustBeforeEach(body interface{}, timeout ...float64) bool {
+ validateBodyFunc(body, codelocation.New(1))
global.Suite.PushJustBeforeEachNode(body, codelocation.New(1), parseTimeout(timeout...))
return true
}
@@ -594,6 +630,7 @@ func JustBeforeEach(body interface{}, timeout ...float64) bool {
//Like It blocks, JustAfterEach blocks can be made asynchronous by providing a body function that accepts
//a Done channel
func JustAfterEach(body interface{}, timeout ...float64) bool {
+ validateBodyFunc(body, codelocation.New(1))
global.Suite.PushJustAfterEachNode(body, codelocation.New(1), parseTimeout(timeout...))
return true
}
@@ -604,10 +641,30 @@ func JustAfterEach(body interface{}, timeout ...float64) bool {
//Like It blocks, AfterEach blocks can be made asynchronous by providing a body function that accepts
//a Done channel
func AfterEach(body interface{}, timeout ...float64) bool {
+ validateBodyFunc(body, codelocation.New(1))
global.Suite.PushAfterEachNode(body, codelocation.New(1), parseTimeout(timeout...))
return true
}
+func validateBodyFunc(body interface{}, cl types.CodeLocation) {
+ t := reflect.TypeOf(body)
+ if t.Kind() != reflect.Func {
+ return
+ }
+
+ if t.NumOut() > 0 {
+ return
+ }
+
+ if t.NumIn() == 0 {
+ return
+ }
+
+ if t.In(0) == reflect.TypeOf(make(Done)) {
+ deprecationTracker.TrackDeprecation(types.Deprecations.Async(), cl)
+ }
+}
+
func parseTimeout(timeout ...float64) time.Duration {
if len(timeout) == 0 {
return global.DefaultTimeout
diff --git a/vendor/github.com/onsi/ginkgo/go.mod b/vendor/github.com/onsi/ginkgo/go.mod
index 1f7125228..86a5a97be 100644
--- a/vendor/github.com/onsi/ginkgo/go.mod
+++ b/vendor/github.com/onsi/ginkgo/go.mod
@@ -1,11 +1,13 @@
module github.com/onsi/ginkgo
+go 1.15
+
require (
- github.com/fsnotify/fsnotify v1.4.9 // indirect
- github.com/nxadm/tail v1.4.4
+ github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0
+ github.com/nxadm/tail v1.4.8
github.com/onsi/gomega v1.10.1
- golang.org/x/sys v0.0.0-20200519105757-fe76b779f299
- golang.org/x/text v0.3.2 // indirect
+ golang.org/x/sys v0.0.0-20210112080510-489259a85091
+ golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e
)
-go 1.13
+retract v1.16.3 // git tag accidentally associated with incorrect git commit
diff --git a/vendor/github.com/onsi/ginkgo/go.sum b/vendor/github.com/onsi/ginkgo/go.sum
index 2b774f3e8..5c5c3c502 100644
--- a/vendor/github.com/onsi/ginkgo/go.sum
+++ b/vendor/github.com/onsi/ginkgo/go.sum
@@ -1,8 +1,11 @@
-github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
+github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
+github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
-github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM=
+github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 h1:p104kn46Q8WdvHunIJ9dAyjPVtrBPhSr3KT2yUst43I=
+github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
@@ -15,39 +18,56 @@ github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
-github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78=
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
+github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
+github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
-github.com/onsi/gomega v1.7.1 h1:K0jcRCwNQM3vFGh1ppMtDh/+7ApJrjldlX8fA0jDTLQ=
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
github.com/onsi/gomega v1.10.1 h1:o0+MgICZLuZ7xjH7Vx6zS/zcu93/BEp1VwkIW1mEXCE=
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
+github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
+github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4=
+github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
+github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
-golang.org/x/net v0.0.0-20180906233101-161cd47e91fd h1:nTDtHvHSdCn1m6ITfMRqtOd/9+7a3s8RBNOZ3eYZzJA=
+golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7 h1:AeiKBIuRw3UomYXSbLy0Mc2dDLfdtbT/IVn4keq83P0=
+golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
-golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f h1:wMNYb4v58l5UBM7MYRLPG6ZhfOqbKu7X5eyFl8ZhKvA=
+golang.org/x/net v0.0.0-20201021035429-f5854403a974 h1:IX6qOQeG5uLjB/hjjwjedwfjND0hgjPMMyO1RoIXQNI=
+golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e h1:N7DeIrjYszNmSW409R3frPPwglRwMkXSBzwVbkOjLLA=
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200519105757-fe76b779f299 h1:DYfZAGf2WMFjMxbgTjaC+2HC7NkNAQs+6Q8b9WEB/F4=
-golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
+golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210112080510-489259a85091 h1:DMyOG0U+gKfu8JZzg2UQe9MeaC1X+xQWlAKcRnjxjCw=
+golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
-golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
-golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
+golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=
+golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
-golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
+golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e h1:4nW4NLDYnU28ojHaHO8OVxFHk/aQ33U01a9cjED+pzE=
+golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
+golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
+golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
@@ -57,11 +77,10 @@ google.golang.org/protobuf v1.23.0 h1:4MY060fB1DLGMB/7MBTLnwQUY6+F09GEiz6SsrNqyz
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
-gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
-gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I=
+gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
diff --git a/vendor/github.com/onsi/ginkgo/internal/remote/output_interceptor_darwin.go b/vendor/github.com/onsi/ginkgo/internal/remote/output_interceptor_darwin.go
deleted file mode 100644
index e3d09eadb..000000000
--- a/vendor/github.com/onsi/ginkgo/internal/remote/output_interceptor_darwin.go
+++ /dev/null
@@ -1,11 +0,0 @@
-// +build darwin
-
-package remote
-
-import (
- "golang.org/x/sys/unix"
-)
-
-func interceptorDupx(oldfd int, newfd int) {
- unix.Dup2(oldfd, newfd)
-}
diff --git a/vendor/github.com/onsi/ginkgo/internal/remote/output_interceptor_dragonfly.go b/vendor/github.com/onsi/ginkgo/internal/remote/output_interceptor_dragonfly.go
deleted file mode 100644
index 72d38686a..000000000
--- a/vendor/github.com/onsi/ginkgo/internal/remote/output_interceptor_dragonfly.go
+++ /dev/null
@@ -1,11 +0,0 @@
-// +build dragonfly
-
-package remote
-
-import (
- "golang.org/x/sys/unix"
-)
-
-func interceptorDupx(oldfd int, newfd int) {
- unix.Dup2(oldfd, newfd)
-}
diff --git a/vendor/github.com/onsi/ginkgo/internal/remote/output_interceptor_freebsd.go b/vendor/github.com/onsi/ginkgo/internal/remote/output_interceptor_freebsd.go
deleted file mode 100644
index 497d548d9..000000000
--- a/vendor/github.com/onsi/ginkgo/internal/remote/output_interceptor_freebsd.go
+++ /dev/null
@@ -1,11 +0,0 @@
-// +build freebsd
-
-package remote
-
-import (
- "golang.org/x/sys/unix"
-)
-
-func interceptorDupx(oldfd int, newfd int) {
- unix.Dup2(oldfd, newfd)
-}
diff --git a/vendor/github.com/onsi/ginkgo/internal/remote/output_interceptor_linux.go b/vendor/github.com/onsi/ginkgo/internal/remote/output_interceptor_linux.go
deleted file mode 100644
index 29add0d33..000000000
--- a/vendor/github.com/onsi/ginkgo/internal/remote/output_interceptor_linux.go
+++ /dev/null
@@ -1,12 +0,0 @@
-// +build linux
-// +build !mips64le
-
-package remote
-
-import (
- "golang.org/x/sys/unix"
-)
-
-func interceptorDupx(oldfd int, newfd int) {
- unix.Dup2(oldfd, newfd)
-}
diff --git a/vendor/github.com/onsi/ginkgo/internal/remote/output_interceptor_linux_mips64le.go b/vendor/github.com/onsi/ginkgo/internal/remote/output_interceptor_linux_mips64le.go
deleted file mode 100644
index 09bd06260..000000000
--- a/vendor/github.com/onsi/ginkgo/internal/remote/output_interceptor_linux_mips64le.go
+++ /dev/null
@@ -1,12 +0,0 @@
-// +build linux
-// +build mips64le
-
-package remote
-
-import (
- "golang.org/x/sys/unix"
-)
-
-func interceptorDupx(oldfd int, newfd int) {
- unix.Dup3(oldfd, newfd, 0)
-}
diff --git a/vendor/github.com/onsi/ginkgo/internal/remote/output_interceptor_netbsd.go b/vendor/github.com/onsi/ginkgo/internal/remote/output_interceptor_netbsd.go
deleted file mode 100644
index 16ad6aeb2..000000000
--- a/vendor/github.com/onsi/ginkgo/internal/remote/output_interceptor_netbsd.go
+++ /dev/null
@@ -1,11 +0,0 @@
-// +build netbsd
-
-package remote
-
-import (
- "golang.org/x/sys/unix"
-)
-
-func interceptorDupx(oldfd int, newfd int) {
- unix.Dup2(oldfd, newfd)
-}
diff --git a/vendor/github.com/onsi/ginkgo/internal/remote/output_interceptor_openbsd.go b/vendor/github.com/onsi/ginkgo/internal/remote/output_interceptor_openbsd.go
deleted file mode 100644
index 4275f8421..000000000
--- a/vendor/github.com/onsi/ginkgo/internal/remote/output_interceptor_openbsd.go
+++ /dev/null
@@ -1,11 +0,0 @@
-// +build openbsd
-
-package remote
-
-import (
- "golang.org/x/sys/unix"
-)
-
-func interceptorDupx(oldfd int, newfd int) {
- unix.Dup2(oldfd, newfd)
-}
diff --git a/vendor/github.com/onsi/ginkgo/internal/remote/output_interceptor_solaris.go b/vendor/github.com/onsi/ginkgo/internal/remote/output_interceptor_solaris.go
deleted file mode 100644
index 882a38a9e..000000000
--- a/vendor/github.com/onsi/ginkgo/internal/remote/output_interceptor_solaris.go
+++ /dev/null
@@ -1,11 +0,0 @@
-// +build solaris
-
-package remote
-
-import (
- "golang.org/x/sys/unix"
-)
-
-func interceptorDupx(oldfd int, newfd int) {
- unix.Dup2(oldfd, newfd)
-}
diff --git a/vendor/github.com/onsi/ginkgo/internal/remote/output_interceptor_unix.go b/vendor/github.com/onsi/ginkgo/internal/remote/output_interceptor_unix.go
index 80614d0ce..774967db6 100644
--- a/vendor/github.com/onsi/ginkgo/internal/remote/output_interceptor_unix.go
+++ b/vendor/github.com/onsi/ginkgo/internal/remote/output_interceptor_unix.go
@@ -8,6 +8,7 @@ import (
"os"
"github.com/nxadm/tail"
+ "golang.org/x/sys/unix"
)
func NewOutputInterceptor() OutputInterceptor {
@@ -35,8 +36,10 @@ func (interceptor *outputInterceptor) StartInterceptingOutput() error {
return err
}
- interceptorDupx(int(interceptor.redirectFile.Fd()), 1)
- interceptorDupx(int(interceptor.redirectFile.Fd()), 2)
+ // This might call Dup3 if the dup2 syscall is not available, e.g. on
+ // linux/arm64 or linux/riscv64
+ unix.Dup2(int(interceptor.redirectFile.Fd()), 1)
+ unix.Dup2(int(interceptor.redirectFile.Fd()), 2)
if interceptor.streamTarget != nil {
interceptor.tailer, _ = tail.TailFile(interceptor.redirectFile.Name(), tail.Config{Follow: true})
diff --git a/vendor/github.com/onsi/ginkgo/internal/spec/specs.go b/vendor/github.com/onsi/ginkgo/internal/spec/specs.go
index 8a2007137..0a24139fb 100644
--- a/vendor/github.com/onsi/ginkgo/internal/spec/specs.go
+++ b/vendor/github.com/onsi/ginkgo/internal/spec/specs.go
@@ -4,6 +4,7 @@ import (
"math/rand"
"regexp"
"sort"
+ "strings"
)
type Specs struct {
@@ -46,11 +47,11 @@ func (e *Specs) Shuffle(r *rand.Rand) {
e.names = names
}
-func (e *Specs) ApplyFocus(description string, focusString string, skipString string) {
- if focusString == "" && skipString == "" {
+func (e *Specs) ApplyFocus(description string, focus, skip []string) {
+ if len(focus)+len(skip) == 0 {
e.applyProgrammaticFocus()
} else {
- e.applyRegExpFocusAndSkip(description, focusString, skipString)
+ e.applyRegExpFocusAndSkip(description, focus, skip)
}
}
@@ -90,14 +91,13 @@ func (e *Specs) toMatch(description string, i int) []byte {
}
}
-func (e *Specs) applyRegExpFocusAndSkip(description string, focusString string, skipString string) {
- var focusFilter *regexp.Regexp
- if focusString != "" {
- focusFilter = regexp.MustCompile(focusString)
+func (e *Specs) applyRegExpFocusAndSkip(description string, focus, skip []string) {
+ var focusFilter, skipFilter *regexp.Regexp
+ if len(focus) > 0 {
+ focusFilter = regexp.MustCompile(strings.Join(focus, "|"))
}
- var skipFilter *regexp.Regexp
- if skipString != "" {
- skipFilter = regexp.MustCompile(skipString)
+ if len(skip) > 0 {
+ skipFilter = regexp.MustCompile(strings.Join(skip, "|"))
}
for i, spec := range e.specs {
diff --git a/vendor/github.com/onsi/ginkgo/internal/suite/suite.go b/vendor/github.com/onsi/ginkgo/internal/suite/suite.go
index e75da1f89..b4a83c432 100644
--- a/vendor/github.com/onsi/ginkgo/internal/suite/suite.go
+++ b/vendor/github.com/onsi/ginkgo/internal/suite/suite.go
@@ -97,7 +97,7 @@ func (suite *Suite) generateSpecsIterator(description string, config config.Gink
specs.Shuffle(rand.New(rand.NewSource(config.RandomSeed)))
}
- specs.ApplyFocus(description, config.FocusString, config.SkipString)
+ specs.ApplyFocus(description, config.FocusStrings, config.SkipStrings)
if config.SkipMeasurements {
specs.SkipMeasurements()
diff --git a/vendor/github.com/onsi/ginkgo/internal/testingtproxy/testing_t_proxy.go b/vendor/github.com/onsi/ginkgo/internal/testingtproxy/testing_t_proxy.go
index 090445d08..d7bbb7a96 100644
--- a/vendor/github.com/onsi/ginkgo/internal/testingtproxy/testing_t_proxy.go
+++ b/vendor/github.com/onsi/ginkgo/internal/testingtproxy/testing_t_proxy.go
@@ -6,21 +6,34 @@ import (
)
type failFunc func(message string, callerSkip ...int)
+type skipFunc func(message string, callerSkip ...int)
+type failedFunc func() bool
+type nameFunc func() string
-func New(writer io.Writer, fail failFunc, offset int) *ginkgoTestingTProxy {
+func New(writer io.Writer, fail failFunc, skip skipFunc, failed failedFunc, name nameFunc, offset int) *ginkgoTestingTProxy {
return &ginkgoTestingTProxy{
fail: fail,
offset: offset,
writer: writer,
+ skip: skip,
+ failed: failed,
+ name: name,
}
}
type ginkgoTestingTProxy struct {
fail failFunc
+ skip skipFunc
+ failed failedFunc
+ name nameFunc
offset int
writer io.Writer
}
+func (t *ginkgoTestingTProxy) Cleanup(func()) {
+ // No-op
+}
+
func (t *ginkgoTestingTProxy) Error(args ...interface{}) {
t.fail(fmt.Sprintln(args...), t.offset)
}
@@ -37,6 +50,10 @@ func (t *ginkgoTestingTProxy) FailNow() {
t.fail("failed", t.offset)
}
+func (t *ginkgoTestingTProxy) Failed() bool {
+ return t.failed()
+}
+
func (t *ginkgoTestingTProxy) Fatal(args ...interface{}) {
t.fail(fmt.Sprintln(args...), t.offset)
}
@@ -45,6 +62,10 @@ func (t *ginkgoTestingTProxy) Fatalf(format string, args ...interface{}) {
t.fail(fmt.Sprintf(format, args...), t.offset)
}
+func (t *ginkgoTestingTProxy) Helper() {
+ // No-op
+}
+
func (t *ginkgoTestingTProxy) Log(args ...interface{}) {
fmt.Fprintln(t.writer, args...)
}
@@ -53,24 +74,31 @@ func (t *ginkgoTestingTProxy) Logf(format string, args ...interface{}) {
t.Log(fmt.Sprintf(format, args...))
}
-func (t *ginkgoTestingTProxy) Failed() bool {
- return false
+func (t *ginkgoTestingTProxy) Name() string {
+ return t.name()
}
func (t *ginkgoTestingTProxy) Parallel() {
+ // No-op
}
func (t *ginkgoTestingTProxy) Skip(args ...interface{}) {
- fmt.Println(args...)
+ t.skip(fmt.Sprintln(args...), t.offset)
}
-func (t *ginkgoTestingTProxy) Skipf(format string, args ...interface{}) {
- t.Skip(fmt.Sprintf(format, args...))
+func (t *ginkgoTestingTProxy) SkipNow() {
+ t.skip("skip", t.offset)
}
-func (t *ginkgoTestingTProxy) SkipNow() {
+func (t *ginkgoTestingTProxy) Skipf(format string, args ...interface{}) {
+ t.skip(fmt.Sprintf(format, args...), t.offset)
}
func (t *ginkgoTestingTProxy) Skipped() bool {
return false
}
+
+func (t *ginkgoTestingTProxy) TempDir() string {
+ // No-op
+ return ""
+}
diff --git a/vendor/github.com/onsi/ginkgo/reporters/junit_reporter.go b/vendor/github.com/onsi/ginkgo/reporters/junit_reporter.go
index 963caaaff..01ddca6e1 100644
--- a/vendor/github.com/onsi/ginkgo/reporters/junit_reporter.go
+++ b/vendor/github.com/onsi/ginkgo/reporters/junit_reporter.go
@@ -33,17 +33,12 @@ type JUnitTestSuite struct {
type JUnitTestCase struct {
Name string `xml:"name,attr"`
ClassName string `xml:"classname,attr"`
- PassedMessage *JUnitPassedMessage `xml:"passed,omitempty"`
FailureMessage *JUnitFailureMessage `xml:"failure,omitempty"`
Skipped *JUnitSkipped `xml:"skipped,omitempty"`
Time float64 `xml:"time,attr"`
SystemOut string `xml:"system-out,omitempty"`
}
-type JUnitPassedMessage struct {
- Message string `xml:",chardata"`
-}
-
type JUnitFailureMessage struct {
Type string `xml:"type,attr"`
Message string `xml:",chardata"`
@@ -114,9 +109,7 @@ func (reporter *JUnitReporter) SpecDidComplete(specSummary *types.SpecSummary) {
ClassName: reporter.testSuiteName,
}
if reporter.ReporterConfig.ReportPassed && specSummary.State == types.SpecStatePassed {
- testCase.PassedMessage = &JUnitPassedMessage{
- Message: specSummary.CapturedOutput,
- }
+ testCase.SystemOut = specSummary.CapturedOutput
}
if specSummary.State == types.SpecStateFailed || specSummary.State == types.SpecStateTimedOut || specSummary.State == types.SpecStatePanicked {
testCase.FailureMessage = &JUnitFailureMessage{
diff --git a/vendor/github.com/onsi/ginkgo/types/deprecation_support.go b/vendor/github.com/onsi/ginkgo/types/deprecation_support.go
new file mode 100644
index 000000000..305c134b7
--- /dev/null
+++ b/vendor/github.com/onsi/ginkgo/types/deprecation_support.go
@@ -0,0 +1,150 @@
+package types
+
+import (
+ "os"
+ "strconv"
+ "strings"
+ "unicode"
+
+ "github.com/onsi/ginkgo/config"
+ "github.com/onsi/ginkgo/formatter"
+)
+
+type Deprecation struct {
+ Message string
+ DocLink string
+ Version string
+}
+
+type deprecations struct{}
+
+var Deprecations = deprecations{}
+
+func (d deprecations) CustomReporter() Deprecation {
+ return Deprecation{
+ Message: "You are using a custom reporter. Support for custom reporters will likely be removed in V2. Most users were using them to generate junit or teamcity reports and this functionality will be merged into the core reporter. In addition, Ginkgo 2.0 will support emitting a JSON-formatted report that users can then manipulate to generate custom reports.\n\n{{red}}{{bold}}If this change will be impactful to you please leave a comment on {{cyan}}{{underline}}https://github.com/onsi/ginkgo/issues/711{{/}}",
+ DocLink: "removed-custom-reporters",
+ Version: "1.16.0",
+ }
+}
+
+func (d deprecations) V1Reporter() Deprecation {
+ return Deprecation{
+ Message: "You are using a V1 Ginkgo Reporter. Please update your custom reporter to the new V2 Reporter interface.",
+ DocLink: "changed-reporter-interface",
+ Version: "1.16.0",
+ }
+}
+
+func (d deprecations) Async() Deprecation {
+ return Deprecation{
+ Message: "You are passing a Done channel to a test node to test asynchronous behavior. This is deprecated in Ginkgo V2. Your test will run synchronously and the timeout will be ignored.",
+ DocLink: "removed-async-testing",
+ Version: "1.16.0",
+ }
+}
+
+func (d deprecations) Measure() Deprecation {
+ return Deprecation{
+ Message: "Measure is deprecated and will be removed in Ginkgo V2. Please migrate to gomega/gmeasure.",
+ DocLink: "removed-measure",
+ Version: "1.16.3",
+ }
+}
+
+func (d deprecations) Convert() Deprecation {
+ return Deprecation{
+ Message: "The convert command is deprecated in Ginkgo V2",
+ DocLink: "removed-ginkgo-convert",
+ Version: "1.16.0",
+ }
+}
+
+func (d deprecations) Blur() Deprecation {
+ return Deprecation{
+ Message: "The blur command is deprecated in Ginkgo V2. Use 'ginkgo unfocus' instead.",
+ Version: "1.16.0",
+ }
+}
+
+type DeprecationTracker struct {
+ deprecations map[Deprecation][]CodeLocation
+}
+
+func NewDeprecationTracker() *DeprecationTracker {
+ return &DeprecationTracker{
+ deprecations: map[Deprecation][]CodeLocation{},
+ }
+}
+
+func (d *DeprecationTracker) TrackDeprecation(deprecation Deprecation, cl ...CodeLocation) {
+ ackVersion := os.Getenv("ACK_GINKGO_DEPRECATIONS")
+ if deprecation.Version != "" && ackVersion != "" {
+ ack := ParseSemVer(ackVersion)
+ version := ParseSemVer(deprecation.Version)
+ if ack.GreaterThanOrEqualTo(version) {
+ return
+ }
+ }
+
+ if len(cl) == 1 {
+ d.deprecations[deprecation] = append(d.deprecations[deprecation], cl[0])
+ } else {
+ d.deprecations[deprecation] = []CodeLocation{}
+ }
+}
+
+func (d *DeprecationTracker) DidTrackDeprecations() bool {
+ return len(d.deprecations) > 0
+}
+
+func (d *DeprecationTracker) DeprecationsReport() string {
+ out := formatter.F("{{light-yellow}}You're using deprecated Ginkgo functionality:{{/}}\n")
+ out += formatter.F("{{light-yellow}}============================================={{/}}\n")
+ out += formatter.F("Ginkgo 2.0 is under active development and will introduce (a small number of) breaking changes.\n")
+ out += formatter.F("To learn more, view the migration guide at {{cyan}}{{underline}}https://github.com/onsi/ginkgo/blob/v2/docs/MIGRATING_TO_V2.md{{/}}\n")
+ out += formatter.F("To comment, chime in at {{cyan}}{{underline}}https://github.com/onsi/ginkgo/issues/711{{/}}\n\n")
+
+ for deprecation, locations := range d.deprecations {
+ out += formatter.Fi(1, "{{yellow}}"+deprecation.Message+"{{/}}\n")
+ if deprecation.DocLink != "" {
+ out += formatter.Fi(1, "{{bold}}Learn more at:{{/}} {{cyan}}{{underline}}https://github.com/onsi/ginkgo/blob/v2/docs/MIGRATING_TO_V2.md#%s{{/}}\n", deprecation.DocLink)
+ }
+ for _, location := range locations {
+ out += formatter.Fi(2, "{{gray}}%s{{/}}\n", location)
+ }
+ }
+ out += formatter.F("\n{{gray}}To silence deprecations that can be silenced set the following environment variable:{{/}}\n")
+ out += formatter.Fi(1, "{{gray}}ACK_GINKGO_DEPRECATIONS=%s{{/}}\n", config.VERSION)
+ return out
+}
+
+type SemVer struct {
+ Major int
+ Minor int
+ Patch int
+}
+
+func (s SemVer) GreaterThanOrEqualTo(o SemVer) bool {
+ return (s.Major > o.Major) ||
+ (s.Major == o.Major && s.Minor > o.Minor) ||
+ (s.Major == o.Major && s.Minor == o.Minor && s.Patch >= o.Patch)
+}
+
+func ParseSemVer(semver string) SemVer {
+ out := SemVer{}
+ semver = strings.TrimFunc(semver, func(r rune) bool {
+ return !(unicode.IsNumber(r) || r == '.')
+ })
+ components := strings.Split(semver, ".")
+ if len(components) > 0 {
+ out.Major, _ = strconv.Atoi(components[0])
+ }
+ if len(components) > 1 {
+ out.Minor, _ = strconv.Atoi(components[1])
+ }
+ if len(components) > 2 {
+ out.Patch, _ = strconv.Atoi(components[2])
+ }
+ return out
+}
diff --git a/vendor/github.com/onsi/gomega/.travis.yml b/vendor/github.com/onsi/gomega/.travis.yml
index e250be4ac..6543dc553 100644
--- a/vendor/github.com/onsi/gomega/.travis.yml
+++ b/vendor/github.com/onsi/gomega/.travis.yml
@@ -1,17 +1,18 @@
language: go
+arch:
+ - amd64
+ - ppc64le
go:
- - 1.14.x
- - 1.15.x
- gotip
+ - 1.16.x
+ - 1.15.x
env:
- GO111MODULE=on
-install:
- - go get -v ./...
- - go build ./...
- - go get github.com/onsi/ginkgo
- - go install github.com/onsi/ginkgo/ginkgo
+install: skip
-script: make test
+script:
+ - go mod tidy && git diff --exit-code go.mod go.sum
+ - make test
diff --git a/vendor/github.com/onsi/gomega/CHANGELOG.md b/vendor/github.com/onsi/gomega/CHANGELOG.md
index 940953394..3486f3582 100644
--- a/vendor/github.com/onsi/gomega/CHANGELOG.md
+++ b/vendor/github.com/onsi/gomega/CHANGELOG.md
@@ -1,3 +1,76 @@
+## 1.15.0
+
+### Fixes
+The previous version (1.14.0) introduced a change to allow `Eventually` and `Consistently` to support functions that make assertions. This was accomplished by overriding the global fail handler when running the callbacks passed to `Eventually/Consistently` in order to capture any resulting errors. Issue #457 uncovered a flaw with this approach: when multiple `Eventually`s are running concurrently they race when overriding the singleton global fail handler.
+
+1.15.0 resolves this by requiring users who want to make assertions in `Eventually/Consistently` call backs to explicitly pass in a function that takes a `Gomega` as an argument. The passed-in `Gomega` instance can be used to make assertions. Any failures will cause `Eventually` to retry the callback. This cleaner interface avoids the issue of swapping out globals but comes at the cost of changing the contract introduced in v1.14.0. As such 1.15.0 introduces a breaking change with respect to 1.14.0 - however we expect that adoption of this feature in 1.14.0 remains limited.
+
+In addition, 1.15.0 cleans up some of Gomega's internals. Most users shouldn't notice any differences stemming from the refactoring that was made.
+
+## 1.14.0
+
+### Features
+- gmeasure.SamplingConfig now suppers a MinSamplingInterval [e94dbca]
+- Eventually and Consistently support functions that make assertions [2f04e6e]
+ - Eventually and Consistently now allow their passed-in functions to make assertions.
+ These assertions must pass or the function is considered to have failed and is retried.
+ - Eventually and Consistently can now take functions with no return values. These implicitly return nil
+ if they contain no failed assertion. Otherwise they return an error wrapping the first assertion failure. This allows
+ these functions to be used with the Succeed() matcher.
+ - Introduce InterceptGomegaFailure - an analogue to InterceptGomegaFailures - that captures the first assertion failure
+ and halts execution in its passed-in callback.
+
+### Fixes
+- Call Verify GHTTPWithGomega receiver funcs (#454) [496e6fd]
+- Build a binary with an expected name (#446) [7356360]
+
+## 1.13.0
+
+### Features
+- gmeasure provides BETA support for benchmarking (#447) [8f2dfbf]
+- Set consistently and eventually defaults on init (#443) [12eb778]
+
+## 1.12.0
+
+### Features
+- Add Satisfy() matcher (#437) [c548f31]
+- tweak truncation message [3360b8c]
+- Add format.GomegaStringer (#427) [cc80b6f]
+- Add Clear() method to gbytes.Buffer [c3c0920]
+
+### Fixes
+- Fix error message in BeNumericallyMatcher (#432) [09c074a]
+- Bump github.com/onsi/ginkgo from 1.12.1 to 1.16.2 (#442) [e5f6ea0]
+- Bump github.com/golang/protobuf from 1.4.3 to 1.5.2 (#431) [adae3bf]
+- Bump golang.org/x/net (#441) [3275b35]
+
+## 1.11.0
+
+### Features
+- feature: add index to gstruct element func (#419) [334e00d]
+- feat(gexec) Add CompileTest functions. Close #410 (#411) [47c613f]
+
+### Fixes
+- Check more carefully for nils in WithTransform (#423) [3c60a15]
+- fix: typo in Makefile [b82522a]
+- Allow WithTransform function to accept a nil value (#422) [b75d2f2]
+- fix: print value type for interface{} containers (#409) [f08e2dc]
+- fix(BeElementOf): consistently flatten expected values [1fa9468]
+
+## 1.10.5
+
+### Fixes
+- fix: collections matchers should display type of expectation (#408) [6b4eb5a]
+- fix(ContainElements): consistently flatten expected values [073b880]
+- fix(ConsistOf): consistently flatten expected values [7266efe]
+
+## 1.10.4
+
+### Fixes
+- update golang net library to more recent version without vulnerability (#406) [817a8b9]
+- Correct spelling: alloted -> allotted (#403) [0bae715]
+- fix a panic in MessageWithDiff with long message (#402) [ea06b9b]
+
## 1.10.3
### Fixes
diff --git a/vendor/github.com/onsi/gomega/Dockerfile b/vendor/github.com/onsi/gomega/Dockerfile
new file mode 100644
index 000000000..11c7e63e7
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/Dockerfile
@@ -0,0 +1 @@
+FROM golang:1.15
diff --git a/vendor/github.com/onsi/gomega/Makefile b/vendor/github.com/onsi/gomega/Makefile
index c92cd56e3..1c6d107e1 100644
--- a/vendor/github.com/onsi/gomega/Makefile
+++ b/vendor/github.com/onsi/gomega/Makefile
@@ -1,6 +1,33 @@
-test:
- [ -z "`gofmt -s -w -l -e .`" ]
- go vet
- ginkgo -p -r --randomizeAllSpecs --failOnPending --randomizeSuites --race
+###### Help ###################################################################
-.PHONY: test
+.DEFAULT_GOAL = help
+
+.PHONY: help
+
+help: ## list Makefile targets
+ @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'
+
+###### Targets ################################################################
+
+test: version download fmt vet ginkgo ## Runs all build, static analysis, and test steps
+
+download: ## Download dependencies
+ go mod download
+
+vet: ## Run static code analysis
+ go vet ./...
+
+ginkgo: ## Run tests using Ginkgo
+ go run github.com/onsi/ginkgo/ginkgo -p -r --randomizeAllSpecs --failOnPending --randomizeSuites --race
+
+fmt: ## Checks that the code is formatted correcty
+ @@if [ -n "$$(gofmt -s -e -l -d .)" ]; then \
+ echo "gofmt check failed: run 'gofmt -s -e -l -w .'"; \
+ exit 1; \
+ fi
+
+docker_test: ## Run tests in a container via docker-compose
+ docker-compose build test && docker-compose run --rm test make test
+
+version: ## Display the version of Go
+ @@go version
diff --git a/vendor/github.com/onsi/gomega/README.md b/vendor/github.com/onsi/gomega/README.md
index 76aa6b558..d45a8c4e5 100644
--- a/vendor/github.com/onsi/gomega/README.md
+++ b/vendor/github.com/onsi/gomega/README.md
@@ -1,6 +1,6 @@
![Gomega: Ginkgo's Preferred Matcher Library](http://onsi.github.io/gomega/images/gomega.png)
-[![Build Status](https://travis-ci.org/onsi/gomega.svg?branch=master)](https://travis-ci.org/onsi/gomega)
+[![test](https://github.com/onsi/gomega/actions/workflows/test.yml/badge.svg)](https://github.com/onsi/gomega/actions/workflows/test.yml)
Jump straight to the [docs](http://onsi.github.io/gomega/) to learn about Gomega, including a list of [all available matchers](http://onsi.github.io/gomega/#provided-matchers).
diff --git a/vendor/github.com/onsi/gomega/docker-compose.yaml b/vendor/github.com/onsi/gomega/docker-compose.yaml
new file mode 100644
index 000000000..f37496143
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/docker-compose.yaml
@@ -0,0 +1,10 @@
+version: '3.0'
+
+services:
+ test:
+ build:
+ dockerfile: Dockerfile
+ context: .
+ working_dir: /app
+ volumes:
+ - ${PWD}:/app
diff --git a/vendor/github.com/onsi/gomega/format/format.go b/vendor/github.com/onsi/gomega/format/format.go
index fae25adce..6e78c391d 100644
--- a/vendor/github.com/onsi/gomega/format/format.go
+++ b/vendor/github.com/onsi/gomega/format/format.go
@@ -7,6 +7,7 @@ Gomega's format package pretty-prints objects. It explores input objects recurs
package format
import (
+ "context"
"fmt"
"reflect"
"strconv"
@@ -17,6 +18,10 @@ import (
// Use MaxDepth to set the maximum recursion depth when printing deeply nested objects
var MaxDepth = uint(10)
+// MaxLength of the string representation of an object.
+// If MaxLength is set to 0, the Object will not be truncated.
+var MaxLength = 4000
+
/*
By default, all objects (even those that implement fmt.Stringer and fmt.GoStringer) are recursively inspected to generate output.
@@ -44,16 +49,7 @@ var TruncateThreshold uint = 50
// after the first diff location in a truncated string assertion error message.
var CharactersAroundMismatchToInclude uint = 5
-// Ctx interface defined here to keep backwards compatibility with go < 1.7
-// It matches the context.Context interface
-type Ctx interface {
- Deadline() (deadline time.Time, ok bool)
- Done() <-chan struct{}
- Err() error
- Value(key interface{}) interface{}
-}
-
-var contextType = reflect.TypeOf((*Ctx)(nil)).Elem()
+var contextType = reflect.TypeOf((*context.Context)(nil)).Elem()
var timeType = reflect.TypeOf(time.Time{})
//The default indentation string emitted by the format package
@@ -61,6 +57,14 @@ var Indent = " "
var longFormThreshold = 20
+// GomegaStringer allows for custom formating of objects for gomega.
+type GomegaStringer interface {
+ // GomegaString will be used to custom format an object.
+ // It does not follow UseStringerRepresentation value and will always be called regardless.
+ // It also ignores the MaxLength value.
+ GomegaString() string
+}
+
/*
Generates a formatted matcher success/failure message of the form:
@@ -105,7 +109,13 @@ func MessageWithDiff(actual, message, expected string) string {
tabLength := 4
spaceFromMessageToActual := tabLength + len("<string>: ") - len(message)
- padding := strings.Repeat(" ", spaceFromMessageToActual+spacesBeforeFormattedMismatch) + "|"
+
+ paddingCount := spaceFromMessageToActual + spacesBeforeFormattedMismatch
+ if paddingCount < 0 {
+ return Message(formattedActual, message, formattedExpected)
+ }
+
+ padding := strings.Repeat(" ", paddingCount) + "|"
return Message(formattedActual, message+padding, formattedExpected)
}
@@ -161,6 +171,33 @@ func findFirstMismatch(a, b string) int {
return 0
}
+const truncateHelpText = `
+Gomega truncated this representation as it exceeds 'format.MaxLength'.
+Consider having the object provide a custom 'GomegaStringer' representation
+or adjust the parameters in Gomega's 'format' package.
+
+Learn more here: https://onsi.github.io/gomega/#adjusting-output
+`
+
+func truncateLongStrings(s string) string {
+ if MaxLength > 0 && len(s) > MaxLength {
+ var sb strings.Builder
+ for i, r := range s {
+ if i < MaxLength {
+ sb.WriteRune(r)
+ continue
+ }
+ break
+ }
+
+ sb.WriteString("...\n")
+ sb.WriteString(truncateHelpText)
+
+ return sb.String()
+ }
+ return s
+}
+
/*
Pretty prints the passed in object at the passed in indentation level.
@@ -175,7 +212,7 @@ Set PrintContextObjects to true to print the content of objects implementing con
func Object(object interface{}, indentation uint) string {
indent := strings.Repeat(Indent, int(indentation))
value := reflect.ValueOf(object)
- return fmt.Sprintf("%s<%s>: %s", indent, formatType(object), formatValue(value, indentation))
+ return fmt.Sprintf("%s<%s>: %s", indent, formatType(value), formatValue(value, indentation))
}
/*
@@ -195,25 +232,20 @@ func IndentString(s string, indentation uint) string {
return result
}
-func formatType(object interface{}) string {
- t := reflect.TypeOf(object)
- if t == nil {
+func formatType(v reflect.Value) string {
+ switch v.Kind() {
+ case reflect.Invalid:
return "nil"
- }
- switch t.Kind() {
case reflect.Chan:
- v := reflect.ValueOf(object)
- return fmt.Sprintf("%T | len:%d, cap:%d", object, v.Len(), v.Cap())
+ return fmt.Sprintf("%s | len:%d, cap:%d", v.Type(), v.Len(), v.Cap())
case reflect.Ptr:
- return fmt.Sprintf("%T | %p", object, object)
+ return fmt.Sprintf("%s | 0x%x", v.Type(), v.Pointer())
case reflect.Slice:
- v := reflect.ValueOf(object)
- return fmt.Sprintf("%T | len:%d, cap:%d", object, v.Len(), v.Cap())
+ return fmt.Sprintf("%s | len:%d, cap:%d", v.Type(), v.Len(), v.Cap())
case reflect.Map:
- v := reflect.ValueOf(object)
- return fmt.Sprintf("%T | len:%d", object, v.Len())
+ return fmt.Sprintf("%s | len:%d", v.Type(), v.Len())
default:
- return fmt.Sprintf("%T", object)
+ return fmt.Sprintf("%s", v.Type())
}
}
@@ -226,14 +258,21 @@ func formatValue(value reflect.Value, indentation uint) string {
return "nil"
}
- if UseStringerRepresentation {
- if value.CanInterface() {
- obj := value.Interface()
+ if value.CanInterface() {
+ obj := value.Interface()
+
+ // GomegaStringer will take precedence to other representations and disregards UseStringerRepresentation
+ if x, ok := obj.(GomegaStringer); ok {
+ // do not truncate a user-defined GoMegaString() value
+ return x.GomegaString()
+ }
+
+ if UseStringerRepresentation {
switch x := obj.(type) {
case fmt.GoStringer:
- return x.GoString()
+ return truncateLongStrings(x.GoString())
case fmt.Stringer:
- return x.String()
+ return truncateLongStrings(x.String())
}
}
}
@@ -264,26 +303,26 @@ func formatValue(value reflect.Value, indentation uint) string {
case reflect.Ptr:
return formatValue(value.Elem(), indentation)
case reflect.Slice:
- return formatSlice(value, indentation)
+ return truncateLongStrings(formatSlice(value, indentation))
case reflect.String:
- return formatString(value.String(), indentation)
+ return truncateLongStrings(formatString(value.String(), indentation))
case reflect.Array:
- return formatSlice(value, indentation)
+ return truncateLongStrings(formatSlice(value, indentation))
case reflect.Map:
- return formatMap(value, indentation)
+ return truncateLongStrings(formatMap(value, indentation))
case reflect.Struct:
if value.Type() == timeType && value.CanInterface() {
t, _ := value.Interface().(time.Time)
return t.Format(time.RFC3339Nano)
}
- return formatStruct(value, indentation)
+ return truncateLongStrings(formatStruct(value, indentation))
case reflect.Interface:
- return formatValue(value.Elem(), indentation)
+ return formatInterface(value, indentation)
default:
if value.CanInterface() {
- return fmt.Sprintf("%#v", value.Interface())
+ return truncateLongStrings(fmt.Sprintf("%#v", value.Interface()))
}
- return fmt.Sprintf("%#v", value)
+ return truncateLongStrings(fmt.Sprintf("%#v", value))
}
}
@@ -373,6 +412,10 @@ func formatStruct(v reflect.Value, indentation uint) string {
return fmt.Sprintf("{%s}", strings.Join(result, ", "))
}
+func formatInterface(v reflect.Value, indentation uint) string {
+ return fmt.Sprintf("<%s>%s", formatType(v.Elem()), formatValue(v.Elem(), indentation))
+}
+
func isNilValue(a reflect.Value) bool {
switch a.Kind() {
case reflect.Invalid:
diff --git a/vendor/github.com/onsi/gomega/go.mod b/vendor/github.com/onsi/gomega/go.mod
index 0a80d5ec3..62b8f396c 100644
--- a/vendor/github.com/onsi/gomega/go.mod
+++ b/vendor/github.com/onsi/gomega/go.mod
@@ -3,9 +3,8 @@ module github.com/onsi/gomega
go 1.14
require (
- github.com/golang/protobuf v1.4.2
- github.com/onsi/ginkgo v1.12.1
- golang.org/x/net v0.0.0-20201006153459-a7d1128ccaa0
- golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543
- gopkg.in/yaml.v2 v2.3.0
+ github.com/golang/protobuf v1.5.2
+ github.com/onsi/ginkgo v1.16.4
+ golang.org/x/net v0.0.0-20210428140749-89ef3d95e781
+ gopkg.in/yaml.v2 v2.4.0
)
diff --git a/vendor/github.com/onsi/gomega/go.sum b/vendor/github.com/onsi/gomega/go.sum
index c54e9b88e..177d5e876 100644
--- a/vendor/github.com/onsi/gomega/go.sum
+++ b/vendor/github.com/onsi/gomega/go.sum
@@ -1,69 +1,95 @@
-github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
+github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
-github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM=
+github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
+github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
+github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 h1:p104kn46Q8WdvHunIJ9dAyjPVtrBPhSr3KT2yUst43I=
+github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
-github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0=
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
+github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
+github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
+github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
-github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
+github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
+github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
-github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78=
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
-github.com/onsi/ginkgo v1.6.0 h1:Ix8l273rp3QzYgXSR+c8d1fTG7UPgYkOSELPhiY/YGw=
+github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
+github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
-github.com/onsi/ginkgo v1.12.1 h1:mFwc4LvZ0xpSvDZ3E+k8Yte0hLOMxXUlP+yXtJqkYfQ=
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
+github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc=
+github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
+github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
+github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
+github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
-golang.org/x/net v0.0.0-20180906233101-161cd47e91fd h1:nTDtHvHSdCn1m6ITfMRqtOd/9+7a3s8RBNOZ3eYZzJA=
+golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
-golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7 h1:AeiKBIuRw3UomYXSbLy0Mc2dDLfdtbT/IVn4keq83P0=
+golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
-golang.org/x/net v0.0.0-20201006153459-a7d1128ccaa0 h1:wBouT66WTYFXdxfVdz9sVWARVd/2vfGcmI45D2gj45M=
-golang.org/x/net v0.0.0-20201006153459-a7d1128ccaa0/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
-golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f h1:wMNYb4v58l5UBM7MYRLPG6ZhfOqbKu7X5eyFl8ZhKvA=
+golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
+golang.org/x/net v0.0.0-20210428140749-89ef3d95e781 h1:DzZ89McO9/gWPsQXS/FVKAlG02ZjaQ6AlZRBimEYOd0=
+golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e h1:o3PsSEY8E4eXWkXrIP9YJALUkVZqzHJT5DOasTyn8Vs=
+golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e h1:N7DeIrjYszNmSW409R3frPPwglRwMkXSBzwVbkOjLLA=
+golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd h1:xhmwyvizuTgC2qz7ZlMluP20uW+C3Rm0FD/WLDX8884=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
+golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210423082822-04245dca01da h1:b3NXsE2LusjYGGjL5bxEVZZORm/YEFFrWFjR8eFrw/c=
+golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
-golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M=
+golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
-golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
+golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e h1:4nW4NLDYnU28ojHaHO8OVxFHk/aQ33U01a9cjED+pzE=
+golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
+golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
+golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
-google.golang.org/protobuf v1.23.0 h1:4MY060fB1DLGMB/7MBTLnwQUY6+F09GEiz6SsrNqyzM=
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
+google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
+google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk=
+google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
-gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
-gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I=
+gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
-gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
+gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
diff --git a/vendor/github.com/onsi/gomega/gomega_dsl.go b/vendor/github.com/onsi/gomega/gomega_dsl.go
index 4af1a8c01..6c7f1d9b7 100644
--- a/vendor/github.com/onsi/gomega/gomega_dsl.go
+++ b/vendor/github.com/onsi/gomega/gomega_dsl.go
@@ -14,101 +14,148 @@ Gomega is MIT-Licensed
package gomega
import (
+ "errors"
"fmt"
- "reflect"
"time"
- "github.com/onsi/gomega/internal/assertion"
- "github.com/onsi/gomega/internal/asyncassertion"
- "github.com/onsi/gomega/internal/testingtsupport"
+ "github.com/onsi/gomega/internal"
"github.com/onsi/gomega/types"
)
-const GOMEGA_VERSION = "1.10.3"
+const GOMEGA_VERSION = "1.15.0"
-const nilFailHandlerPanic = `You are trying to make an assertion, but Gomega's fail handler is nil.
+const nilGomegaPanic = `You are trying to make an assertion, but haven't registered Gomega's fail handler.
If you're using Ginkgo then you probably forgot to put your assertion in an It().
Alternatively, you may have forgotten to register a fail handler with RegisterFailHandler() or RegisterTestingT().
Depending on your vendoring solution you may be inadvertently importing gomega and subpackages (e.g. ghhtp, gexec,...) from different locations.
`
-var globalFailWrapper *types.GomegaFailWrapper
-
-var defaultEventuallyTimeout = time.Second
-var defaultEventuallyPollingInterval = 10 * time.Millisecond
-var defaultConsistentlyDuration = 100 * time.Millisecond
-var defaultConsistentlyPollingInterval = 10 * time.Millisecond
-
-// RegisterFailHandler connects Ginkgo to Gomega. When a matcher fails
-// the fail handler passed into RegisterFailHandler is called.
-func RegisterFailHandler(handler types.GomegaFailHandler) {
- RegisterFailHandlerWithT(testingtsupport.EmptyTWithHelper{}, handler)
-}
+// Gomega describes the essential Gomega DSL. This interface allows libraries
+// to abstract between the standard package-level function implementations
+// and alternatives like *WithT.
+//
+// The types in the top-level DSL have gotten a bit messy due to earlier depracations that avoid stuttering
+// and due to an accidental use of a concrete type (*WithT) in an earlier release.
+//
+// As of 1.15 both the WithT and Ginkgo variants of Gomega are implemented by the same underlying object
+// however one (the Ginkgo variant) is exported as an interface (types.Gomega) whereas the other (the withT variant)
+// is shared as a concrete type (*WithT, which is aliased to *internal.Gomega). 1.15 did not clean this mess up to ensure
+// that declarations of *WithT in existing code are not broken by the upgrade to 1.15.
+type Gomega = types.Gomega
-// RegisterFailHandlerWithT ensures that the given types.TWithHelper and fail handler
-// are used globally.
-func RegisterFailHandlerWithT(t types.TWithHelper, handler types.GomegaFailHandler) {
- if handler == nil {
- globalFailWrapper = nil
- return
- }
+// DefaultGomega supplies the standard package-level implementation
+var Default = Gomega(internal.NewGomega(internal.FetchDefaultDurationBundle()))
- globalFailWrapper = &types.GomegaFailWrapper{
- Fail: handler,
- TWithHelper: t,
- }
+// NewGomega returns an instance of Gomega wired into the passed-in fail handler.
+// You generally don't need to use this when using Ginkgo - RegisterFailHandler will wire up the global gomega
+// However creating a NewGomega with a custom fail handler can be useful in contexts where you want to use Gomega's
+// rich ecosystem of matchers without causing a test to fail. For example, to aggregate a series of potential failures
+// or for use in a non-test setting.
+func NewGomega(fail types.GomegaFailHandler) Gomega {
+ return internal.NewGomega(Default.(*internal.Gomega).DurationBundle).ConfigureWithFailHandler(fail)
}
-// RegisterTestingT connects Gomega to Golang's XUnit style
-// Testing.T tests. It is now deprecated and you should use NewWithT() instead.
+// WithT wraps a *testing.T and provides `Expect`, `Eventually`, and `Consistently` methods. This allows you to leverage
+// Gomega's rich ecosystem of matchers in standard `testing` test suites.
//
-// Legacy Documentation:
+// Use `NewWithT` to instantiate a `WithT`
//
-// You'll need to call this at the top of each XUnit style test:
+// As of 1.15 both the WithT and Ginkgo variants of Gomega are implemented by the same underlying object
+// however one (the Ginkgo variant) is exported as an interface (types.Gomega) whereas the other (the withT variant)
+// is shared as a concrete type (*WithT, which is aliased to *internal.Gomega). 1.15 did not clean this mess up to ensure
+// that declarations of *WithT in existing code are not broken by the upgrade to 1.15.
+type WithT = internal.Gomega
+
+// GomegaWithT is deprecated in favor of gomega.WithT, which does not stutter.
+type GomegaWithT = WithT
+
+// NewWithT takes a *testing.T and returngs a `gomega.WithT` allowing you to use `Expect`, `Eventually`, and `Consistently` along with
+// Gomega's rich ecosystem of matchers in standard `testing` test suits.
//
// func TestFarmHasCow(t *testing.T) {
-// RegisterTestingT(t)
+// g := gomega.NewWithT(t)
//
// f := farm.New([]string{"Cow", "Horse"})
-// Expect(f.HasCow()).To(BeTrue(), "Farm should have cow")
-// }
-//
-// Note that this *testing.T is registered *globally* by Gomega (this is why you don't have to
-// pass `t` down to the matcher itself). This means that you cannot run the XUnit style tests
-// in parallel as the global fail handler cannot point to more than one testing.T at a time.
-//
-// NewWithT() does not have this limitation
-//
-// (As an aside: Ginkgo gets around this limitation by running parallel tests in different *processes*).
+// g.Expect(f.HasCow()).To(BeTrue(), "Farm should have cow")
+// }
+func NewWithT(t types.GomegaTestingT) *WithT {
+ return internal.NewGomega(Default.(*internal.Gomega).DurationBundle).ConfigureWithT(t)
+}
+
+// NewGomegaWithT is deprecated in favor of gomega.NewWithT, which does not stutter.
+var NewGomegaWithT = NewWithT
+
+// RegisterFailHandler connects Ginkgo to Gomega. When a matcher fails
+// the fail handler passed into RegisterFailHandler is called.
+func RegisterFailHandler(fail types.GomegaFailHandler) {
+ Default.(*internal.Gomega).ConfigureWithFailHandler(fail)
+}
+
+// RegisterFailHandlerWithT is deprecated and will be removed in a future release.
+// users should use RegisterFailHandler, or RegisterTestingT
+func RegisterFailHandlerWithT(_ types.GomegaTestingT, fail types.GomegaFailHandler) {
+ fmt.Println("RegisterFailHandlerWithT is deprecated. Please use RegisterFailHandler or RegisterTestingT instead.")
+ Default.(*internal.Gomega).ConfigureWithFailHandler(fail)
+}
+
+// RegisterTestingT connects Gomega to Golang's XUnit style
+// Testing.T tests. It is now deprecated and you should use NewWithT() instead to get a fresh instance of Gomega for each test.
func RegisterTestingT(t types.GomegaTestingT) {
- tWithHelper, hasHelper := t.(types.TWithHelper)
- if !hasHelper {
- RegisterFailHandler(testingtsupport.BuildTestingTGomegaFailWrapper(t).Fail)
- return
- }
- RegisterFailHandlerWithT(tWithHelper, testingtsupport.BuildTestingTGomegaFailWrapper(t).Fail)
+ Default.(*internal.Gomega).ConfigureWithT(t)
}
// InterceptGomegaFailures runs a given callback and returns an array of
// failure messages generated by any Gomega assertions within the callback.
-//
-// This is accomplished by temporarily replacing the *global* fail handler
-// with a fail handler that simply annotates failures. The original fail handler
-// is reset when InterceptGomegaFailures returns.
+// Exeuction continues after the first failure allowing users to collect all failures
+// in the callback.
//
// This is most useful when testing custom matchers, but can also be used to check
// on a value using a Gomega assertion without causing a test failure.
func InterceptGomegaFailures(f func()) []string {
- originalHandler := globalFailWrapper.Fail
+ originalHandler := Default.(*internal.Gomega).Fail
failures := []string{}
- RegisterFailHandler(func(message string, callerSkip ...int) {
+ Default.(*internal.Gomega).Fail = func(message string, callerSkip ...int) {
failures = append(failures, message)
- })
+ }
+ defer func() {
+ Default.(*internal.Gomega).Fail = originalHandler
+ }()
f()
- RegisterFailHandler(originalHandler)
return failures
}
+// InterceptGomegaFailure runs a given callback and returns the first
+// failure message generated by any Gomega assertions within the callback, wrapped in an error.
+//
+// The callback ceases execution as soon as the first failed assertion occurs, however Gomega
+// does not register a failure with the FailHandler registered via RegisterFailHandler - it is up
+// to the user to decide what to do with the returned error
+func InterceptGomegaFailure(f func()) (err error) {
+ originalHandler := Default.(*internal.Gomega).Fail
+ Default.(*internal.Gomega).Fail = func(message string, callerSkip ...int) {
+ err = errors.New(message)
+ panic("stop execution")
+ }
+
+ defer func() {
+ Default.(*internal.Gomega).Fail = originalHandler
+ if e := recover(); e != nil {
+ if err == nil {
+ panic(e)
+ }
+ }
+ }()
+
+ f()
+ return err
+}
+
+func ensureDefaultGomegaIsConfigured() {
+ if !Default.(*internal.Gomega).IsConfigured() {
+ panic(nilGomegaPanic)
+ }
+}
+
// Ω wraps an actual value allowing assertions to be made on it:
// Ω("foo").Should(Equal("foo"))
//
@@ -127,7 +174,8 @@ func InterceptGomegaFailures(f func()) []string {
//
// Ω and Expect are identical
func Ω(actual interface{}, extra ...interface{}) Assertion {
- return ExpectWithOffset(0, actual, extra...)
+ ensureDefaultGomegaIsConfigured()
+ return Default.Ω(actual, extra...)
}
// Expect wraps an actual value allowing assertions to be made on it:
@@ -148,7 +196,8 @@ func Ω(actual interface{}, extra ...interface{}) Assertion {
//
// Expect and Ω are identical
func Expect(actual interface{}, extra ...interface{}) Assertion {
- return ExpectWithOffset(0, actual, extra...)
+ ensureDefaultGomegaIsConfigured()
+ return Default.Expect(actual, extra...)
}
// ExpectWithOffset wraps an actual value allowing assertions to be made on it:
@@ -161,133 +210,156 @@ func Expect(actual interface{}, extra ...interface{}) Assertion {
// error message to refer to the calling line in the test (as opposed to the line in the helper function)
// set the first argument of `ExpectWithOffset` appropriately.
func ExpectWithOffset(offset int, actual interface{}, extra ...interface{}) Assertion {
- if globalFailWrapper == nil {
- panic(nilFailHandlerPanic)
- }
- return assertion.New(actual, globalFailWrapper, offset, extra...)
+ ensureDefaultGomegaIsConfigured()
+ return Default.ExpectWithOffset(offset, actual, extra...)
}
-// Eventually wraps an actual value allowing assertions to be made on it.
-// The assertion is tried periodically until it passes or a timeout occurs.
-//
-// Both the timeout and polling interval are configurable as optional arguments:
-// The first optional argument is the timeout
-// The second optional argument is the polling interval
-//
-// Both intervals can either be specified as time.Duration, parsable duration strings or as floats/integers. In the
-// last case they are interpreted as seconds.
-//
-// If Eventually is passed an actual that is a function taking no arguments and returning at least one value,
-// then Eventually will call the function periodically and try the matcher against the function's first return value.
-//
-// Example:
-//
-// Eventually(func() int {
-// return thingImPolling.Count()
-// }).Should(BeNumerically(">=", 17))
-//
-// Note that this example could be rewritten:
-//
-// Eventually(thingImPolling.Count).Should(BeNumerically(">=", 17))
-//
-// If the function returns more than one value, then Eventually will pass the first value to the matcher and
-// assert that all other values are nil/zero.
-// This allows you to pass Eventually a function that returns a value and an error - a common pattern in Go.
-//
-// For example, consider a method that returns a value and an error:
-// func FetchFromDB() (string, error)
-//
-// Then
-// Eventually(FetchFromDB).Should(Equal("hasselhoff"))
-//
-// Will pass only if the the returned error is nil and the returned string passes the matcher.
-//
-// Eventually's default timeout is 1 second, and its default polling interval is 10ms
+/*
+Eventually enables making assertions on asynchronous behavior.
+
+Eventually checks that an assertion *eventually* passes. Eventually blocks when called and attempts an assertion periodically until it passes or a timeout occurs. Both the timeout and polling interval are configurable as optional arguments.
+The first optional argument is the timeout (which defaults to 1s), the second is the polling interval (which defaults to 10ms). Both intervals can be specified as time.Duration, parsable duration strings or floats/integers (in which case they are interpreted as seconds).
+
+Eventually works with any Gomega compatible matcher and supports making assertions against three categories of actual value:
+
+**Category 1: Making Eventually assertions on values**
+
+There are several examples of values that can change over time. These can be passed in to Eventually and will be passed to the matcher repeatedly until a match occurs. For example:
+
+ c := make(chan bool)
+ go DoStuff(c)
+ Eventually(c, "50ms").Should(BeClosed())
+
+will poll the channel repeatedly until it is closed. In this example `Eventually` will block until either the specified timeout of 50ms has elapsed or the channel is closed, whichever comes first.
+
+Several Gomega libraries allow you to use Eventually in this way. For example, the gomega/gexec package allows you to block until a *gexec.Session exits successfuly via:
+
+ Eventually(session).Should(gexec.Exit(0))
+
+And the gomega/gbytes package allows you to monitor a streaming *gbytes.Buffer until a given string is seen:
+
+ Eventually(buffer).Should(gbytes.Say("hello there"))
+
+In these examples, both `session` and `buffer` are designed to be thread-safe when polled by the `Exit` and `Say` matchers. This is not true in general of most raw values, so while it is tempting to do something like:
+
+ // THIS IS NOT THREAD-SAFE
+ var s *string
+ go mutateStringEventually(s)
+ Eventually(s).Should(Equal("I've changed"))
+
+this will trigger Go's race detector as the goroutine polling via Eventually will race over the value of s with the goroutine mutating the string. For cases like this you can use channels or introduce your own locking around s by passing Eventually a function.
+
+**Category 2: Make Eventually assertions on functions**
+
+Eventually can be passed functions that **take no arguments** and **return at least one value**. When configured this way, Eventually will poll the function repeatedly and pass the first returned value to the matcher.
+
+For example:
+
+ Eventually(func() int {
+ return client.FetchCount()
+ }).Should(BeNumerically(">=", 17))
+
+ will repeatedly poll client.FetchCount until the BeNumerically matcher is satisfied. (Note that this example could have been written as Eventually(client.FetchCount).Should(BeNumerically(">=", 17)))
+
+If multple values are returned by the function, Eventually will pass the first value to the matcher and require that all others are zero-valued. This allows you to pass Eventually a function that returns a value and an error - a common patternin Go.
+
+For example, consider a method that returns a value and an error:
+ func FetchFromDB() (string, error)
+
+Then
+ Eventually(FetchFromDB).Should(Equal("got it"))
+
+will pass only if and when the returned error is nil *and* the returned string satisfies the matcher.
+
+It is important to note that the function passed into Eventually is invoked *synchronously* when polled. Eventually does not (in fact, it cannot) kill the function if it takes longer to return than Eventually's configured timeout. You should design your functions with this in mind.
+
+**Category 3: Making assertions _in_ the function passed into Eventually**
+
+When testing complex systems it can be valuable to assert that a _set_ of assertions passes Eventually. Eventually supports this by accepting functions that take a single Gomega argument and return zero or more values.
+
+Here's an example that makes some asssertions and returns a value and error:
+
+ Eventually(func(g Gomega) (Widget, error) {
+ ids, err := client.FetchIDs()
+ g.Expect(err).NotTo(HaveOccurred())
+ g.Expect(ids).To(ContainElement(1138))
+ return client.FetchWidget(1138)
+ }).Should(Equal(expectedWidget))
+
+will pass only if all the assertions in the polled function pass and the return value satisfied the matcher.
+
+Eventually also supports a special case polling function that takes a single Gomega argument and returns no values. Eventually assumes such a function is making assertions and is designed to work with the Succeed matcher to validate that all assertions have passed.
+For example:
+
+ Eventually(func(g Gomega) {
+ model, err := client.Find(1138)
+ g.Expect(err).NotTo(HaveOccurred())
+ g.Expect(model.Reticulate()).To(Succeed())
+ g.Expect(model.IsReticulated()).To(BeTrue())
+ g.Expect(model.Save()).To(Succeed())
+ }).Should(Succeed())
+
+will rerun the function until all assertions pass.
+*/
func Eventually(actual interface{}, intervals ...interface{}) AsyncAssertion {
- return EventuallyWithOffset(0, actual, intervals...)
+ ensureDefaultGomegaIsConfigured()
+ return Default.Eventually(actual, intervals...)
}
// EventuallyWithOffset operates like Eventually but takes an additional
// initial argument to indicate an offset in the call stack. This is useful when building helper
// functions that contain matchers. To learn more, read about `ExpectWithOffset`.
func EventuallyWithOffset(offset int, actual interface{}, intervals ...interface{}) AsyncAssertion {
- if globalFailWrapper == nil {
- panic(nilFailHandlerPanic)
- }
- timeoutInterval := defaultEventuallyTimeout
- pollingInterval := defaultEventuallyPollingInterval
- if len(intervals) > 0 {
- timeoutInterval = toDuration(intervals[0])
- }
- if len(intervals) > 1 {
- pollingInterval = toDuration(intervals[1])
- }
- return asyncassertion.New(asyncassertion.AsyncAssertionTypeEventually, actual, globalFailWrapper, timeoutInterval, pollingInterval, offset)
+ ensureDefaultGomegaIsConfigured()
+ return Default.EventuallyWithOffset(offset, actual, intervals...)
}
-// Consistently wraps an actual value allowing assertions to be made on it.
-// The assertion is tried periodically and is required to pass for a period of time.
-//
-// Both the total time and polling interval are configurable as optional arguments:
-// The first optional argument is the duration that Consistently will run for
-// The second optional argument is the polling interval
-//
-// Both intervals can either be specified as time.Duration, parsable duration strings or as floats/integers. In the
-// last case they are interpreted as seconds.
-//
-// If Consistently is passed an actual that is a function taking no arguments and returning at least one value,
-// then Consistently will call the function periodically and try the matcher against the function's first return value.
-//
-// If the function returns more than one value, then Consistently will pass the first value to the matcher and
-// assert that all other values are nil/zero.
-// This allows you to pass Consistently a function that returns a value and an error - a common pattern in Go.
-//
-// Consistently is useful in cases where you want to assert that something *does not happen* over a period of time.
-// For example, you want to assert that a goroutine does *not* send data down a channel. In this case, you could:
-//
-// Consistently(channel).ShouldNot(Receive())
-//
-// Consistently's default duration is 100ms, and its default polling interval is 10ms
+/*
+Consistently, like Eventually, enables making assertions on asynchronous behavior.
+
+Consistently blocks when called for a specified duration. During that duration Consistently repeatedly polls its matcher and ensures that it is satisfied. If the matcher is consistently satisfied, then Consistently will pass. Otherwise Consistently will fail.
+
+Both the total waiting duration and the polling interval are configurable as optional arguments. The first optional arugment is the duration that Consistently will run for (defaults to 100ms), and the second argument is the polling interval (defaults to 10ms). As with Eventually, these intervals can be passed in as time.Duration, parsable duration strings or an integer or float number of seconds.
+
+Consistently accepts the same three categories of actual as Eventually, check the Eventually docs to learn more.
+
+Consistently is useful in cases where you want to assert that something *does not happen* for a period of time. For example, you may want to assert that a goroutine does *not* send data down a channel. In this case you could write:
+
+ Consistently(channel, "200ms").ShouldNot(Receive())
+
+This will block for 200 milliseconds and repeatedly check the channel and ensure nothing has been received.
+*/
func Consistently(actual interface{}, intervals ...interface{}) AsyncAssertion {
- return ConsistentlyWithOffset(0, actual, intervals...)
+ ensureDefaultGomegaIsConfigured()
+ return Default.Consistently(actual, intervals...)
}
// ConsistentlyWithOffset operates like Consistently but takes an additional
// initial argument to indicate an offset in the call stack. This is useful when building helper
// functions that contain matchers. To learn more, read about `ExpectWithOffset`.
func ConsistentlyWithOffset(offset int, actual interface{}, intervals ...interface{}) AsyncAssertion {
- if globalFailWrapper == nil {
- panic(nilFailHandlerPanic)
- }
- timeoutInterval := defaultConsistentlyDuration
- pollingInterval := defaultConsistentlyPollingInterval
- if len(intervals) > 0 {
- timeoutInterval = toDuration(intervals[0])
- }
- if len(intervals) > 1 {
- pollingInterval = toDuration(intervals[1])
- }
- return asyncassertion.New(asyncassertion.AsyncAssertionTypeConsistently, actual, globalFailWrapper, timeoutInterval, pollingInterval, offset)
+ ensureDefaultGomegaIsConfigured()
+ return Default.ConsistentlyWithOffset(offset, actual, intervals...)
}
// SetDefaultEventuallyTimeout sets the default timeout duration for Eventually. Eventually will repeatedly poll your condition until it succeeds, or until this timeout elapses.
func SetDefaultEventuallyTimeout(t time.Duration) {
- defaultEventuallyTimeout = t
+ Default.SetDefaultEventuallyTimeout(t)
}
// SetDefaultEventuallyPollingInterval sets the default polling interval for Eventually.
func SetDefaultEventuallyPollingInterval(t time.Duration) {
- defaultEventuallyPollingInterval = t
+ Default.SetDefaultEventuallyPollingInterval(t)
}
// SetDefaultConsistentlyDuration sets the default duration for Consistently. Consistently will verify that your condition is satisfied for this long.
func SetDefaultConsistentlyDuration(t time.Duration) {
- defaultConsistentlyDuration = t
+ Default.SetDefaultConsistentlyDuration(t)
}
// SetDefaultConsistentlyPollingInterval sets the default polling interval for Consistently.
func SetDefaultConsistentlyPollingInterval(t time.Duration) {
- defaultConsistentlyPollingInterval = t
+ Default.SetDefaultConsistentlyPollingInterval(t)
}
// AsyncAssertion is returned by Eventually and Consistently and polls the actual value passed into Eventually against
@@ -305,13 +377,10 @@ func SetDefaultConsistentlyPollingInterval(t time.Duration) {
//
// Eventually(myChannel).Should(Receive(), "Something should have come down the pipe.")
// Consistently(myChannel).ShouldNot(Receive(), func() string { return "Nothing should have come down the pipe." })
-type AsyncAssertion interface {
- Should(matcher types.GomegaMatcher, optionalDescription ...interface{}) bool
- ShouldNot(matcher types.GomegaMatcher, optionalDescription ...interface{}) bool
-}
+type AsyncAssertion = types.AsyncAssertion
// GomegaAsyncAssertion is deprecated in favor of AsyncAssertion, which does not stutter.
-type GomegaAsyncAssertion = AsyncAssertion
+type GomegaAsyncAssertion = types.AsyncAssertion
// Assertion is returned by Ω and Expect and compares the actual value to the matcher
// passed to the Should/ShouldNot and To/ToNot/NotTo methods.
@@ -330,149 +399,10 @@ type GomegaAsyncAssertion = AsyncAssertion
// Example:
//
// Ω(farm.HasCow()).Should(BeTrue(), "Farm %v should have a cow", farm)
-type Assertion interface {
- Should(matcher types.GomegaMatcher, optionalDescription ...interface{}) bool
- ShouldNot(matcher types.GomegaMatcher, optionalDescription ...interface{}) bool
-
- To(matcher types.GomegaMatcher, optionalDescription ...interface{}) bool
- ToNot(matcher types.GomegaMatcher, optionalDescription ...interface{}) bool
- NotTo(matcher types.GomegaMatcher, optionalDescription ...interface{}) bool
-}
+type Assertion = types.Assertion
// GomegaAssertion is deprecated in favor of Assertion, which does not stutter.
-type GomegaAssertion = Assertion
+type GomegaAssertion = types.Assertion
// OmegaMatcher is deprecated in favor of the better-named and better-organized types.GomegaMatcher but sticks around to support existing code that uses it
-type OmegaMatcher types.GomegaMatcher
-
-// WithT wraps a *testing.T and provides `Expect`, `Eventually`, and `Consistently` methods. This allows you to leverage
-// Gomega's rich ecosystem of matchers in standard `testing` test suites.
-//
-// Use `NewWithT` to instantiate a `WithT`
-type WithT struct {
- t types.GomegaTestingT
-}
-
-// GomegaWithT is deprecated in favor of gomega.WithT, which does not stutter.
-type GomegaWithT = WithT
-
-// NewWithT takes a *testing.T and returngs a `gomega.WithT` allowing you to use `Expect`, `Eventually`, and `Consistently` along with
-// Gomega's rich ecosystem of matchers in standard `testing` test suits.
-//
-// func TestFarmHasCow(t *testing.T) {
-// g := gomega.NewWithT(t)
-//
-// f := farm.New([]string{"Cow", "Horse"})
-// g.Expect(f.HasCow()).To(BeTrue(), "Farm should have cow")
-// }
-func NewWithT(t types.GomegaTestingT) *WithT {
- return &WithT{
- t: t,
- }
-}
-
-// NewGomegaWithT is deprecated in favor of gomega.NewWithT, which does not stutter.
-func NewGomegaWithT(t types.GomegaTestingT) *GomegaWithT {
- return NewWithT(t)
-}
-
-// ExpectWithOffset is used to make assertions. See documentation for ExpectWithOffset.
-func (g *WithT) ExpectWithOffset(offset int, actual interface{}, extra ...interface{}) Assertion {
- return assertion.New(actual, testingtsupport.BuildTestingTGomegaFailWrapper(g.t), offset, extra...)
-}
-
-// EventuallyWithOffset is used to make asynchronous assertions. See documentation for EventuallyWithOffset.
-func (g *WithT) EventuallyWithOffset(offset int, actual interface{}, intervals ...interface{}) AsyncAssertion {
- timeoutInterval := defaultEventuallyTimeout
- pollingInterval := defaultEventuallyPollingInterval
- if len(intervals) > 0 {
- timeoutInterval = toDuration(intervals[0])
- }
- if len(intervals) > 1 {
- pollingInterval = toDuration(intervals[1])
- }
- return asyncassertion.New(asyncassertion.AsyncAssertionTypeEventually, actual, testingtsupport.BuildTestingTGomegaFailWrapper(g.t), timeoutInterval, pollingInterval, offset)
-}
-
-// ConsistentlyWithOffset is used to make asynchronous assertions. See documentation for ConsistentlyWithOffset.
-func (g *WithT) ConsistentlyWithOffset(offset int, actual interface{}, intervals ...interface{}) AsyncAssertion {
- timeoutInterval := defaultConsistentlyDuration
- pollingInterval := defaultConsistentlyPollingInterval
- if len(intervals) > 0 {
- timeoutInterval = toDuration(intervals[0])
- }
- if len(intervals) > 1 {
- pollingInterval = toDuration(intervals[1])
- }
- return asyncassertion.New(asyncassertion.AsyncAssertionTypeConsistently, actual, testingtsupport.BuildTestingTGomegaFailWrapper(g.t), timeoutInterval, pollingInterval, offset)
-}
-
-// Expect is used to make assertions. See documentation for Expect.
-func (g *WithT) Expect(actual interface{}, extra ...interface{}) Assertion {
- return g.ExpectWithOffset(0, actual, extra...)
-}
-
-// Eventually is used to make asynchronous assertions. See documentation for Eventually.
-func (g *WithT) Eventually(actual interface{}, intervals ...interface{}) AsyncAssertion {
- return g.EventuallyWithOffset(0, actual, intervals...)
-}
-
-// Consistently is used to make asynchronous assertions. See documentation for Consistently.
-func (g *WithT) Consistently(actual interface{}, intervals ...interface{}) AsyncAssertion {
- return g.ConsistentlyWithOffset(0, actual, intervals...)
-}
-
-func toDuration(input interface{}) time.Duration {
- duration, ok := input.(time.Duration)
- if ok {
- return duration
- }
-
- value := reflect.ValueOf(input)
- kind := reflect.TypeOf(input).Kind()
-
- if reflect.Int <= kind && kind <= reflect.Int64 {
- return time.Duration(value.Int()) * time.Second
- } else if reflect.Uint <= kind && kind <= reflect.Uint64 {
- return time.Duration(value.Uint()) * time.Second
- } else if reflect.Float32 <= kind && kind <= reflect.Float64 {
- return time.Duration(value.Float() * float64(time.Second))
- } else if reflect.String == kind {
- duration, err := time.ParseDuration(value.String())
- if err != nil {
- panic(fmt.Sprintf("%#v is not a valid parsable duration string.", input))
- }
- return duration
- }
-
- panic(fmt.Sprintf("%v is not a valid interval. Must be time.Duration, parsable duration string or a number.", input))
-}
-
-// Gomega describes the essential Gomega DSL. This interface allows libraries
-// to abstract between the standard package-level function implementations
-// and alternatives like *WithT.
-type Gomega interface {
- Expect(actual interface{}, extra ...interface{}) Assertion
- Eventually(actual interface{}, intervals ...interface{}) AsyncAssertion
- Consistently(actual interface{}, intervals ...interface{}) AsyncAssertion
-}
-
-type globalFailHandlerGomega struct{}
-
-// DefaultGomega supplies the standard package-level implementation
-var Default Gomega = globalFailHandlerGomega{}
-
-// Expect is used to make assertions. See documentation for Expect.
-func (globalFailHandlerGomega) Expect(actual interface{}, extra ...interface{}) Assertion {
- return Expect(actual, extra...)
-}
-
-// Eventually is used to make asynchronous assertions. See documentation for Eventually.
-func (globalFailHandlerGomega) Eventually(actual interface{}, extra ...interface{}) AsyncAssertion {
- return Eventually(actual, extra...)
-}
-
-// Consistently is used to make asynchronous assertions. See documentation for Consistently.
-func (globalFailHandlerGomega) Consistently(actual interface{}, extra ...interface{}) AsyncAssertion {
- return Consistently(actual, extra...)
-}
+type OmegaMatcher = types.GomegaMatcher
diff --git a/vendor/github.com/onsi/gomega/internal/assertion/assertion.go b/vendor/github.com/onsi/gomega/internal/assertion.go
index a248298f4..36b0e8345 100644
--- a/vendor/github.com/onsi/gomega/internal/assertion/assertion.go
+++ b/vendor/github.com/onsi/gomega/internal/assertion.go
@@ -1,4 +1,4 @@
-package assertion
+package internal
import (
"fmt"
@@ -9,42 +9,42 @@ import (
type Assertion struct {
actualInput interface{}
- failWrapper *types.GomegaFailWrapper
offset int
extra []interface{}
+ g *Gomega
}
-func New(actualInput interface{}, failWrapper *types.GomegaFailWrapper, offset int, extra ...interface{}) *Assertion {
+func NewAssertion(actualInput interface{}, g *Gomega, offset int, extra ...interface{}) *Assertion {
return &Assertion{
actualInput: actualInput,
- failWrapper: failWrapper,
offset: offset,
extra: extra,
+ g: g,
}
}
func (assertion *Assertion) Should(matcher types.GomegaMatcher, optionalDescription ...interface{}) bool {
- assertion.failWrapper.TWithHelper.Helper()
+ assertion.g.THelper()
return assertion.vetExtras(optionalDescription...) && assertion.match(matcher, true, optionalDescription...)
}
func (assertion *Assertion) ShouldNot(matcher types.GomegaMatcher, optionalDescription ...interface{}) bool {
- assertion.failWrapper.TWithHelper.Helper()
+ assertion.g.THelper()
return assertion.vetExtras(optionalDescription...) && assertion.match(matcher, false, optionalDescription...)
}
func (assertion *Assertion) To(matcher types.GomegaMatcher, optionalDescription ...interface{}) bool {
- assertion.failWrapper.TWithHelper.Helper()
+ assertion.g.THelper()
return assertion.vetExtras(optionalDescription...) && assertion.match(matcher, true, optionalDescription...)
}
func (assertion *Assertion) ToNot(matcher types.GomegaMatcher, optionalDescription ...interface{}) bool {
- assertion.failWrapper.TWithHelper.Helper()
+ assertion.g.THelper()
return assertion.vetExtras(optionalDescription...) && assertion.match(matcher, false, optionalDescription...)
}
func (assertion *Assertion) NotTo(matcher types.GomegaMatcher, optionalDescription ...interface{}) bool {
- assertion.failWrapper.TWithHelper.Helper()
+ assertion.g.THelper()
return assertion.vetExtras(optionalDescription...) && assertion.match(matcher, false, optionalDescription...)
}
@@ -62,10 +62,10 @@ func (assertion *Assertion) buildDescription(optionalDescription ...interface{})
func (assertion *Assertion) match(matcher types.GomegaMatcher, desiredMatch bool, optionalDescription ...interface{}) bool {
matches, err := matcher.Match(assertion.actualInput)
- assertion.failWrapper.TWithHelper.Helper()
+ assertion.g.THelper()
if err != nil {
description := assertion.buildDescription(optionalDescription...)
- assertion.failWrapper.Fail(description+err.Error(), 2+assertion.offset)
+ assertion.g.Fail(description+err.Error(), 2+assertion.offset)
return false
}
if matches != desiredMatch {
@@ -76,7 +76,7 @@ func (assertion *Assertion) match(matcher types.GomegaMatcher, desiredMatch bool
message = matcher.NegatedFailureMessage(assertion.actualInput)
}
description := assertion.buildDescription(optionalDescription...)
- assertion.failWrapper.Fail(description+message, 2+assertion.offset)
+ assertion.g.Fail(description+message, 2+assertion.offset)
return false
}
@@ -90,8 +90,8 @@ func (assertion *Assertion) vetExtras(optionalDescription ...interface{}) bool {
}
description := assertion.buildDescription(optionalDescription...)
- assertion.failWrapper.TWithHelper.Helper()
- assertion.failWrapper.Fail(description+message, 2+assertion.offset)
+ assertion.g.THelper()
+ assertion.g.Fail(description+message, 2+assertion.offset)
return false
}
diff --git a/vendor/github.com/onsi/gomega/internal/asyncassertion/async_assertion.go b/vendor/github.com/onsi/gomega/internal/async_assertion.go
index 5204836bf..ae20c14b8 100644
--- a/vendor/github.com/onsi/gomega/internal/asyncassertion/async_assertion.go
+++ b/vendor/github.com/onsi/gomega/internal/async_assertion.go
@@ -1,14 +1,12 @@
-// untested sections: 2
-
-package asyncassertion
+package internal
import (
"errors"
"fmt"
"reflect"
+ "runtime"
"time"
- "github.com/onsi/gomega/internal/oraclematcher"
"github.com/onsi/gomega/types"
)
@@ -20,39 +18,82 @@ const (
)
type AsyncAssertion struct {
- asyncType AsyncAssertionType
- actualInput interface{}
+ asyncType AsyncAssertionType
+
+ actualIsFunc bool
+ actualValue interface{}
+ actualFunc func() ([]reflect.Value, error)
+
timeoutInterval time.Duration
pollingInterval time.Duration
- failWrapper *types.GomegaFailWrapper
offset int
+ g *Gomega
}
-func New(asyncType AsyncAssertionType, actualInput interface{}, failWrapper *types.GomegaFailWrapper, timeoutInterval time.Duration, pollingInterval time.Duration, offset int) *AsyncAssertion {
- actualType := reflect.TypeOf(actualInput)
- if actualType.Kind() == reflect.Func {
- if actualType.NumIn() != 0 || actualType.NumOut() == 0 {
- panic("Expected a function with no arguments and one or more return values.")
- }
- }
-
- return &AsyncAssertion{
+func NewAsyncAssertion(asyncType AsyncAssertionType, actualInput interface{}, g *Gomega, timeoutInterval time.Duration, pollingInterval time.Duration, offset int) *AsyncAssertion {
+ out := &AsyncAssertion{
asyncType: asyncType,
- actualInput: actualInput,
- failWrapper: failWrapper,
timeoutInterval: timeoutInterval,
pollingInterval: pollingInterval,
offset: offset,
+ g: g,
+ }
+
+ switch actualType := reflect.TypeOf(actualInput); {
+ case actualType.Kind() != reflect.Func:
+ out.actualValue = actualInput
+ case actualType.NumIn() == 0 && actualType.NumOut() > 0:
+ out.actualIsFunc = true
+ out.actualFunc = func() ([]reflect.Value, error) {
+ return reflect.ValueOf(actualInput).Call([]reflect.Value{}), nil
+ }
+ case actualType.NumIn() == 1 && actualType.In(0).Implements(reflect.TypeOf((*types.Gomega)(nil)).Elem()):
+ out.actualIsFunc = true
+ out.actualFunc = func() (values []reflect.Value, err error) {
+ var assertionFailure error
+ assertionCapturingGomega := NewGomega(g.DurationBundle).ConfigureWithFailHandler(func(message string, callerSkip ...int) {
+ skip := 0
+ if len(callerSkip) > 0 {
+ skip = callerSkip[0]
+ }
+ _, file, line, _ := runtime.Caller(skip + 1)
+ assertionFailure = fmt.Errorf("Assertion in callback at %s:%d failed:\n%s", file, line, message)
+ panic("stop execution")
+ })
+
+ defer func() {
+ if actualType.NumOut() == 0 {
+ if assertionFailure == nil {
+ values = []reflect.Value{reflect.Zero(reflect.TypeOf((*error)(nil)).Elem())}
+ } else {
+ values = []reflect.Value{reflect.ValueOf(assertionFailure)}
+ }
+ } else {
+ err = assertionFailure
+ }
+ if e := recover(); e != nil && assertionFailure == nil {
+ panic(e)
+ }
+ }()
+
+ values = reflect.ValueOf(actualInput).Call([]reflect.Value{reflect.ValueOf(assertionCapturingGomega)})
+ return
+ }
+ default:
+ msg := fmt.Sprintf("The function passed to Gomega's async assertions should either take no arguments and return values, or take a single Gomega interface that it can use to make assertions within the body of the function. When taking a Gomega interface the function can optionally return values or return nothing. The function you passed takes %d arguments and returns %d values.", actualType.NumIn(), actualType.NumOut())
+ g.Fail(msg, offset+4)
}
+
+ return out
}
func (assertion *AsyncAssertion) Should(matcher types.GomegaMatcher, optionalDescription ...interface{}) bool {
- assertion.failWrapper.TWithHelper.Helper()
+ assertion.g.THelper()
return assertion.match(matcher, true, optionalDescription...)
}
func (assertion *AsyncAssertion) ShouldNot(matcher types.GomegaMatcher, optionalDescription ...interface{}) bool {
- assertion.failWrapper.TWithHelper.Helper()
+ assertion.g.THelper()
return assertion.match(matcher, false, optionalDescription...)
}
@@ -68,38 +109,32 @@ func (assertion *AsyncAssertion) buildDescription(optionalDescription ...interfa
return fmt.Sprintf(optionalDescription[0].(string), optionalDescription[1:]...) + "\n"
}
-func (assertion *AsyncAssertion) actualInputIsAFunction() bool {
- actualType := reflect.TypeOf(assertion.actualInput)
- return actualType.Kind() == reflect.Func && actualType.NumIn() == 0 && actualType.NumOut() > 0
-}
-
func (assertion *AsyncAssertion) pollActual() (interface{}, error) {
- if assertion.actualInputIsAFunction() {
- values := reflect.ValueOf(assertion.actualInput).Call([]reflect.Value{})
-
- extras := []interface{}{}
- for _, value := range values[1:] {
- extras = append(extras, value.Interface())
- }
-
- success, message := vetExtras(extras)
-
- if !success {
- return nil, errors.New(message)
- }
+ if !assertion.actualIsFunc {
+ return assertion.actualValue, nil
+ }
- return values[0].Interface(), nil
+ values, err := assertion.actualFunc()
+ if err != nil {
+ return nil, err
+ }
+ extras := []interface{}{}
+ for _, value := range values[1:] {
+ extras = append(extras, value.Interface())
+ }
+ success, message := vetExtras(extras)
+ if !success {
+ return nil, errors.New(message)
}
- return assertion.actualInput, nil
+ return values[0].Interface(), nil
}
func (assertion *AsyncAssertion) matcherMayChange(matcher types.GomegaMatcher, value interface{}) bool {
- if assertion.actualInputIsAFunction() {
+ if assertion.actualIsFunc {
return true
}
-
- return oraclematcher.MatchMayChangeInTheFuture(matcher, value)
+ return types.MatchMayChangeInTheFuture(matcher, value)
}
func (assertion *AsyncAssertion) match(matcher types.GomegaMatcher, desiredMatch bool, optionalDescription ...interface{}) bool {
@@ -115,7 +150,7 @@ func (assertion *AsyncAssertion) match(matcher types.GomegaMatcher, desiredMatch
matches, err = matcher.Match(value)
}
- assertion.failWrapper.TWithHelper.Helper()
+ assertion.g.THelper()
fail := func(preamble string) {
errMsg := ""
@@ -129,9 +164,9 @@ func (assertion *AsyncAssertion) match(matcher types.GomegaMatcher, desiredMatch
message = matcher.NegatedFailureMessage(value)
}
}
- assertion.failWrapper.TWithHelper.Helper()
+ assertion.g.THelper()
description := assertion.buildDescription(optionalDescription...)
- assertion.failWrapper.Fail(fmt.Sprintf("%s after %.3fs.\n%s%s%s", preamble, time.Since(timer).Seconds(), description, message, errMsg), 3+assertion.offset)
+ assertion.g.Fail(fmt.Sprintf("%s after %.3fs.\n%s%s%s", preamble, time.Since(timer).Seconds(), description, message, errMsg), 3+assertion.offset)
}
if assertion.asyncType == AsyncAssertionTypeEventually {
@@ -183,16 +218,3 @@ func (assertion *AsyncAssertion) match(matcher types.GomegaMatcher, desiredMatch
return false
}
-
-func vetExtras(extras []interface{}) (bool, string) {
- for i, extra := range extras {
- if extra != nil {
- zeroValue := reflect.Zero(reflect.TypeOf(extra)).Interface()
- if !reflect.DeepEqual(zeroValue, extra) {
- message := fmt.Sprintf("Unexpected non-nil/non-zero extra argument at index %d:\n\t<%T>: %#v", i+1, extra, extra)
- return false, message
- }
- }
- }
- return true, ""
-}
diff --git a/vendor/github.com/onsi/gomega/internal/duration_bundle.go b/vendor/github.com/onsi/gomega/internal/duration_bundle.go
new file mode 100644
index 000000000..af8d989fa
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/internal/duration_bundle.go
@@ -0,0 +1,71 @@
+package internal
+
+import (
+ "fmt"
+ "os"
+ "reflect"
+ "time"
+)
+
+type DurationBundle struct {
+ EventuallyTimeout time.Duration
+ EventuallyPollingInterval time.Duration
+ ConsistentlyDuration time.Duration
+ ConsistentlyPollingInterval time.Duration
+}
+
+const (
+ EventuallyTimeoutEnvVarName = "GOMEGA_DEFAULT_EVENTUALLY_TIMEOUT"
+ EventuallyPollingIntervalEnvVarName = "GOMEGA_DEFAULT_EVENTUALLY_POLLING_INTERVAL"
+
+ ConsistentlyDurationEnvVarName = "GOMEGA_DEFAULT_CONSISTENTLY_DURATION"
+ ConsistentlyPollingIntervalEnvVarName = "GOMEGA_DEFAULT_CONSISTENTLY_POLLING_INTERVAL"
+)
+
+func FetchDefaultDurationBundle() DurationBundle {
+ return DurationBundle{
+ EventuallyTimeout: durationFromEnv(EventuallyTimeoutEnvVarName, time.Second),
+ EventuallyPollingInterval: durationFromEnv(EventuallyPollingIntervalEnvVarName, 10*time.Millisecond),
+
+ ConsistentlyDuration: durationFromEnv(ConsistentlyDurationEnvVarName, 100*time.Millisecond),
+ ConsistentlyPollingInterval: durationFromEnv(ConsistentlyPollingIntervalEnvVarName, 10*time.Millisecond),
+ }
+}
+
+func durationFromEnv(key string, defaultDuration time.Duration) time.Duration {
+ value := os.Getenv(key)
+ if value == "" {
+ return defaultDuration
+ }
+ duration, err := time.ParseDuration(value)
+ if err != nil {
+ panic(fmt.Sprintf("Expected a duration when using %s! Parse error %v", key, err))
+ }
+ return duration
+}
+
+func toDuration(input interface{}) time.Duration {
+ duration, ok := input.(time.Duration)
+ if ok {
+ return duration
+ }
+
+ value := reflect.ValueOf(input)
+ kind := reflect.TypeOf(input).Kind()
+
+ if reflect.Int <= kind && kind <= reflect.Int64 {
+ return time.Duration(value.Int()) * time.Second
+ } else if reflect.Uint <= kind && kind <= reflect.Uint64 {
+ return time.Duration(value.Uint()) * time.Second
+ } else if reflect.Float32 <= kind && kind <= reflect.Float64 {
+ return time.Duration(value.Float() * float64(time.Second))
+ } else if reflect.String == kind {
+ duration, err := time.ParseDuration(value.String())
+ if err != nil {
+ panic(fmt.Sprintf("%#v is not a valid parsable duration string.", input))
+ }
+ return duration
+ }
+
+ panic(fmt.Sprintf("%v is not a valid interval. Must be time.Duration, parsable duration string or a number.", input))
+}
diff --git a/vendor/github.com/onsi/gomega/internal/gomega.go b/vendor/github.com/onsi/gomega/internal/gomega.go
new file mode 100644
index 000000000..f5b5c6b7a
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/internal/gomega.go
@@ -0,0 +1,102 @@
+package internal
+
+import (
+ "time"
+
+ "github.com/onsi/gomega/types"
+)
+
+type Gomega struct {
+ Fail types.GomegaFailHandler
+ THelper func()
+ DurationBundle DurationBundle
+}
+
+func NewGomega(bundle DurationBundle) *Gomega {
+ return &Gomega{
+ Fail: nil,
+ THelper: nil,
+ DurationBundle: bundle,
+ }
+}
+
+func (g *Gomega) IsConfigured() bool {
+ return g.Fail != nil && g.THelper != nil
+}
+
+func (g *Gomega) ConfigureWithFailHandler(fail types.GomegaFailHandler) *Gomega {
+ g.Fail = fail
+ g.THelper = func() {}
+ return g
+}
+
+func (g *Gomega) ConfigureWithT(t types.GomegaTestingT) *Gomega {
+ g.Fail = func(message string, _ ...int) {
+ t.Helper()
+ t.Fatalf("\n%s", message)
+ }
+ g.THelper = t.Helper
+ return g
+}
+
+func (g *Gomega) Ω(atual interface{}, extra ...interface{}) types.Assertion {
+ return g.ExpectWithOffset(0, atual, extra...)
+}
+
+func (g *Gomega) Expect(atual interface{}, extra ...interface{}) types.Assertion {
+ return g.ExpectWithOffset(0, atual, extra...)
+}
+
+func (g *Gomega) ExpectWithOffset(offset int, actual interface{}, extra ...interface{}) types.Assertion {
+ return NewAssertion(actual, g, offset, extra...)
+}
+
+func (g *Gomega) Eventually(actual interface{}, intervals ...interface{}) types.AsyncAssertion {
+ return g.EventuallyWithOffset(0, actual, intervals...)
+}
+
+func (g *Gomega) EventuallyWithOffset(offset int, actual interface{}, intervals ...interface{}) types.AsyncAssertion {
+ timeoutInterval := g.DurationBundle.EventuallyTimeout
+ pollingInterval := g.DurationBundle.EventuallyPollingInterval
+ if len(intervals) > 0 {
+ timeoutInterval = toDuration(intervals[0])
+ }
+ if len(intervals) > 1 {
+ pollingInterval = toDuration(intervals[1])
+ }
+
+ return NewAsyncAssertion(AsyncAssertionTypeEventually, actual, g, timeoutInterval, pollingInterval, offset)
+}
+
+func (g *Gomega) Consistently(actual interface{}, intervals ...interface{}) types.AsyncAssertion {
+ return g.ConsistentlyWithOffset(0, actual, intervals...)
+}
+
+func (g *Gomega) ConsistentlyWithOffset(offset int, actual interface{}, intervals ...interface{}) types.AsyncAssertion {
+ timeoutInterval := g.DurationBundle.ConsistentlyDuration
+ pollingInterval := g.DurationBundle.ConsistentlyPollingInterval
+ if len(intervals) > 0 {
+ timeoutInterval = toDuration(intervals[0])
+ }
+ if len(intervals) > 1 {
+ pollingInterval = toDuration(intervals[1])
+ }
+
+ return NewAsyncAssertion(AsyncAssertionTypeConsistently, actual, g, timeoutInterval, pollingInterval, offset)
+}
+
+func (g *Gomega) SetDefaultEventuallyTimeout(t time.Duration) {
+ g.DurationBundle.EventuallyTimeout = t
+}
+
+func (g *Gomega) SetDefaultEventuallyPollingInterval(t time.Duration) {
+ g.DurationBundle.EventuallyPollingInterval = t
+}
+
+func (g *Gomega) SetDefaultConsistentlyDuration(t time.Duration) {
+ g.DurationBundle.ConsistentlyDuration = t
+}
+
+func (g *Gomega) SetDefaultConsistentlyPollingInterval(t time.Duration) {
+ g.DurationBundle.ConsistentlyPollingInterval = t
+}
diff --git a/vendor/github.com/onsi/gomega/internal/oraclematcher/oracle_matcher.go b/vendor/github.com/onsi/gomega/internal/oraclematcher/oracle_matcher.go
deleted file mode 100644
index 66cad88a1..000000000
--- a/vendor/github.com/onsi/gomega/internal/oraclematcher/oracle_matcher.go
+++ /dev/null
@@ -1,25 +0,0 @@
-package oraclematcher
-
-import "github.com/onsi/gomega/types"
-
-/*
-GomegaMatchers that also match the OracleMatcher interface can convey information about
-whether or not their result will change upon future attempts.
-
-This allows `Eventually` and `Consistently` to short circuit if success becomes impossible.
-
-For example, a process' exit code can never change. So, gexec's Exit matcher returns `true`
-for `MatchMayChangeInTheFuture` until the process exits, at which point it returns `false` forevermore.
-*/
-type OracleMatcher interface {
- MatchMayChangeInTheFuture(actual interface{}) bool
-}
-
-func MatchMayChangeInTheFuture(matcher types.GomegaMatcher, value interface{}) bool {
- oracleMatcher, ok := matcher.(OracleMatcher)
- if !ok {
- return true
- }
-
- return oracleMatcher.MatchMayChangeInTheFuture(value)
-}
diff --git a/vendor/github.com/onsi/gomega/internal/testingtsupport/testing_t_support.go b/vendor/github.com/onsi/gomega/internal/testingtsupport/testing_t_support.go
deleted file mode 100644
index bb27032f6..000000000
--- a/vendor/github.com/onsi/gomega/internal/testingtsupport/testing_t_support.go
+++ /dev/null
@@ -1,60 +0,0 @@
-package testingtsupport
-
-import (
- "regexp"
- "runtime/debug"
- "strings"
-
- "github.com/onsi/gomega/types"
-)
-
-var StackTracePruneRE = regexp.MustCompile(`\/gomega\/|\/ginkgo\/|\/pkg\/testing\/|\/pkg\/runtime\/`)
-
-type EmptyTWithHelper struct{}
-
-func (e EmptyTWithHelper) Helper() {}
-
-type gomegaTestingT interface {
- Fatalf(format string, args ...interface{})
-}
-
-func BuildTestingTGomegaFailWrapper(t gomegaTestingT) *types.GomegaFailWrapper {
- tWithHelper, hasHelper := t.(types.TWithHelper)
- if !hasHelper {
- tWithHelper = EmptyTWithHelper{}
- }
-
- fail := func(message string, callerSkip ...int) {
- if hasHelper {
- tWithHelper.Helper()
- t.Fatalf("\n%s", message)
- } else {
- skip := 2
- if len(callerSkip) > 0 {
- skip += callerSkip[0]
- }
- stackTrace := pruneStack(string(debug.Stack()), skip)
- t.Fatalf("\n%s\n%s\n", stackTrace, message)
- }
- }
-
- return &types.GomegaFailWrapper{
- Fail: fail,
- TWithHelper: tWithHelper,
- }
-}
-
-func pruneStack(fullStackTrace string, skip int) string {
- stack := strings.Split(fullStackTrace, "\n")[1:]
- if len(stack) > 2*skip {
- stack = stack[2*skip:]
- }
- prunedStack := []string{}
- for i := 0; i < len(stack)/2; i++ {
- if !StackTracePruneRE.Match([]byte(stack[i*2])) {
- prunedStack = append(prunedStack, stack[i*2])
- prunedStack = append(prunedStack, stack[i*2+1])
- }
- }
- return strings.Join(prunedStack, "\n")
-}
diff --git a/vendor/github.com/onsi/gomega/matchers.go b/vendor/github.com/onsi/gomega/matchers.go
index 16218d4c5..667160ade 100644
--- a/vendor/github.com/onsi/gomega/matchers.go
+++ b/vendor/github.com/onsi/gomega/matchers.go
@@ -474,3 +474,11 @@ func Not(matcher types.GomegaMatcher) types.GomegaMatcher {
func WithTransform(transform interface{}, matcher types.GomegaMatcher) types.GomegaMatcher {
return matchers.NewWithTransformMatcher(transform, matcher)
}
+
+//Satisfy matches the actual value against the `predicate` function.
+//The given predicate must be a function of one paramter that returns bool.
+// var isEven = func(i int) bool { return i%2 == 0 }
+// Expect(2).To(Satisfy(isEven))
+func Satisfy(predicate interface{}) types.GomegaMatcher {
+ return matchers.NewSatisfyMatcher(predicate)
+}
diff --git a/vendor/github.com/onsi/gomega/matchers/and.go b/vendor/github.com/onsi/gomega/matchers/and.go
index d83a29164..6bd826adc 100644
--- a/vendor/github.com/onsi/gomega/matchers/and.go
+++ b/vendor/github.com/onsi/gomega/matchers/and.go
@@ -4,7 +4,6 @@ import (
"fmt"
"github.com/onsi/gomega/format"
- "github.com/onsi/gomega/internal/oraclematcher"
"github.com/onsi/gomega/types"
)
@@ -52,12 +51,12 @@ func (m *AndMatcher) MatchMayChangeInTheFuture(actual interface{}) bool {
if m.firstFailedMatcher == nil {
// so all matchers succeeded.. Any one of them changing would change the result.
for _, matcher := range m.Matchers {
- if oraclematcher.MatchMayChangeInTheFuture(matcher, actual) {
+ if types.MatchMayChangeInTheFuture(matcher, actual) {
return true
}
}
return false // none of were going to change
}
// one of the matchers failed.. it must be able to change in order to affect the result
- return oraclematcher.MatchMayChangeInTheFuture(m.firstFailedMatcher, actual)
+ return types.MatchMayChangeInTheFuture(m.firstFailedMatcher, actual)
}
diff --git a/vendor/github.com/onsi/gomega/matchers/be_element_of_matcher.go b/vendor/github.com/onsi/gomega/matchers/be_element_of_matcher.go
index 1f9d7a8e6..9ee75a5d5 100644
--- a/vendor/github.com/onsi/gomega/matchers/be_element_of_matcher.go
+++ b/vendor/github.com/onsi/gomega/matchers/be_element_of_matcher.go
@@ -18,23 +18,9 @@ func (matcher *BeElementOfMatcher) Match(actual interface{}) (success bool, err
return false, fmt.Errorf("BeElement matcher expects actual to be typed")
}
- length := len(matcher.Elements)
- valueAt := func(i int) interface{} {
- return matcher.Elements[i]
- }
- // Special handling of a single element of type Array or Slice
- if length == 1 && isArrayOrSlice(valueAt(0)) {
- element := valueAt(0)
- value := reflect.ValueOf(element)
- length = value.Len()
- valueAt = func(i int) interface{} {
- return value.Index(i).Interface()
- }
- }
-
var lastError error
- for i := 0; i < length; i++ {
- matcher := &EqualMatcher{Expected: valueAt(i)}
+ for _, m := range flatten(matcher.Elements) {
+ matcher := &EqualMatcher{Expected: m}
success, err := matcher.Match(actual)
if err != nil {
lastError = err
@@ -49,9 +35,9 @@ func (matcher *BeElementOfMatcher) Match(actual interface{}) (success bool, err
}
func (matcher *BeElementOfMatcher) FailureMessage(actual interface{}) (message string) {
- return format.Message(actual, "to be an element of", matcher.Elements)
+ return format.Message(actual, "to be an element of", presentable(matcher.Elements))
}
func (matcher *BeElementOfMatcher) NegatedFailureMessage(actual interface{}) (message string) {
- return format.Message(actual, "not to be an element of", matcher.Elements)
+ return format.Message(actual, "not to be an element of", presentable(matcher.Elements))
}
diff --git a/vendor/github.com/onsi/gomega/matchers/be_numerically_matcher.go b/vendor/github.com/onsi/gomega/matchers/be_numerically_matcher.go
index f72591a1a..100735de3 100644
--- a/vendor/github.com/onsi/gomega/matchers/be_numerically_matcher.go
+++ b/vendor/github.com/onsi/gomega/matchers/be_numerically_matcher.go
@@ -45,7 +45,7 @@ func (matcher *BeNumericallyMatcher) Match(actual interface{}) (success bool, er
return false, fmt.Errorf("Expected a number. Got:\n%s", format.Object(matcher.CompareTo[0], 1))
}
if len(matcher.CompareTo) == 2 && !isNumber(matcher.CompareTo[1]) {
- return false, fmt.Errorf("Expected a number. Got:\n%s", format.Object(matcher.CompareTo[0], 1))
+ return false, fmt.Errorf("Expected a number. Got:\n%s", format.Object(matcher.CompareTo[1], 1))
}
switch matcher.Comparator {
diff --git a/vendor/github.com/onsi/gomega/matchers/consist_of.go b/vendor/github.com/onsi/gomega/matchers/consist_of.go
index e453b22d1..e8ef0dee1 100644
--- a/vendor/github.com/onsi/gomega/matchers/consist_of.go
+++ b/vendor/github.com/onsi/gomega/matchers/consist_of.go
@@ -57,17 +57,21 @@ func equalMatchersToElements(matchers []interface{}) (elements []interface{}) {
return
}
-func matchers(expectedElems []interface{}) (matchers []interface{}) {
- elems := expectedElems
- if len(expectedElems) == 1 && isArrayOrSlice(expectedElems[0]) {
- elems = []interface{}{}
- value := reflect.ValueOf(expectedElems[0])
- for i := 0; i < value.Len(); i++ {
- elems = append(elems, value.Index(i).Interface())
- }
+func flatten(elems []interface{}) []interface{} {
+ if len(elems) != 1 || !isArrayOrSlice(elems[0]) {
+ return elems
}
- for _, e := range elems {
+ value := reflect.ValueOf(elems[0])
+ flattened := make([]interface{}, value.Len())
+ for i := 0; i < value.Len(); i++ {
+ flattened[i] = value.Index(i).Interface()
+ }
+ return flattened
+}
+
+func matchers(expectedElems []interface{}) (matchers []interface{}) {
+ for _, e := range flatten(expectedElems) {
matcher, isMatcher := e.(omegaMatcher)
if !isMatcher {
matcher = &EqualMatcher{Expected: e}
@@ -77,6 +81,29 @@ func matchers(expectedElems []interface{}) (matchers []interface{}) {
return
}
+func presentable(elems []interface{}) interface{} {
+ elems = flatten(elems)
+
+ if len(elems) == 0 {
+ return []interface{}{}
+ }
+
+ sv := reflect.ValueOf(elems)
+ tt := sv.Index(0).Elem().Type()
+ for i := 1; i < sv.Len(); i++ {
+ if sv.Index(i).Elem().Type() != tt {
+ return elems
+ }
+ }
+
+ ss := reflect.MakeSlice(reflect.SliceOf(tt), sv.Len(), sv.Len())
+ for i := 0; i < sv.Len(); i++ {
+ ss.Index(i).Set(sv.Index(i).Elem())
+ }
+
+ return ss.Interface()
+}
+
func valuesOf(actual interface{}) []interface{} {
value := reflect.ValueOf(actual)
values := []interface{}{}
@@ -95,11 +122,11 @@ func valuesOf(actual interface{}) []interface{} {
}
func (matcher *ConsistOfMatcher) FailureMessage(actual interface{}) (message string) {
- message = format.Message(actual, "to consist of", matcher.Elements)
+ message = format.Message(actual, "to consist of", presentable(matcher.Elements))
message = appendMissingElements(message, matcher.missingElements)
if len(matcher.extraElements) > 0 {
message = fmt.Sprintf("%s\nthe extra elements were\n%s", message,
- format.Object(matcher.extraElements, 1))
+ format.Object(presentable(matcher.extraElements), 1))
}
return
}
@@ -109,9 +136,9 @@ func appendMissingElements(message string, missingElements []interface{}) string
return message
}
return fmt.Sprintf("%s\nthe missing elements were\n%s", message,
- format.Object(missingElements, 1))
+ format.Object(presentable(missingElements), 1))
}
func (matcher *ConsistOfMatcher) NegatedFailureMessage(actual interface{}) (message string) {
- return format.Message(actual, "not to consist of", matcher.Elements)
+ return format.Message(actual, "not to consist of", presentable(matcher.Elements))
}
diff --git a/vendor/github.com/onsi/gomega/matchers/contain_elements_matcher.go b/vendor/github.com/onsi/gomega/matchers/contain_elements_matcher.go
index 19a9e78f8..946cd8bea 100644
--- a/vendor/github.com/onsi/gomega/matchers/contain_elements_matcher.go
+++ b/vendor/github.com/onsi/gomega/matchers/contain_elements_matcher.go
@@ -35,10 +35,10 @@ func (matcher *ContainElementsMatcher) Match(actual interface{}) (success bool,
}
func (matcher *ContainElementsMatcher) FailureMessage(actual interface{}) (message string) {
- message = format.Message(actual, "to contain elements", matcher.Elements)
+ message = format.Message(actual, "to contain elements", presentable(matcher.Elements))
return appendMissingElements(message, matcher.missingElements)
}
func (matcher *ContainElementsMatcher) NegatedFailureMessage(actual interface{}) (message string) {
- return format.Message(actual, "not to contain elements", matcher.Elements)
+ return format.Message(actual, "not to contain elements", presentable(matcher.Elements))
}
diff --git a/vendor/github.com/onsi/gomega/matchers/match_error_matcher.go b/vendor/github.com/onsi/gomega/matchers/match_error_matcher.go
index 4e09239ff..c8993a86d 100644
--- a/vendor/github.com/onsi/gomega/matchers/match_error_matcher.go
+++ b/vendor/github.com/onsi/gomega/matchers/match_error_matcher.go
@@ -1,11 +1,11 @@
package matchers
import (
+ "errors"
"fmt"
"reflect"
"github.com/onsi/gomega/format"
- "golang.org/x/xerrors"
)
type MatchErrorMatcher struct {
@@ -25,7 +25,7 @@ func (matcher *MatchErrorMatcher) Match(actual interface{}) (success bool, err e
expected := matcher.Expected
if isError(expected) {
- return reflect.DeepEqual(actualErr, expected) || xerrors.Is(actualErr, expected.(error)), nil
+ return reflect.DeepEqual(actualErr, expected) || errors.Is(actualErr, expected.(error)), nil
}
if isString(expected) {
diff --git a/vendor/github.com/onsi/gomega/matchers/not.go b/vendor/github.com/onsi/gomega/matchers/not.go
index 2c91670bd..78b71910d 100644
--- a/vendor/github.com/onsi/gomega/matchers/not.go
+++ b/vendor/github.com/onsi/gomega/matchers/not.go
@@ -1,7 +1,6 @@
package matchers
import (
- "github.com/onsi/gomega/internal/oraclematcher"
"github.com/onsi/gomega/types"
)
@@ -26,5 +25,5 @@ func (m *NotMatcher) NegatedFailureMessage(actual interface{}) (message string)
}
func (m *NotMatcher) MatchMayChangeInTheFuture(actual interface{}) bool {
- return oraclematcher.MatchMayChangeInTheFuture(m.Matcher, actual) // just return m.Matcher's value
+ return types.MatchMayChangeInTheFuture(m.Matcher, actual) // just return m.Matcher's value
}
diff --git a/vendor/github.com/onsi/gomega/matchers/or.go b/vendor/github.com/onsi/gomega/matchers/or.go
index 3bf799800..841ae26ab 100644
--- a/vendor/github.com/onsi/gomega/matchers/or.go
+++ b/vendor/github.com/onsi/gomega/matchers/or.go
@@ -4,7 +4,6 @@ import (
"fmt"
"github.com/onsi/gomega/format"
- "github.com/onsi/gomega/internal/oraclematcher"
"github.com/onsi/gomega/types"
)
@@ -54,11 +53,11 @@ func (m *OrMatcher) MatchMayChangeInTheFuture(actual interface{}) bool {
if m.firstSuccessfulMatcher != nil {
// one of the matchers succeeded.. it must be able to change in order to affect the result
- return oraclematcher.MatchMayChangeInTheFuture(m.firstSuccessfulMatcher, actual)
+ return types.MatchMayChangeInTheFuture(m.firstSuccessfulMatcher, actual)
} else {
// so all matchers failed.. Any one of them changing would change the result.
for _, matcher := range m.Matchers {
- if oraclematcher.MatchMayChangeInTheFuture(matcher, actual) {
+ if types.MatchMayChangeInTheFuture(matcher, actual) {
return true
}
}
diff --git a/vendor/github.com/onsi/gomega/matchers/satisfy_matcher.go b/vendor/github.com/onsi/gomega/matchers/satisfy_matcher.go
new file mode 100644
index 000000000..ec68fe8b6
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/matchers/satisfy_matcher.go
@@ -0,0 +1,66 @@
+package matchers
+
+import (
+ "fmt"
+ "reflect"
+
+ "github.com/onsi/gomega/format"
+)
+
+type SatisfyMatcher struct {
+ Predicate interface{}
+
+ // cached type
+ predicateArgType reflect.Type
+}
+
+func NewSatisfyMatcher(predicate interface{}) *SatisfyMatcher {
+ if predicate == nil {
+ panic("predicate cannot be nil")
+ }
+ predicateType := reflect.TypeOf(predicate)
+ if predicateType.Kind() != reflect.Func {
+ panic("predicate must be a function")
+ }
+ if predicateType.NumIn() != 1 {
+ panic("predicate must have 1 argument")
+ }
+ if predicateType.NumOut() != 1 || predicateType.Out(0).Kind() != reflect.Bool {
+ panic("predicate must return bool")
+ }
+
+ return &SatisfyMatcher{
+ Predicate: predicate,
+ predicateArgType: predicateType.In(0),
+ }
+}
+
+func (m *SatisfyMatcher) Match(actual interface{}) (success bool, err error) {
+ // prepare a parameter to pass to the predicate
+ var param reflect.Value
+ if actual != nil && reflect.TypeOf(actual).AssignableTo(m.predicateArgType) {
+ // The dynamic type of actual is compatible with the predicate argument.
+ param = reflect.ValueOf(actual)
+
+ } else if actual == nil && m.predicateArgType.Kind() == reflect.Interface {
+ // The dynamic type of actual is unknown, so there's no way to make its
+ // reflect.Value. Create a nil of the predicate argument, which is known.
+ param = reflect.Zero(m.predicateArgType)
+
+ } else {
+ return false, fmt.Errorf("predicate expects '%s' but we have '%T'", m.predicateArgType, actual)
+ }
+
+ // call the predicate with `actual`
+ fn := reflect.ValueOf(m.Predicate)
+ result := fn.Call([]reflect.Value{param})
+ return result[0].Bool(), nil
+}
+
+func (m *SatisfyMatcher) FailureMessage(actual interface{}) (message string) {
+ return format.Message(actual, "to satisfy predicate", m.Predicate)
+}
+
+func (m *SatisfyMatcher) NegatedFailureMessage(actual interface{}) (message string) {
+ return format.Message(actual, "to not satisfy predicate", m.Predicate)
+}
diff --git a/vendor/github.com/onsi/gomega/matchers/with_transform.go b/vendor/github.com/onsi/gomega/matchers/with_transform.go
index 8e58d8a0f..8a06bd384 100644
--- a/vendor/github.com/onsi/gomega/matchers/with_transform.go
+++ b/vendor/github.com/onsi/gomega/matchers/with_transform.go
@@ -4,7 +4,6 @@ import (
"fmt"
"reflect"
- "github.com/onsi/gomega/internal/oraclematcher"
"github.com/onsi/gomega/types"
)
@@ -40,15 +39,24 @@ func NewWithTransformMatcher(transform interface{}, matcher types.GomegaMatcher)
}
func (m *WithTransformMatcher) Match(actual interface{}) (bool, error) {
- // return error if actual's type is incompatible with Transform function's argument type
- actualType := reflect.TypeOf(actual)
- if !actualType.AssignableTo(m.transformArgType) {
- return false, fmt.Errorf("Transform function expects '%s' but we have '%s'", m.transformArgType, actualType)
+ // prepare a parameter to pass to the Transform function
+ var param reflect.Value
+ if actual != nil && reflect.TypeOf(actual).AssignableTo(m.transformArgType) {
+ // The dynamic type of actual is compatible with the transform argument.
+ param = reflect.ValueOf(actual)
+
+ } else if actual == nil && m.transformArgType.Kind() == reflect.Interface {
+ // The dynamic type of actual is unknown, so there's no way to make its
+ // reflect.Value. Create a nil of the transform argument, which is known.
+ param = reflect.Zero(m.transformArgType)
+
+ } else {
+ return false, fmt.Errorf("Transform function expects '%s' but we have '%T'", m.transformArgType, actual)
}
// call the Transform function with `actual`
fn := reflect.ValueOf(m.Transform)
- result := fn.Call([]reflect.Value{reflect.ValueOf(actual)})
+ result := fn.Call([]reflect.Value{param})
m.transformedValue = result[0].Interface() // expect exactly one value
return m.Matcher.Match(m.transformedValue)
@@ -68,5 +76,5 @@ func (m *WithTransformMatcher) MatchMayChangeInTheFuture(_ interface{}) bool {
// Querying the next matcher is fine if the transformer always will return the same value.
// But if the transformer is non-deterministic and returns a different value each time, then there
// is no point in querying the next matcher, since it can only comment on the last transformed value.
- return oraclematcher.MatchMayChangeInTheFuture(m.Matcher, m.transformedValue)
+ return types.MatchMayChangeInTheFuture(m.Matcher, m.transformedValue)
}
diff --git a/vendor/github.com/onsi/gomega/types/types.go b/vendor/github.com/onsi/gomega/types/types.go
index ac59a3a5a..c75fcb3cc 100644
--- a/vendor/github.com/onsi/gomega/types/types.go
+++ b/vendor/github.com/onsi/gomega/types/types.go
@@ -1,21 +1,35 @@
package types
-type TWithHelper interface {
- Helper()
-}
+import (
+ "time"
+)
type GomegaFailHandler func(message string, callerSkip ...int)
-type GomegaFailWrapper struct {
- Fail GomegaFailHandler
- TWithHelper TWithHelper
-}
-
//A simple *testing.T interface wrapper
type GomegaTestingT interface {
+ Helper()
Fatalf(format string, args ...interface{})
}
+// Gomega represents an object that can perform synchronous and assynchronous assertions with Gomega matchers
+type Gomega interface {
+ Ω(actual interface{}, extra ...interface{}) Assertion
+ Expect(actual interface{}, extra ...interface{}) Assertion
+ ExpectWithOffset(offset int, actual interface{}, extra ...interface{}) Assertion
+
+ Eventually(actual interface{}, intervals ...interface{}) AsyncAssertion
+ EventuallyWithOffset(offset int, actual interface{}, intervals ...interface{}) AsyncAssertion
+
+ Consistently(actual interface{}, intervals ...interface{}) AsyncAssertion
+ ConsistentlyWithOffset(offset int, actual interface{}, intervals ...interface{}) AsyncAssertion
+
+ SetDefaultEventuallyTimeout(time.Duration)
+ SetDefaultEventuallyPollingInterval(time.Duration)
+ SetDefaultConsistentlyDuration(time.Duration)
+ SetDefaultConsistentlyPollingInterval(time.Duration)
+}
+
//All Gomega matchers must implement the GomegaMatcher interface
//
//For details on writing custom matchers, check out: http://onsi.github.io/gomega/#adding-your-own-matchers
@@ -24,3 +38,42 @@ type GomegaMatcher interface {
FailureMessage(actual interface{}) (message string)
NegatedFailureMessage(actual interface{}) (message string)
}
+
+/*
+GomegaMatchers that also match the OracleMatcher interface can convey information about
+whether or not their result will change upon future attempts.
+
+This allows `Eventually` and `Consistently` to short circuit if success becomes impossible.
+
+For example, a process' exit code can never change. So, gexec's Exit matcher returns `true`
+for `MatchMayChangeInTheFuture` until the process exits, at which point it returns `false` forevermore.
+*/
+type OracleMatcher interface {
+ MatchMayChangeInTheFuture(actual interface{}) bool
+}
+
+func MatchMayChangeInTheFuture(matcher GomegaMatcher, value interface{}) bool {
+ oracleMatcher, ok := matcher.(OracleMatcher)
+ if !ok {
+ return true
+ }
+
+ return oracleMatcher.MatchMayChangeInTheFuture(value)
+}
+
+// AsyncAssertions are returned by Eventually and Consistently and enable matchers to be polled repeatedly to ensure
+// they are eventually satisfied
+type AsyncAssertion interface {
+ Should(matcher GomegaMatcher, optionalDescription ...interface{}) bool
+ ShouldNot(matcher GomegaMatcher, optionalDescription ...interface{}) bool
+}
+
+// Assertions are returned by Ω and Expect and enable assertions against Gomega matchers
+type Assertion interface {
+ Should(matcher GomegaMatcher, optionalDescription ...interface{}) bool
+ ShouldNot(matcher GomegaMatcher, optionalDescription ...interface{}) bool
+
+ To(matcher GomegaMatcher, optionalDescription ...interface{}) bool
+ ToNot(matcher GomegaMatcher, optionalDescription ...interface{}) bool
+ NotTo(matcher GomegaMatcher, optionalDescription ...interface{}) bool
+}
diff --git a/vendor/github.com/prometheus/client_golang/prometheus/collectors/collectors.go b/vendor/github.com/prometheus/client_golang/prometheus/collectors/collectors.go
new file mode 100644
index 000000000..c4d0f5c35
--- /dev/null
+++ b/vendor/github.com/prometheus/client_golang/prometheus/collectors/collectors.go
@@ -0,0 +1,16 @@
+// Copyright 2021 The Prometheus Authors
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Package collectors provides implementations of prometheus.Collector to
+// conveniently collect process and Go-related metrics.
+package collectors
diff --git a/vendor/github.com/prometheus/client_golang/prometheus/collectors/dbstats_collector.go b/vendor/github.com/prometheus/client_golang/prometheus/collectors/dbstats_collector.go
new file mode 100644
index 000000000..e09f149d7
--- /dev/null
+++ b/vendor/github.com/prometheus/client_golang/prometheus/collectors/dbstats_collector.go
@@ -0,0 +1,119 @@
+// Copyright 2021 The Prometheus Authors
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package collectors
+
+import (
+ "database/sql"
+
+ "github.com/prometheus/client_golang/prometheus"
+)
+
+type dbStatsCollector struct {
+ db *sql.DB
+
+ maxOpenConnections *prometheus.Desc
+
+ openConnections *prometheus.Desc
+ inUseConnections *prometheus.Desc
+ idleConnections *prometheus.Desc
+
+ waitCount *prometheus.Desc
+ waitDuration *prometheus.Desc
+ maxIdleClosed *prometheus.Desc
+ maxIdleTimeClosed *prometheus.Desc
+ maxLifetimeClosed *prometheus.Desc
+}
+
+// NewDBStatsCollector returns a collector that exports metrics about the given *sql.DB.
+// See https://golang.org/pkg/database/sql/#DBStats for more information on stats.
+func NewDBStatsCollector(db *sql.DB, dbName string) prometheus.Collector {
+ fqName := func(name string) string {
+ return "go_sql_" + name
+ }
+ return &dbStatsCollector{
+ db: db,
+ maxOpenConnections: prometheus.NewDesc(
+ fqName("max_open_connections"),
+ "Maximum number of open connections to the database.",
+ nil, prometheus.Labels{"db_name": dbName},
+ ),
+ openConnections: prometheus.NewDesc(
+ fqName("open_connections"),
+ "The number of established connections both in use and idle.",
+ nil, prometheus.Labels{"db_name": dbName},
+ ),
+ inUseConnections: prometheus.NewDesc(
+ fqName("in_use_connections"),
+ "The number of connections currently in use.",
+ nil, prometheus.Labels{"db_name": dbName},
+ ),
+ idleConnections: prometheus.NewDesc(
+ fqName("idle_connections"),
+ "The number of idle connections.",
+ nil, prometheus.Labels{"db_name": dbName},
+ ),
+ waitCount: prometheus.NewDesc(
+ fqName("wait_count_total"),
+ "The total number of connections waited for.",
+ nil, prometheus.Labels{"db_name": dbName},
+ ),
+ waitDuration: prometheus.NewDesc(
+ fqName("wait_duration_seconds_total"),
+ "The total time blocked waiting for a new connection.",
+ nil, prometheus.Labels{"db_name": dbName},
+ ),
+ maxIdleClosed: prometheus.NewDesc(
+ fqName("max_idle_closed_total"),
+ "The total number of connections closed due to SetMaxIdleConns.",
+ nil, prometheus.Labels{"db_name": dbName},
+ ),
+ maxIdleTimeClosed: prometheus.NewDesc(
+ fqName("max_idle_time_closed_total"),
+ "The total number of connections closed due to SetConnMaxIdleTime.",
+ nil, prometheus.Labels{"db_name": dbName},
+ ),
+ maxLifetimeClosed: prometheus.NewDesc(
+ fqName("max_lifetime_closed_total"),
+ "The total number of connections closed due to SetConnMaxLifetime.",
+ nil, prometheus.Labels{"db_name": dbName},
+ ),
+ }
+}
+
+// Describe implements Collector.
+func (c *dbStatsCollector) Describe(ch chan<- *prometheus.Desc) {
+ ch <- c.maxOpenConnections
+ ch <- c.openConnections
+ ch <- c.inUseConnections
+ ch <- c.idleConnections
+ ch <- c.waitCount
+ ch <- c.waitDuration
+ ch <- c.maxIdleClosed
+ ch <- c.maxLifetimeClosed
+ c.describeNewInGo115(ch)
+}
+
+// Collect implements Collector.
+func (c *dbStatsCollector) Collect(ch chan<- prometheus.Metric) {
+ stats := c.db.Stats()
+ ch <- prometheus.MustNewConstMetric(c.maxOpenConnections, prometheus.GaugeValue, float64(stats.MaxOpenConnections))
+ ch <- prometheus.MustNewConstMetric(c.openConnections, prometheus.GaugeValue, float64(stats.OpenConnections))
+ ch <- prometheus.MustNewConstMetric(c.inUseConnections, prometheus.GaugeValue, float64(stats.InUse))
+ ch <- prometheus.MustNewConstMetric(c.idleConnections, prometheus.GaugeValue, float64(stats.Idle))
+ ch <- prometheus.MustNewConstMetric(c.waitCount, prometheus.CounterValue, float64(stats.WaitCount))
+ ch <- prometheus.MustNewConstMetric(c.waitDuration, prometheus.CounterValue, stats.WaitDuration.Seconds())
+ ch <- prometheus.MustNewConstMetric(c.maxIdleClosed, prometheus.CounterValue, float64(stats.MaxIdleClosed))
+ ch <- prometheus.MustNewConstMetric(c.maxLifetimeClosed, prometheus.CounterValue, float64(stats.MaxLifetimeClosed))
+ c.collectNewInGo115(ch, stats)
+}
diff --git a/vendor/github.com/prometheus/client_golang/prometheus/collectors/dbstats_collector_go115.go b/vendor/github.com/prometheus/client_golang/prometheus/collectors/dbstats_collector_go115.go
new file mode 100644
index 000000000..a6e6268ce
--- /dev/null
+++ b/vendor/github.com/prometheus/client_golang/prometheus/collectors/dbstats_collector_go115.go
@@ -0,0 +1,30 @@
+// Copyright 2021 The Prometheus Authors
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// +build go1.15
+
+package collectors
+
+import (
+ "database/sql"
+
+ "github.com/prometheus/client_golang/prometheus"
+)
+
+func (c *dbStatsCollector) describeNewInGo115(ch chan<- *prometheus.Desc) {
+ ch <- c.maxIdleTimeClosed
+}
+
+func (c *dbStatsCollector) collectNewInGo115(ch chan<- prometheus.Metric, stats sql.DBStats) {
+ ch <- prometheus.MustNewConstMetric(c.maxIdleTimeClosed, prometheus.CounterValue, float64(stats.MaxIdleTimeClosed))
+}
diff --git a/vendor/github.com/prometheus/client_golang/prometheus/collectors/dbstats_collector_pre_go115.go b/vendor/github.com/prometheus/client_golang/prometheus/collectors/dbstats_collector_pre_go115.go
new file mode 100644
index 000000000..0568affe2
--- /dev/null
+++ b/vendor/github.com/prometheus/client_golang/prometheus/collectors/dbstats_collector_pre_go115.go
@@ -0,0 +1,26 @@
+// Copyright 2021 The Prometheus Authors
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// +build !go1.15
+
+package collectors
+
+import (
+ "database/sql"
+
+ "github.com/prometheus/client_golang/prometheus"
+)
+
+func (c *dbStatsCollector) describeNewInGo115(ch chan<- *prometheus.Desc) {}
+
+func (c *dbStatsCollector) collectNewInGo115(ch chan<- prometheus.Metric, stats sql.DBStats) {}
diff --git a/vendor/github.com/prometheus/client_golang/prometheus/collectors/expvar_collector.go b/vendor/github.com/prometheus/client_golang/prometheus/collectors/expvar_collector.go
new file mode 100644
index 000000000..3aa8d0590
--- /dev/null
+++ b/vendor/github.com/prometheus/client_golang/prometheus/collectors/expvar_collector.go
@@ -0,0 +1,57 @@
+// Copyright 2021 The Prometheus Authors
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package collectors
+
+import "github.com/prometheus/client_golang/prometheus"
+
+// NewExpvarCollector returns a newly allocated expvar Collector.
+//
+// An expvar Collector collects metrics from the expvar interface. It provides a
+// quick way to expose numeric values that are already exported via expvar as
+// Prometheus metrics. Note that the data models of expvar and Prometheus are
+// fundamentally different, and that the expvar Collector is inherently slower
+// than native Prometheus metrics. Thus, the expvar Collector is probably great
+// for experiments and prototying, but you should seriously consider a more
+// direct implementation of Prometheus metrics for monitoring production
+// systems.
+//
+// The exports map has the following meaning:
+//
+// The keys in the map correspond to expvar keys, i.e. for every expvar key you
+// want to export as Prometheus metric, you need an entry in the exports
+// map. The descriptor mapped to each key describes how to export the expvar
+// value. It defines the name and the help string of the Prometheus metric
+// proxying the expvar value. The type will always be Untyped.
+//
+// For descriptors without variable labels, the expvar value must be a number or
+// a bool. The number is then directly exported as the Prometheus sample
+// value. (For a bool, 'false' translates to 0 and 'true' to 1). Expvar values
+// that are not numbers or bools are silently ignored.
+//
+// If the descriptor has one variable label, the expvar value must be an expvar
+// map. The keys in the expvar map become the various values of the one
+// Prometheus label. The values in the expvar map must be numbers or bools again
+// as above.
+//
+// For descriptors with more than one variable label, the expvar must be a
+// nested expvar map, i.e. where the values of the topmost map are maps again
+// etc. until a depth is reached that corresponds to the number of labels. The
+// leaves of that structure must be numbers or bools as above to serve as the
+// sample values.
+//
+// Anything that does not fit into the scheme above is silently ignored.
+func NewExpvarCollector(exports map[string]*prometheus.Desc) prometheus.Collector {
+ //nolint:staticcheck // Ignore SA1019 until v2.
+ return prometheus.NewExpvarCollector(exports)
+}
diff --git a/vendor/github.com/prometheus/client_golang/prometheus/collectors/go_collector.go b/vendor/github.com/prometheus/client_golang/prometheus/collectors/go_collector.go
new file mode 100644
index 000000000..edaa4e50b
--- /dev/null
+++ b/vendor/github.com/prometheus/client_golang/prometheus/collectors/go_collector.go
@@ -0,0 +1,69 @@
+// Copyright 2021 The Prometheus Authors
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package collectors
+
+import "github.com/prometheus/client_golang/prometheus"
+
+// NewGoCollector returns a collector that exports metrics about the current Go
+// process. This includes memory stats. To collect those, runtime.ReadMemStats
+// is called. This requires to “stop the world”, which usually only happens for
+// garbage collection (GC). Take the following implications into account when
+// deciding whether to use the Go collector:
+//
+// 1. The performance impact of stopping the world is the more relevant the more
+// frequently metrics are collected. However, with Go1.9 or later the
+// stop-the-world time per metrics collection is very short (~25µs) so that the
+// performance impact will only matter in rare cases. However, with older Go
+// versions, the stop-the-world duration depends on the heap size and can be
+// quite significant (~1.7 ms/GiB as per
+// https://go-review.googlesource.com/c/go/+/34937).
+//
+// 2. During an ongoing GC, nothing else can stop the world. Therefore, if the
+// metrics collection happens to coincide with GC, it will only complete after
+// GC has finished. Usually, GC is fast enough to not cause problems. However,
+// with a very large heap, GC might take multiple seconds, which is enough to
+// cause scrape timeouts in common setups. To avoid this problem, the Go
+// collector will use the memstats from a previous collection if
+// runtime.ReadMemStats takes more than 1s. However, if there are no previously
+// collected memstats, or their collection is more than 5m ago, the collection
+// will block until runtime.ReadMemStats succeeds.
+//
+// NOTE: The problem is solved in Go 1.15, see
+// https://github.com/golang/go/issues/19812 for the related Go issue.
+func NewGoCollector() prometheus.Collector {
+ //nolint:staticcheck // Ignore SA1019 until v2.
+ return prometheus.NewGoCollector()
+}
+
+// NewBuildInfoCollector returns a collector collecting a single metric
+// "go_build_info" with the constant value 1 and three labels "path", "version",
+// and "checksum". Their label values contain the main module path, version, and
+// checksum, respectively. The labels will only have meaningful values if the
+// binary is built with Go module support and from source code retrieved from
+// the source repository (rather than the local file system). This is usually
+// accomplished by building from outside of GOPATH, specifying the full address
+// of the main package, e.g. "GO111MODULE=on go run
+// github.com/prometheus/client_golang/examples/random". If built without Go
+// module support, all label values will be "unknown". If built with Go module
+// support but using the source code from the local file system, the "path" will
+// be set appropriately, but "checksum" will be empty and "version" will be
+// "(devel)".
+//
+// This collector uses only the build information for the main module. See
+// https://github.com/povilasv/prommod for an example of a collector for the
+// module dependencies.
+func NewBuildInfoCollector() prometheus.Collector {
+ //nolint:staticcheck // Ignore SA1019 until v2.
+ return prometheus.NewBuildInfoCollector()
+}
diff --git a/vendor/github.com/prometheus/client_golang/prometheus/collectors/process_collector.go b/vendor/github.com/prometheus/client_golang/prometheus/collectors/process_collector.go
new file mode 100644
index 000000000..24558f50a
--- /dev/null
+++ b/vendor/github.com/prometheus/client_golang/prometheus/collectors/process_collector.go
@@ -0,0 +1,56 @@
+// Copyright 2021 The Prometheus Authors
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package collectors
+
+import "github.com/prometheus/client_golang/prometheus"
+
+// ProcessCollectorOpts defines the behavior of a process metrics collector
+// created with NewProcessCollector.
+type ProcessCollectorOpts struct {
+ // PidFn returns the PID of the process the collector collects metrics
+ // for. It is called upon each collection. By default, the PID of the
+ // current process is used, as determined on construction time by
+ // calling os.Getpid().
+ PidFn func() (int, error)
+ // If non-empty, each of the collected metrics is prefixed by the
+ // provided string and an underscore ("_").
+ Namespace string
+ // If true, any error encountered during collection is reported as an
+ // invalid metric (see NewInvalidMetric). Otherwise, errors are ignored
+ // and the collected metrics will be incomplete. (Possibly, no metrics
+ // will be collected at all.) While that's usually not desired, it is
+ // appropriate for the common "mix-in" of process metrics, where process
+ // metrics are nice to have, but failing to collect them should not
+ // disrupt the collection of the remaining metrics.
+ ReportErrors bool
+}
+
+// NewProcessCollector returns a collector which exports the current state of
+// process metrics including CPU, memory and file descriptor usage as well as
+// the process start time. The detailed behavior is defined by the provided
+// ProcessCollectorOpts. The zero value of ProcessCollectorOpts creates a
+// collector for the current process with an empty namespace string and no error
+// reporting.
+//
+// The collector only works on operating systems with a Linux-style proc
+// filesystem and on Microsoft Windows. On other operating systems, it will not
+// collect any metrics.
+func NewProcessCollector(opts ProcessCollectorOpts) prometheus.Collector {
+ //nolint:staticcheck // Ignore SA1019 until v2.
+ return prometheus.NewProcessCollector(prometheus.ProcessCollectorOpts{
+ PidFn: opts.PidFn,
+ Namespace: opts.Namespace,
+ ReportErrors: opts.ReportErrors,
+ })
+}
diff --git a/vendor/go.uber.org/zap/CHANGELOG.md b/vendor/go.uber.org/zap/CHANGELOG.md
index 3b99bf0ac..fdfef8808 100644
--- a/vendor/go.uber.org/zap/CHANGELOG.md
+++ b/vendor/go.uber.org/zap/CHANGELOG.md
@@ -1,5 +1,49 @@
# Changelog
+## 1.19.0 (9 Aug 2021)
+
+Enhancements:
+* [#975][]: Avoid panicking in Sampler core if the level is out of bounds.
+* [#984][]: Reduce the size of BufferedWriteSyncer by aligning the fields
+ better.
+
+[#975]: https://github.com/uber-go/zap/pull/975
+[#984]: https://github.com/uber-go/zap/pull/984
+
+Thanks to @lancoLiu and @thockin for their contributions to this release.
+
+## 1.18.1 (28 Jun 2021)
+
+Bugfixes:
+* [#974][]: Fix nil dereference in logger constructed by `zap.NewNop`.
+
+[#974]: https://github.com/uber-go/zap/pull/974
+
+## 1.18.0 (28 Jun 2021)
+
+Enhancements:
+* [#961][]: Add `zapcore.BufferedWriteSyncer`, a new `WriteSyncer` that buffers
+ messages in-memory and flushes them periodically.
+* [#971][]: Add `zapio.Writer` to use a Zap logger as an `io.Writer`.
+* [#897][]: Add `zap.WithClock` option to control the source of time via the
+ new `zapcore.Clock` interface.
+* [#949][]: Avoid panicking in `zap.SugaredLogger` when arguments of `*w`
+ methods don't match expectations.
+* [#943][]: Add support for filtering by level or arbitrary matcher function to
+ `zaptest/observer`.
+* [#691][]: Comply with `io.StringWriter` and `io.ByteWriter` in Zap's
+ `buffer.Buffer`.
+
+Thanks to @atrn0, @ernado, @heyanfu, @hnlq715, @zchee
+for their contributions to this release.
+
+[#691]: https://github.com/uber-go/zap/pull/691
+[#897]: https://github.com/uber-go/zap/pull/897
+[#943]: https://github.com/uber-go/zap/pull/943
+[#949]: https://github.com/uber-go/zap/pull/949
+[#961]: https://github.com/uber-go/zap/pull/961
+[#971]: https://github.com/uber-go/zap/pull/971
+
## 1.17.0 (25 May 2021)
Bugfixes:
diff --git a/vendor/go.uber.org/zap/buffer/buffer.go b/vendor/go.uber.org/zap/buffer/buffer.go
index 3f4b86e08..9e929cd98 100644
--- a/vendor/go.uber.org/zap/buffer/buffer.go
+++ b/vendor/go.uber.org/zap/buffer/buffer.go
@@ -106,6 +106,24 @@ func (b *Buffer) Write(bs []byte) (int, error) {
return len(bs), nil
}
+// WriteByte writes a single byte to the Buffer.
+//
+// Error returned is always nil, function signature is compatible
+// with bytes.Buffer and bufio.Writer
+func (b *Buffer) WriteByte(v byte) error {
+ b.AppendByte(v)
+ return nil
+}
+
+// WriteString writes a string to the Buffer.
+//
+// Error returned is always nil, function signature is compatible
+// with bytes.Buffer and bufio.Writer
+func (b *Buffer) WriteString(s string) (int, error) {
+ b.AppendString(s)
+ return len(s), nil
+}
+
// TrimNewline trims any final "\n" byte from the end of the buffer.
func (b *Buffer) TrimNewline() {
if i := len(b.bs) - 1; i >= 0 {
diff --git a/vendor/go.uber.org/zap/go.mod b/vendor/go.uber.org/zap/go.mod
index 6578a3545..9455c99cc 100644
--- a/vendor/go.uber.org/zap/go.mod
+++ b/vendor/go.uber.org/zap/go.mod
@@ -3,9 +3,11 @@ module go.uber.org/zap
go 1.13
require (
+ github.com/benbjohnson/clock v1.1.0
github.com/pkg/errors v0.8.1
github.com/stretchr/testify v1.7.0
go.uber.org/atomic v1.7.0
+ go.uber.org/goleak v1.1.10
go.uber.org/multierr v1.6.0
gopkg.in/yaml.v2 v2.2.8
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
diff --git a/vendor/go.uber.org/zap/go.sum b/vendor/go.uber.org/zap/go.sum
index 911a87ae1..9031a6131 100644
--- a/vendor/go.uber.org/zap/go.sum
+++ b/vendor/go.uber.org/zap/go.sum
@@ -1,20 +1,44 @@
+github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8=
+github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
+github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
+github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
+github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
+github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
+github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
+go.uber.org/goleak v1.1.10 h1:z+mqJhf6ss6BSfSM671tgKyZBFPTTJM+HLxnhPC3wu0=
+go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A=
go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4=
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
-gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
+golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/lint v0.0.0-20190930215403-16217165b5de h1:5hukYrvBGR8/eNkX5mdUezrA6JiaEZDtJb9Ei+1LlBs=
+golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20191108193012-7d206e10da11 h1:Yq9t9jnGoR+dBuitxdo9l6Q7xh/zOyNnYUtDKaQ3x0E=
+golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
+gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
diff --git a/vendor/go.uber.org/zap/logger.go b/vendor/go.uber.org/zap/logger.go
index 553f258e7..f116bd936 100644
--- a/vendor/go.uber.org/zap/logger.go
+++ b/vendor/go.uber.org/zap/logger.go
@@ -26,7 +26,6 @@ import (
"os"
"runtime"
"strings"
- "time"
"go.uber.org/zap/zapcore"
)
@@ -51,6 +50,8 @@ type Logger struct {
addStack zapcore.LevelEnabler
callerSkip int
+
+ clock zapcore.Clock
}
// New constructs a new Logger from the provided zapcore.Core and Options. If
@@ -71,6 +72,7 @@ func New(core zapcore.Core, options ...Option) *Logger {
core: core,
errorOutput: zapcore.Lock(os.Stderr),
addStack: zapcore.FatalLevel + 1,
+ clock: zapcore.DefaultClock,
}
return log.WithOptions(options...)
}
@@ -85,6 +87,7 @@ func NewNop() *Logger {
core: zapcore.NewNopCore(),
errorOutput: zapcore.AddSync(ioutil.Discard),
addStack: zapcore.FatalLevel + 1,
+ clock: zapcore.DefaultClock,
}
}
@@ -270,7 +273,7 @@ func (log *Logger) check(lvl zapcore.Level, msg string) *zapcore.CheckedEntry {
// log message will actually be written somewhere.
ent := zapcore.Entry{
LoggerName: log.name,
- Time: time.Now(),
+ Time: log.clock.Now(),
Level: lvl,
Message: msg,
}
@@ -307,7 +310,7 @@ func (log *Logger) check(lvl zapcore.Level, msg string) *zapcore.CheckedEntry {
if log.addCaller {
frame, defined := getCallerFrame(log.callerSkip + callerSkipOffset)
if !defined {
- fmt.Fprintf(log.errorOutput, "%v Logger.check error: failed to get caller\n", time.Now().UTC())
+ fmt.Fprintf(log.errorOutput, "%v Logger.check error: failed to get caller\n", ent.Time.UTC())
log.errorOutput.Sync()
}
diff --git a/vendor/go.uber.org/zap/options.go b/vendor/go.uber.org/zap/options.go
index 0135c2092..e9e66161f 100644
--- a/vendor/go.uber.org/zap/options.go
+++ b/vendor/go.uber.org/zap/options.go
@@ -138,3 +138,11 @@ func OnFatal(action zapcore.CheckWriteAction) Option {
log.onFatal = action
})
}
+
+// WithClock specifies the clock used by the logger to determine the current
+// time for logged entries. Defaults to the system clock with time.Now.
+func WithClock(clock zapcore.Clock) Option {
+ return optionFunc(func(log *Logger) {
+ log.clock = clock
+ })
+}
diff --git a/vendor/go.uber.org/zap/sugar.go b/vendor/go.uber.org/zap/sugar.go
index 4084dada7..0b9651981 100644
--- a/vendor/go.uber.org/zap/sugar.go
+++ b/vendor/go.uber.org/zap/sugar.go
@@ -266,7 +266,7 @@ func (s *SugaredLogger) sweetenFields(args []interface{}) []Field {
// Make sure this element isn't a dangling key.
if i == len(args)-1 {
- s.base.DPanic(_oddNumberErrMsg, Any("ignored", args[i]))
+ s.base.Error(_oddNumberErrMsg, Any("ignored", args[i]))
break
}
@@ -287,7 +287,7 @@ func (s *SugaredLogger) sweetenFields(args []interface{}) []Field {
// If we encountered any invalid key-value pairs, log an error.
if len(invalid) > 0 {
- s.base.DPanic(_nonStringKeyErrMsg, Array("invalid", invalid))
+ s.base.Error(_nonStringKeyErrMsg, Array("invalid", invalid))
}
return fields
}
diff --git a/vendor/go.uber.org/zap/zapcore/buffered_write_syncer.go b/vendor/go.uber.org/zap/zapcore/buffered_write_syncer.go
new file mode 100644
index 000000000..ef2f7d963
--- /dev/null
+++ b/vendor/go.uber.org/zap/zapcore/buffered_write_syncer.go
@@ -0,0 +1,188 @@
+// Copyright (c) 2021 Uber Technologies, Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+package zapcore
+
+import (
+ "bufio"
+ "sync"
+ "time"
+
+ "go.uber.org/multierr"
+)
+
+const (
+ // _defaultBufferSize specifies the default size used by Buffer.
+ _defaultBufferSize = 256 * 1024 // 256 kB
+
+ // _defaultFlushInterval specifies the default flush interval for
+ // Buffer.
+ _defaultFlushInterval = 30 * time.Second
+)
+
+// A BufferedWriteSyncer is a WriteSyncer that buffers writes in-memory before
+// flushing them to a wrapped WriteSyncer after reaching some limit, or at some
+// fixed interval--whichever comes first.
+//
+// BufferedWriteSyncer is safe for concurrent use. You don't need to use
+// zapcore.Lock for WriteSyncers with BufferedWriteSyncer.
+type BufferedWriteSyncer struct {
+ // WS is the WriteSyncer around which BufferedWriteSyncer will buffer
+ // writes.
+ //
+ // This field is required.
+ WS WriteSyncer
+
+ // Size specifies the maximum amount of data the writer will buffered
+ // before flushing.
+ //
+ // Defaults to 256 kB if unspecified.
+ Size int
+
+ // FlushInterval specifies how often the writer should flush data if
+ // there have been no writes.
+ //
+ // Defaults to 30 seconds if unspecified.
+ FlushInterval time.Duration
+
+ // Clock, if specified, provides control of the source of time for the
+ // writer.
+ //
+ // Defaults to the system clock.
+ Clock Clock
+
+ // unexported fields for state
+ mu sync.Mutex
+ initialized bool // whether initialize() has run
+ stopped bool // whether Stop() has run
+ writer *bufio.Writer
+ ticker *time.Ticker
+ stop chan struct{} // closed when flushLoop should stop
+ done chan struct{} // closed when flushLoop has stopped
+}
+
+func (s *BufferedWriteSyncer) initialize() {
+ size := s.Size
+ if size == 0 {
+ size = _defaultBufferSize
+ }
+
+ flushInterval := s.FlushInterval
+ if flushInterval == 0 {
+ flushInterval = _defaultFlushInterval
+ }
+
+ if s.Clock == nil {
+ s.Clock = DefaultClock
+ }
+
+ s.ticker = s.Clock.NewTicker(flushInterval)
+ s.writer = bufio.NewWriterSize(s.WS, size)
+ s.stop = make(chan struct{})
+ s.done = make(chan struct{})
+ s.initialized = true
+ go s.flushLoop()
+}
+
+// Write writes log data into buffer syncer directly, multiple Write calls will be batched,
+// and log data will be flushed to disk when the buffer is full or periodically.
+func (s *BufferedWriteSyncer) Write(bs []byte) (int, error) {
+ s.mu.Lock()
+ defer s.mu.Unlock()
+
+ if !s.initialized {
+ s.initialize()
+ }
+
+ // To avoid partial writes from being flushed, we manually flush the existing buffer if:
+ // * The current write doesn't fit into the buffer fully, and
+ // * The buffer is not empty (since bufio will not split large writes when the buffer is empty)
+ if len(bs) > s.writer.Available() && s.writer.Buffered() > 0 {
+ if err := s.writer.Flush(); err != nil {
+ return 0, err
+ }
+ }
+
+ return s.writer.Write(bs)
+}
+
+// Sync flushes buffered log data into disk directly.
+func (s *BufferedWriteSyncer) Sync() error {
+ s.mu.Lock()
+ defer s.mu.Unlock()
+
+ var err error
+ if s.initialized {
+ err = s.writer.Flush()
+ }
+
+ return multierr.Append(err, s.WS.Sync())
+}
+
+// flushLoop flushes the buffer at the configured interval until Stop is
+// called.
+func (s *BufferedWriteSyncer) flushLoop() {
+ defer close(s.done)
+
+ for {
+ select {
+ case <-s.ticker.C:
+ // we just simply ignore error here
+ // because the underlying bufio writer stores any errors
+ // and we return any error from Sync() as part of the close
+ _ = s.Sync()
+ case <-s.stop:
+ return
+ }
+ }
+}
+
+// Stop closes the buffer, cleans up background goroutines, and flushes
+// remaining unwritten data.
+func (s *BufferedWriteSyncer) Stop() (err error) {
+ var stopped bool
+
+ // Critical section.
+ func() {
+ s.mu.Lock()
+ defer s.mu.Unlock()
+
+ if !s.initialized {
+ return
+ }
+
+ stopped = s.stopped
+ if stopped {
+ return
+ }
+ s.stopped = true
+
+ s.ticker.Stop()
+ close(s.stop) // tell flushLoop to stop
+ <-s.done // and wait until it has
+ }()
+
+ // Don't call Sync on consecutive Stops.
+ if !stopped {
+ err = s.Sync()
+ }
+
+ return err
+}
diff --git a/vendor/go.uber.org/zap/zapcore/clock.go b/vendor/go.uber.org/zap/zapcore/clock.go
new file mode 100644
index 000000000..d2ea95b39
--- /dev/null
+++ b/vendor/go.uber.org/zap/zapcore/clock.go
@@ -0,0 +1,50 @@
+// Copyright (c) 2021 Uber Technologies, Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+package zapcore
+
+import (
+ "time"
+)
+
+// DefaultClock is the default clock used by Zap in operations that require
+// time. This clock uses the system clock for all operations.
+var DefaultClock = systemClock{}
+
+// Clock is a source of time for logged entries.
+type Clock interface {
+ // Now returns the current local time.
+ Now() time.Time
+
+ // NewTicker returns *time.Ticker that holds a channel
+ // that delivers "ticks" of a clock.
+ NewTicker(time.Duration) *time.Ticker
+}
+
+// systemClock implements default Clock that uses system time.
+type systemClock struct{}
+
+func (systemClock) Now() time.Time {
+ return time.Now()
+}
+
+func (systemClock) NewTicker(duration time.Duration) *time.Ticker {
+ return time.NewTicker(duration)
+}
diff --git a/vendor/go.uber.org/zap/zapcore/entry.go b/vendor/go.uber.org/zap/zapcore/entry.go
index 4aa8b4f90..0885505b7 100644
--- a/vendor/go.uber.org/zap/zapcore/entry.go
+++ b/vendor/go.uber.org/zap/zapcore/entry.go
@@ -208,7 +208,7 @@ func (ce *CheckedEntry) Write(fields ...Field) {
// If the entry is dirty, log an internal error; because the
// CheckedEntry is being used after it was returned to the pool,
// the message may be an amalgamation from multiple call sites.
- fmt.Fprintf(ce.ErrorOutput, "%v Unsafe CheckedEntry re-use near Entry %+v.\n", time.Now(), ce.Entry)
+ fmt.Fprintf(ce.ErrorOutput, "%v Unsafe CheckedEntry re-use near Entry %+v.\n", ce.Time, ce.Entry)
ce.ErrorOutput.Sync()
}
return
@@ -219,11 +219,9 @@ func (ce *CheckedEntry) Write(fields ...Field) {
for i := range ce.cores {
err = multierr.Append(err, ce.cores[i].Write(ce.Entry, fields))
}
- if ce.ErrorOutput != nil {
- if err != nil {
- fmt.Fprintf(ce.ErrorOutput, "%v write error: %v\n", time.Now(), err)
- ce.ErrorOutput.Sync()
- }
+ if err != nil && ce.ErrorOutput != nil {
+ fmt.Fprintf(ce.ErrorOutput, "%v write error: %v\n", ce.Time, err)
+ ce.ErrorOutput.Sync()
}
should, msg := ce.should, ce.Message
diff --git a/vendor/go.uber.org/zap/zapcore/error.go b/vendor/go.uber.org/zap/zapcore/error.go
index f2a07d786..74919b0cc 100644
--- a/vendor/go.uber.org/zap/zapcore/error.go
+++ b/vendor/go.uber.org/zap/zapcore/error.go
@@ -83,7 +83,7 @@ type errorGroup interface {
Errors() []error
}
-// Note that errArry and errArrayElem are very similar to the version
+// Note that errArray and errArrayElem are very similar to the version
// implemented in the top-level error.go file. We can't re-use this because
// that would require exporting errArray as part of the zapcore API.
diff --git a/vendor/go.uber.org/zap/zapcore/sampler.go b/vendor/go.uber.org/zap/zapcore/sampler.go
index 25f10ca1d..31ed96e12 100644
--- a/vendor/go.uber.org/zap/zapcore/sampler.go
+++ b/vendor/go.uber.org/zap/zapcore/sampler.go
@@ -197,12 +197,14 @@ func (s *sampler) Check(ent Entry, ce *CheckedEntry) *CheckedEntry {
return ce
}
- counter := s.counts.get(ent.Level, ent.Message)
- n := counter.IncCheckReset(ent.Time, s.tick)
- if n > s.first && (n-s.first)%s.thereafter != 0 {
- s.hook(ent, LogDropped)
- return ce
+ if ent.Level >= _minLevel && ent.Level <= _maxLevel {
+ counter := s.counts.get(ent.Level, ent.Message)
+ n := counter.IncCheckReset(ent.Time, s.tick)
+ if n > s.first && (n-s.first)%s.thereafter != 0 {
+ s.hook(ent, LogDropped)
+ return ce
+ }
+ s.hook(ent, LogSampled)
}
- s.hook(ent, LogSampled)
return s.Core.Check(ent, ce)
}
diff --git a/vendor/gomodules.xyz/jsonpatch/v2/LICENSE b/vendor/gomodules.xyz/jsonpatch/v2/LICENSE
new file mode 100644
index 000000000..8f71f43fe
--- /dev/null
+++ b/vendor/gomodules.xyz/jsonpatch/v2/LICENSE
@@ -0,0 +1,202 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "{}"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright {yyyy} {name of copyright owner}
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
diff --git a/vendor/gomodules.xyz/jsonpatch/v2/go.mod b/vendor/gomodules.xyz/jsonpatch/v2/go.mod
new file mode 100644
index 000000000..0395a5805
--- /dev/null
+++ b/vendor/gomodules.xyz/jsonpatch/v2/go.mod
@@ -0,0 +1,8 @@
+module gomodules.xyz/jsonpatch/v2
+
+go 1.12
+
+require (
+ github.com/evanphx/json-patch v0.5.2
+ github.com/stretchr/testify v1.3.0
+)
diff --git a/vendor/gomodules.xyz/jsonpatch/v2/go.sum b/vendor/gomodules.xyz/jsonpatch/v2/go.sum
new file mode 100644
index 000000000..d931385bc
--- /dev/null
+++ b/vendor/gomodules.xyz/jsonpatch/v2/go.sum
@@ -0,0 +1,12 @@
+github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
+github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/evanphx/json-patch v0.5.2 h1:xVCHIVMUu1wtM/VkR9jVZ45N3FhZfYMMYGorLCR8P3k=
+github.com/evanphx/json-patch v0.5.2/go.mod h1:ZWS5hhDbVDyob71nXKNL0+PWn6ToqBHMikGIFbs31qQ=
+github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
+github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
+github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
+github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
+github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
diff --git a/vendor/gomodules.xyz/jsonpatch/v2/jsonpatch.go b/vendor/gomodules.xyz/jsonpatch/v2/jsonpatch.go
new file mode 100644
index 000000000..0ffb31560
--- /dev/null
+++ b/vendor/gomodules.xyz/jsonpatch/v2/jsonpatch.go
@@ -0,0 +1,334 @@
+package jsonpatch
+
+import (
+ "bytes"
+ "encoding/json"
+ "fmt"
+ "reflect"
+ "strings"
+)
+
+var errBadJSONDoc = fmt.Errorf("invalid JSON Document")
+
+type JsonPatchOperation = Operation
+
+type Operation struct {
+ Operation string `json:"op"`
+ Path string `json:"path"`
+ Value interface{} `json:"value,omitempty"`
+}
+
+func (j *Operation) Json() string {
+ b, _ := json.Marshal(j)
+ return string(b)
+}
+
+func (j *Operation) MarshalJSON() ([]byte, error) {
+ var b bytes.Buffer
+ b.WriteString("{")
+ b.WriteString(fmt.Sprintf(`"op":"%s"`, j.Operation))
+ b.WriteString(fmt.Sprintf(`,"path":"%s"`, j.Path))
+ // Consider omitting Value for non-nullable operations.
+ if j.Value != nil || j.Operation == "replace" || j.Operation == "add" {
+ v, err := json.Marshal(j.Value)
+ if err != nil {
+ return nil, err
+ }
+ b.WriteString(`,"value":`)
+ b.Write(v)
+ }
+ b.WriteString("}")
+ return b.Bytes(), nil
+}
+
+type ByPath []Operation
+
+func (a ByPath) Len() int { return len(a) }
+func (a ByPath) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
+func (a ByPath) Less(i, j int) bool { return a[i].Path < a[j].Path }
+
+func NewOperation(op, path string, value interface{}) Operation {
+ return Operation{Operation: op, Path: path, Value: value}
+}
+
+// CreatePatch creates a patch as specified in http://jsonpatch.com/
+//
+// 'a' is original, 'b' is the modified document. Both are to be given as json encoded content.
+// The function will return an array of JsonPatchOperations
+//
+// An error will be returned if any of the two documents are invalid.
+func CreatePatch(a, b []byte) ([]Operation, error) {
+ var aI interface{}
+ var bI interface{}
+ err := json.Unmarshal(a, &aI)
+ if err != nil {
+ return nil, errBadJSONDoc
+ }
+ err = json.Unmarshal(b, &bI)
+ if err != nil {
+ return nil, errBadJSONDoc
+ }
+ return handleValues(aI, bI, "", []Operation{})
+}
+
+// Returns true if the values matches (must be json types)
+// The types of the values must match, otherwise it will always return false
+// If two map[string]interface{} are given, all elements must match.
+func matchesValue(av, bv interface{}) bool {
+ if reflect.TypeOf(av) != reflect.TypeOf(bv) {
+ return false
+ }
+ switch at := av.(type) {
+ case string:
+ bt, ok := bv.(string)
+ if ok && bt == at {
+ return true
+ }
+ case float64:
+ bt, ok := bv.(float64)
+ if ok && bt == at {
+ return true
+ }
+ case bool:
+ bt, ok := bv.(bool)
+ if ok && bt == at {
+ return true
+ }
+ case map[string]interface{}:
+ bt, ok := bv.(map[string]interface{})
+ if !ok {
+ return false
+ }
+ for key := range at {
+ if !matchesValue(at[key], bt[key]) {
+ return false
+ }
+ }
+ for key := range bt {
+ if !matchesValue(at[key], bt[key]) {
+ return false
+ }
+ }
+ return true
+ case []interface{}:
+ bt, ok := bv.([]interface{})
+ if !ok {
+ return false
+ }
+ if len(bt) != len(at) {
+ return false
+ }
+ for key := range at {
+ if !matchesValue(at[key], bt[key]) {
+ return false
+ }
+ }
+ for key := range bt {
+ if !matchesValue(at[key], bt[key]) {
+ return false
+ }
+ }
+ return true
+ }
+ return false
+}
+
+// From http://tools.ietf.org/html/rfc6901#section-4 :
+//
+// Evaluation of each reference token begins by decoding any escaped
+// character sequence. This is performed by first transforming any
+// occurrence of the sequence '~1' to '/', and then transforming any
+// occurrence of the sequence '~0' to '~'.
+// TODO decode support:
+// var rfc6901Decoder = strings.NewReplacer("~1", "/", "~0", "~")
+
+var rfc6901Encoder = strings.NewReplacer("~", "~0", "/", "~1")
+
+func makePath(path string, newPart interface{}) string {
+ key := rfc6901Encoder.Replace(fmt.Sprintf("%v", newPart))
+ if path == "" {
+ return "/" + key
+ }
+ if strings.HasSuffix(path, "/") {
+ return path + key
+ }
+ return path + "/" + key
+}
+
+// diff returns the (recursive) difference between a and b as an array of JsonPatchOperations.
+func diff(a, b map[string]interface{}, path string, patch []Operation) ([]Operation, error) {
+ for key, bv := range b {
+ p := makePath(path, key)
+ av, ok := a[key]
+ // value was added
+ if !ok {
+ patch = append(patch, NewOperation("add", p, bv))
+ continue
+ }
+ // Types are the same, compare values
+ var err error
+ patch, err = handleValues(av, bv, p, patch)
+ if err != nil {
+ return nil, err
+ }
+ }
+ // Now add all deleted values as nil
+ for key := range a {
+ _, found := b[key]
+ if !found {
+ p := makePath(path, key)
+
+ patch = append(patch, NewOperation("remove", p, nil))
+ }
+ }
+ return patch, nil
+}
+
+func handleValues(av, bv interface{}, p string, patch []Operation) ([]Operation, error) {
+ {
+ at := reflect.TypeOf(av)
+ bt := reflect.TypeOf(bv)
+ if at == nil && bt == nil {
+ // do nothing
+ return patch, nil
+ } else if at != bt {
+ // If types have changed, replace completely (preserves null in destination)
+ return append(patch, NewOperation("replace", p, bv)), nil
+ }
+ }
+
+ var err error
+ switch at := av.(type) {
+ case map[string]interface{}:
+ bt := bv.(map[string]interface{})
+ patch, err = diff(at, bt, p, patch)
+ if err != nil {
+ return nil, err
+ }
+ case string, float64, bool:
+ if !matchesValue(av, bv) {
+ patch = append(patch, NewOperation("replace", p, bv))
+ }
+ case []interface{}:
+ bt := bv.([]interface{})
+ if isSimpleArray(at) && isSimpleArray(bt) {
+ patch = append(patch, compareEditDistance(at, bt, p)...)
+ } else {
+ n := min(len(at), len(bt))
+ for i := len(at) - 1; i >= n; i-- {
+ patch = append(patch, NewOperation("remove", makePath(p, i), nil))
+ }
+ for i := n; i < len(bt); i++ {
+ patch = append(patch, NewOperation("add", makePath(p, i), bt[i]))
+ }
+ for i := 0; i < n; i++ {
+ var err error
+ patch, err = handleValues(at[i], bt[i], makePath(p, i), patch)
+ if err != nil {
+ return nil, err
+ }
+ }
+ }
+ default:
+ panic(fmt.Sprintf("Unknown type:%T ", av))
+ }
+ return patch, nil
+}
+
+func isBasicType(a interface{}) bool {
+ switch a.(type) {
+ case string, float64, bool:
+ default:
+ return false
+ }
+ return true
+}
+
+func isSimpleArray(a []interface{}) bool {
+ for i := range a {
+ switch a[i].(type) {
+ case string, float64, bool:
+ default:
+ val := reflect.ValueOf(a[i])
+ if val.Kind() == reflect.Map {
+ for _, k := range val.MapKeys() {
+ av := val.MapIndex(k)
+ if av.Kind() == reflect.Ptr || av.Kind() == reflect.Interface {
+ if av.IsNil() {
+ continue
+ }
+ av = av.Elem()
+ }
+ if av.Kind() != reflect.String && av.Kind() != reflect.Float64 && av.Kind() != reflect.Bool {
+ return false
+ }
+ }
+ return true
+ }
+ return false
+ }
+ }
+ return true
+}
+
+// https://en.wikipedia.org/wiki/Wagner%E2%80%93Fischer_algorithm
+// Adapted from https://github.com/texttheater/golang-levenshtein
+func compareEditDistance(s, t []interface{}, p string) []Operation {
+ m := len(s)
+ n := len(t)
+
+ d := make([][]int, m+1)
+ for i := 0; i <= m; i++ {
+ d[i] = make([]int, n+1)
+ d[i][0] = i
+ }
+ for j := 0; j <= n; j++ {
+ d[0][j] = j
+ }
+
+ for j := 1; j <= n; j++ {
+ for i := 1; i <= m; i++ {
+ if reflect.DeepEqual(s[i-1], t[j-1]) {
+ d[i][j] = d[i-1][j-1] // no op required
+ } else {
+ del := d[i-1][j] + 1
+ add := d[i][j-1] + 1
+ rep := d[i-1][j-1] + 1
+ d[i][j] = min(rep, min(add, del))
+ }
+ }
+ }
+
+ return backtrace(s, t, p, m, n, d)
+}
+
+func min(x int, y int) int {
+ if y < x {
+ return y
+ }
+ return x
+}
+
+func backtrace(s, t []interface{}, p string, i int, j int, matrix [][]int) []Operation {
+ if i > 0 && matrix[i-1][j]+1 == matrix[i][j] {
+ op := NewOperation("remove", makePath(p, i-1), nil)
+ return append([]Operation{op}, backtrace(s, t, p, i-1, j, matrix)...)
+ }
+ if j > 0 && matrix[i][j-1]+1 == matrix[i][j] {
+ op := NewOperation("add", makePath(p, i), t[j-1])
+ return append([]Operation{op}, backtrace(s, t, p, i, j-1, matrix)...)
+ }
+ if i > 0 && j > 0 && matrix[i-1][j-1]+1 == matrix[i][j] {
+ if isBasicType(s[0]) {
+ op := NewOperation("replace", makePath(p, i-1), t[j-1])
+ return append([]Operation{op}, backtrace(s, t, p, i-1, j-1, matrix)...)
+ }
+
+ p2, _ := handleValues(s[i-1], t[j-1], makePath(p, i-1), []Operation{})
+ return append(p2, backtrace(s, t, p, i-1, j-1, matrix)...)
+ }
+ if i > 0 && j > 0 && matrix[i-1][j-1] == matrix[i][j] {
+ return backtrace(s, t, p, i-1, j-1, matrix)
+ }
+ return []Operation{}
+}
diff --git a/vendor/k8s.io/client-go/metadata/interface.go b/vendor/k8s.io/client-go/metadata/interface.go
new file mode 100644
index 000000000..127c39501
--- /dev/null
+++ b/vendor/k8s.io/client-go/metadata/interface.go
@@ -0,0 +1,49 @@
+/*
+Copyright 2016 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 metadata
+
+import (
+ "context"
+
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ "k8s.io/apimachinery/pkg/runtime/schema"
+ "k8s.io/apimachinery/pkg/types"
+ "k8s.io/apimachinery/pkg/watch"
+)
+
+// Interface allows a caller to get the metadata (in the form of PartialObjectMetadata objects)
+// from any Kubernetes compatible resource API.
+type Interface interface {
+ Resource(resource schema.GroupVersionResource) Getter
+}
+
+// ResourceInterface contains the set of methods that may be invoked on objects by their metadata.
+// Update is not supported by the server, but Patch can be used for the actions Update would handle.
+type ResourceInterface interface {
+ Delete(ctx context.Context, name string, options metav1.DeleteOptions, subresources ...string) error
+ DeleteCollection(ctx context.Context, options metav1.DeleteOptions, listOptions metav1.ListOptions) error
+ Get(ctx context.Context, name string, options metav1.GetOptions, subresources ...string) (*metav1.PartialObjectMetadata, error)
+ List(ctx context.Context, opts metav1.ListOptions) (*metav1.PartialObjectMetadataList, error)
+ Watch(ctx context.Context, opts metav1.ListOptions) (watch.Interface, error)
+ Patch(ctx context.Context, name string, pt types.PatchType, data []byte, options metav1.PatchOptions, subresources ...string) (*metav1.PartialObjectMetadata, error)
+}
+
+// Getter handles both namespaced and non-namespaced resource types consistently.
+type Getter interface {
+ Namespace(string) ResourceInterface
+ ResourceInterface
+}
diff --git a/vendor/k8s.io/client-go/metadata/metadata.go b/vendor/k8s.io/client-go/metadata/metadata.go
new file mode 100644
index 000000000..72b557991
--- /dev/null
+++ b/vendor/k8s.io/client-go/metadata/metadata.go
@@ -0,0 +1,307 @@
+/*
+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 metadata
+
+import (
+ "context"
+ "encoding/json"
+ "fmt"
+ "time"
+
+ "k8s.io/klog/v2"
+
+ metainternalversionscheme "k8s.io/apimachinery/pkg/apis/meta/internalversion/scheme"
+ 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/types"
+ "k8s.io/apimachinery/pkg/watch"
+ "k8s.io/client-go/rest"
+)
+
+var deleteScheme = runtime.NewScheme()
+var parameterScheme = runtime.NewScheme()
+var deleteOptionsCodec = serializer.NewCodecFactory(deleteScheme)
+var dynamicParameterCodec = runtime.NewParameterCodec(parameterScheme)
+
+var versionV1 = schema.GroupVersion{Version: "v1"}
+
+func init() {
+ metav1.AddToGroupVersion(parameterScheme, versionV1)
+ metav1.AddToGroupVersion(deleteScheme, versionV1)
+}
+
+// Client allows callers to retrieve the object metadata for any
+// Kubernetes-compatible API endpoint. The client uses the
+// meta.k8s.io/v1 PartialObjectMetadata resource to more efficiently
+// retrieve just the necessary metadata, but on older servers
+// (Kubernetes 1.14 and before) will retrieve the object and then
+// convert the metadata.
+type Client struct {
+ client *rest.RESTClient
+}
+
+var _ Interface = &Client{}
+
+// ConfigFor returns a copy of the provided config with the
+// appropriate metadata client defaults set.
+func ConfigFor(inConfig *rest.Config) *rest.Config {
+ config := rest.CopyConfig(inConfig)
+ config.AcceptContentTypes = "application/vnd.kubernetes.protobuf,application/json"
+ config.ContentType = "application/vnd.kubernetes.protobuf"
+ config.NegotiatedSerializer = metainternalversionscheme.Codecs.WithoutConversion()
+ if config.UserAgent == "" {
+ config.UserAgent = rest.DefaultKubernetesUserAgent()
+ }
+ return config
+}
+
+// NewForConfigOrDie creates a new metadata client for the given config and
+// panics if there is an error in the config.
+func NewForConfigOrDie(c *rest.Config) Interface {
+ ret, err := NewForConfig(c)
+ if err != nil {
+ panic(err)
+ }
+ return ret
+}
+
+// NewForConfig creates a new metadata client that can retrieve object
+// metadata details about any Kubernetes object (core, aggregated, or custom
+// resource based) in the form of PartialObjectMetadata objects, or returns
+// an error.
+func NewForConfig(inConfig *rest.Config) (Interface, error) {
+ config := ConfigFor(inConfig)
+ // for serializing the options
+ config.GroupVersion = &schema.GroupVersion{}
+ config.APIPath = "/this-value-should-never-be-sent"
+
+ restClient, err := rest.RESTClientFor(config)
+ if err != nil {
+ return nil, err
+ }
+
+ return &Client{client: restClient}, nil
+}
+
+type client struct {
+ client *Client
+ namespace string
+ resource schema.GroupVersionResource
+}
+
+// Resource returns an interface that can access cluster or namespace
+// scoped instances of resource.
+func (c *Client) Resource(resource schema.GroupVersionResource) Getter {
+ return &client{client: c, resource: resource}
+}
+
+// Namespace returns an interface that can access namespace-scoped instances of the
+// provided resource.
+func (c *client) Namespace(ns string) ResourceInterface {
+ ret := *c
+ ret.namespace = ns
+ return &ret
+}
+
+// Delete removes the provided resource from the server.
+func (c *client) Delete(ctx context.Context, name string, opts metav1.DeleteOptions, subresources ...string) error {
+ if len(name) == 0 {
+ return fmt.Errorf("name is required")
+ }
+ deleteOptionsByte, err := runtime.Encode(deleteOptionsCodec.LegacyCodec(schema.GroupVersion{Version: "v1"}), &opts)
+ if err != nil {
+ return err
+ }
+
+ result := c.client.client.
+ Delete().
+ AbsPath(append(c.makeURLSegments(name), subresources...)...).
+ Body(deleteOptionsByte).
+ Do(ctx)
+ return result.Error()
+}
+
+// DeleteCollection triggers deletion of all resources in the specified scope (namespace or cluster).
+func (c *client) DeleteCollection(ctx context.Context, opts metav1.DeleteOptions, listOptions metav1.ListOptions) error {
+ deleteOptionsByte, err := runtime.Encode(deleteOptionsCodec.LegacyCodec(schema.GroupVersion{Version: "v1"}), &opts)
+ if err != nil {
+ return err
+ }
+
+ result := c.client.client.
+ Delete().
+ AbsPath(c.makeURLSegments("")...).
+ Body(deleteOptionsByte).
+ SpecificallyVersionedParams(&listOptions, dynamicParameterCodec, versionV1).
+ Do(ctx)
+ return result.Error()
+}
+
+// Get returns the resource with name from the specified scope (namespace or cluster).
+func (c *client) Get(ctx context.Context, name string, opts metav1.GetOptions, subresources ...string) (*metav1.PartialObjectMetadata, error) {
+ if len(name) == 0 {
+ return nil, fmt.Errorf("name is required")
+ }
+ result := c.client.client.Get().AbsPath(append(c.makeURLSegments(name), subresources...)...).
+ SetHeader("Accept", "application/vnd.kubernetes.protobuf;as=PartialObjectMetadata;g=meta.k8s.io;v=v1,application/json;as=PartialObjectMetadata;g=meta.k8s.io;v=v1,application/json").
+ SpecificallyVersionedParams(&opts, dynamicParameterCodec, versionV1).
+ Do(ctx)
+ if err := result.Error(); err != nil {
+ return nil, err
+ }
+ obj, err := result.Get()
+ if runtime.IsNotRegisteredError(err) {
+ klog.V(5).Infof("Unable to retrieve PartialObjectMetadata: %#v", err)
+ rawBytes, err := result.Raw()
+ if err != nil {
+ return nil, err
+ }
+ var partial metav1.PartialObjectMetadata
+ if err := json.Unmarshal(rawBytes, &partial); err != nil {
+ return nil, fmt.Errorf("unable to decode returned object as PartialObjectMetadata: %v", err)
+ }
+ if !isLikelyObjectMetadata(&partial) {
+ return nil, fmt.Errorf("object does not appear to match the ObjectMeta schema: %#v", partial)
+ }
+ partial.TypeMeta = metav1.TypeMeta{}
+ return &partial, nil
+ }
+ if err != nil {
+ return nil, err
+ }
+ partial, ok := obj.(*metav1.PartialObjectMetadata)
+ if !ok {
+ return nil, fmt.Errorf("unexpected object, expected PartialObjectMetadata but got %T", obj)
+ }
+ return partial, nil
+}
+
+// List returns all resources within the specified scope (namespace or cluster).
+func (c *client) List(ctx context.Context, opts metav1.ListOptions) (*metav1.PartialObjectMetadataList, error) {
+ result := c.client.client.Get().AbsPath(c.makeURLSegments("")...).
+ SetHeader("Accept", "application/vnd.kubernetes.protobuf;as=PartialObjectMetadataList;g=meta.k8s.io;v=v1,application/json;as=PartialObjectMetadataList;g=meta.k8s.io;v=v1,application/json").
+ SpecificallyVersionedParams(&opts, dynamicParameterCodec, versionV1).
+ Do(ctx)
+ if err := result.Error(); err != nil {
+ return nil, err
+ }
+ obj, err := result.Get()
+ if runtime.IsNotRegisteredError(err) {
+ klog.V(5).Infof("Unable to retrieve PartialObjectMetadataList: %#v", err)
+ rawBytes, err := result.Raw()
+ if err != nil {
+ return nil, err
+ }
+ var partial metav1.PartialObjectMetadataList
+ if err := json.Unmarshal(rawBytes, &partial); err != nil {
+ return nil, fmt.Errorf("unable to decode returned object as PartialObjectMetadataList: %v", err)
+ }
+ partial.TypeMeta = metav1.TypeMeta{}
+ return &partial, nil
+ }
+ if err != nil {
+ return nil, err
+ }
+ partial, ok := obj.(*metav1.PartialObjectMetadataList)
+ if !ok {
+ return nil, fmt.Errorf("unexpected object, expected PartialObjectMetadata but got %T", obj)
+ }
+ return partial, nil
+}
+
+// Watch finds all changes to the resources in the specified scope (namespace or cluster).
+func (c *client) Watch(ctx context.Context, opts metav1.ListOptions) (watch.Interface, error) {
+ var timeout time.Duration
+ if opts.TimeoutSeconds != nil {
+ timeout = time.Duration(*opts.TimeoutSeconds) * time.Second
+ }
+ opts.Watch = true
+ return c.client.client.Get().
+ AbsPath(c.makeURLSegments("")...).
+ SetHeader("Accept", "application/vnd.kubernetes.protobuf;as=PartialObjectMetadata;g=meta.k8s.io;v=v1,application/json;as=PartialObjectMetadata;g=meta.k8s.io;v=v1,application/json").
+ SpecificallyVersionedParams(&opts, dynamicParameterCodec, versionV1).
+ Timeout(timeout).
+ Watch(ctx)
+}
+
+// Patch modifies the named resource in the specified scope (namespace or cluster).
+func (c *client) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts metav1.PatchOptions, subresources ...string) (*metav1.PartialObjectMetadata, error) {
+ if len(name) == 0 {
+ return nil, fmt.Errorf("name is required")
+ }
+ result := c.client.client.
+ Patch(pt).
+ AbsPath(append(c.makeURLSegments(name), subresources...)...).
+ Body(data).
+ SetHeader("Accept", "application/vnd.kubernetes.protobuf;as=PartialObjectMetadata;g=meta.k8s.io;v=v1,application/json;as=PartialObjectMetadata;g=meta.k8s.io;v=v1,application/json").
+ SpecificallyVersionedParams(&opts, dynamicParameterCodec, versionV1).
+ Do(ctx)
+ if err := result.Error(); err != nil {
+ return nil, err
+ }
+ obj, err := result.Get()
+ if runtime.IsNotRegisteredError(err) {
+ rawBytes, err := result.Raw()
+ if err != nil {
+ return nil, err
+ }
+ var partial metav1.PartialObjectMetadata
+ if err := json.Unmarshal(rawBytes, &partial); err != nil {
+ return nil, fmt.Errorf("unable to decode returned object as PartialObjectMetadata: %v", err)
+ }
+ if !isLikelyObjectMetadata(&partial) {
+ return nil, fmt.Errorf("object does not appear to match the ObjectMeta schema")
+ }
+ partial.TypeMeta = metav1.TypeMeta{}
+ return &partial, nil
+ }
+ if err != nil {
+ return nil, err
+ }
+ partial, ok := obj.(*metav1.PartialObjectMetadata)
+ if !ok {
+ return nil, fmt.Errorf("unexpected object, expected PartialObjectMetadata but got %T", obj)
+ }
+ return partial, nil
+}
+
+func (c *client) makeURLSegments(name string) []string {
+ url := []string{}
+ if len(c.resource.Group) == 0 {
+ url = append(url, "api")
+ } else {
+ url = append(url, "apis", c.resource.Group)
+ }
+ url = append(url, c.resource.Version)
+
+ if len(c.namespace) > 0 {
+ url = append(url, "namespaces", c.namespace)
+ }
+ url = append(url, c.resource.Resource)
+
+ if len(name) > 0 {
+ url = append(url, name)
+ }
+
+ return url
+}
+
+func isLikelyObjectMetadata(meta *metav1.PartialObjectMetadata) bool {
+ return len(meta.UID) > 0 || !meta.CreationTimestamp.IsZero() || len(meta.Name) > 0 || len(meta.GenerateName) > 0
+}
diff --git a/vendor/k8s.io/client-go/tools/leaderelection/OWNERS b/vendor/k8s.io/client-go/tools/leaderelection/OWNERS
new file mode 100644
index 000000000..2ba793ee8
--- /dev/null
+++ b/vendor/k8s.io/client-go/tools/leaderelection/OWNERS
@@ -0,0 +1,12 @@
+# See the OWNERS docs at https://go.k8s.io/owners
+
+approvers:
+- mikedanese
+- timothysc
+reviewers:
+- wojtek-t
+- deads2k
+- mikedanese
+- timothysc
+- ingvagabund
+- resouer
diff --git a/vendor/k8s.io/client-go/tools/leaderelection/healthzadaptor.go b/vendor/k8s.io/client-go/tools/leaderelection/healthzadaptor.go
new file mode 100644
index 000000000..b93537291
--- /dev/null
+++ b/vendor/k8s.io/client-go/tools/leaderelection/healthzadaptor.go
@@ -0,0 +1,69 @@
+/*
+Copyright 2015 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package leaderelection
+
+import (
+ "net/http"
+ "sync"
+ "time"
+)
+
+// HealthzAdaptor associates the /healthz endpoint with the LeaderElection object.
+// It helps deal with the /healthz endpoint being set up prior to the LeaderElection.
+// This contains the code needed to act as an adaptor between the leader
+// election code the health check code. It allows us to provide health
+// status about the leader election. Most specifically about if the leader
+// has failed to renew without exiting the process. In that case we should
+// report not healthy and rely on the kubelet to take down the process.
+type HealthzAdaptor struct {
+ pointerLock sync.Mutex
+ le *LeaderElector
+ timeout time.Duration
+}
+
+// Name returns the name of the health check we are implementing.
+func (l *HealthzAdaptor) Name() string {
+ return "leaderElection"
+}
+
+// Check is called by the healthz endpoint handler.
+// It fails (returns an error) if we own the lease but had not been able to renew it.
+func (l *HealthzAdaptor) Check(req *http.Request) error {
+ l.pointerLock.Lock()
+ defer l.pointerLock.Unlock()
+ if l.le == nil {
+ return nil
+ }
+ return l.le.Check(l.timeout)
+}
+
+// SetLeaderElection ties a leader election object to a HealthzAdaptor
+func (l *HealthzAdaptor) SetLeaderElection(le *LeaderElector) {
+ l.pointerLock.Lock()
+ defer l.pointerLock.Unlock()
+ l.le = le
+}
+
+// NewLeaderHealthzAdaptor creates a basic healthz adaptor to monitor a leader election.
+// timeout determines the time beyond the lease expiry to be allowed for timeout.
+// checks within the timeout period after the lease expires will still return healthy.
+func NewLeaderHealthzAdaptor(timeout time.Duration) *HealthzAdaptor {
+ result := &HealthzAdaptor{
+ timeout: timeout,
+ }
+ return result
+}
diff --git a/vendor/k8s.io/client-go/tools/leaderelection/leaderelection.go b/vendor/k8s.io/client-go/tools/leaderelection/leaderelection.go
new file mode 100644
index 000000000..55f34fd3e
--- /dev/null
+++ b/vendor/k8s.io/client-go/tools/leaderelection/leaderelection.go
@@ -0,0 +1,418 @@
+/*
+Copyright 2015 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+// Package leaderelection implements leader election of a set of endpoints.
+// It uses an annotation in the endpoints object to store the record of the
+// election state. This implementation does not guarantee that only one
+// client is acting as a leader (a.k.a. fencing).
+//
+// A client only acts on timestamps captured locally to infer the state of the
+// leader election. The client does not consider timestamps in the leader
+// election record to be accurate because these timestamps may not have been
+// produced by a local clock. The implemention does not depend on their
+// accuracy and only uses their change to indicate that another client has
+// renewed the leader lease. Thus the implementation is tolerant to arbitrary
+// clock skew, but is not tolerant to arbitrary clock skew rate.
+//
+// However the level of tolerance to skew rate can be configured by setting
+// RenewDeadline and LeaseDuration appropriately. The tolerance expressed as a
+// maximum tolerated ratio of time passed on the fastest node to time passed on
+// the slowest node can be approximately achieved with a configuration that sets
+// the same ratio of LeaseDuration to RenewDeadline. For example if a user wanted
+// to tolerate some nodes progressing forward in time twice as fast as other nodes,
+// the user could set LeaseDuration to 60 seconds and RenewDeadline to 30 seconds.
+//
+// While not required, some method of clock synchronization between nodes in the
+// cluster is highly recommended. It's important to keep in mind when configuring
+// this client that the tolerance to skew rate varies inversely to master
+// availability.
+//
+// Larger clusters often have a more lenient SLA for API latency. This should be
+// taken into account when configuring the client. The rate of leader transitions
+// should be monitored and RetryPeriod and LeaseDuration should be increased
+// until the rate is stable and acceptably low. It's important to keep in mind
+// when configuring this client that the tolerance to API latency varies inversely
+// to master availability.
+//
+// DISCLAIMER: this is an alpha API. This library will likely change significantly
+// or even be removed entirely in subsequent releases. Depend on this API at
+// your own risk.
+package leaderelection
+
+import (
+ "bytes"
+ "context"
+ "fmt"
+ "sync"
+ "time"
+
+ "k8s.io/apimachinery/pkg/api/errors"
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ "k8s.io/apimachinery/pkg/util/clock"
+ "k8s.io/apimachinery/pkg/util/runtime"
+ "k8s.io/apimachinery/pkg/util/wait"
+ rl "k8s.io/client-go/tools/leaderelection/resourcelock"
+
+ "k8s.io/klog/v2"
+)
+
+const (
+ JitterFactor = 1.2
+)
+
+// NewLeaderElector creates a LeaderElector from a LeaderElectionConfig
+func NewLeaderElector(lec LeaderElectionConfig) (*LeaderElector, error) {
+ if lec.LeaseDuration <= lec.RenewDeadline {
+ return nil, fmt.Errorf("leaseDuration must be greater than renewDeadline")
+ }
+ if lec.RenewDeadline <= time.Duration(JitterFactor*float64(lec.RetryPeriod)) {
+ return nil, fmt.Errorf("renewDeadline must be greater than retryPeriod*JitterFactor")
+ }
+ if lec.LeaseDuration < 1 {
+ return nil, fmt.Errorf("leaseDuration must be greater than zero")
+ }
+ if lec.RenewDeadline < 1 {
+ return nil, fmt.Errorf("renewDeadline must be greater than zero")
+ }
+ if lec.RetryPeriod < 1 {
+ return nil, fmt.Errorf("retryPeriod must be greater than zero")
+ }
+ if lec.Callbacks.OnStartedLeading == nil {
+ return nil, fmt.Errorf("OnStartedLeading callback must not be nil")
+ }
+ if lec.Callbacks.OnStoppedLeading == nil {
+ return nil, fmt.Errorf("OnStoppedLeading callback must not be nil")
+ }
+
+ if lec.Lock == nil {
+ return nil, fmt.Errorf("Lock must not be nil.")
+ }
+ le := LeaderElector{
+ config: lec,
+ clock: clock.RealClock{},
+ metrics: globalMetricsFactory.newLeaderMetrics(),
+ }
+ le.metrics.leaderOff(le.config.Name)
+ return &le, nil
+}
+
+type LeaderElectionConfig struct {
+ // Lock is the resource that will be used for locking
+ Lock rl.Interface
+
+ // LeaseDuration is the duration that non-leader candidates will
+ // wait to force acquire leadership. This is measured against time of
+ // last observed ack.
+ //
+ // A client needs to wait a full LeaseDuration without observing a change to
+ // the record before it can attempt to take over. When all clients are
+ // shutdown and a new set of clients are started with different names against
+ // the same leader record, they must wait the full LeaseDuration before
+ // attempting to acquire the lease. Thus LeaseDuration should be as short as
+ // possible (within your tolerance for clock skew rate) to avoid a possible
+ // long waits in the scenario.
+ //
+ // Core clients default this value to 15 seconds.
+ LeaseDuration time.Duration
+ // RenewDeadline is the duration that the acting master will retry
+ // refreshing leadership before giving up.
+ //
+ // Core clients default this value to 10 seconds.
+ RenewDeadline time.Duration
+ // RetryPeriod is the duration the LeaderElector clients should wait
+ // between tries of actions.
+ //
+ // Core clients default this value to 2 seconds.
+ RetryPeriod time.Duration
+
+ // Callbacks are callbacks that are triggered during certain lifecycle
+ // events of the LeaderElector
+ Callbacks LeaderCallbacks
+
+ // WatchDog is the associated health checker
+ // WatchDog may be null if its not needed/configured.
+ WatchDog *HealthzAdaptor
+
+ // ReleaseOnCancel should be set true if the lock should be released
+ // when the run context is cancelled. If you set this to true, you must
+ // ensure all code guarded by this lease has successfully completed
+ // prior to cancelling the context, or you may have two processes
+ // simultaneously acting on the critical path.
+ ReleaseOnCancel bool
+
+ // Name is the name of the resource lock for debugging
+ Name string
+}
+
+// LeaderCallbacks are callbacks that are triggered during certain
+// lifecycle events of the LeaderElector. These are invoked asynchronously.
+//
+// possible future callbacks:
+// * OnChallenge()
+type LeaderCallbacks struct {
+ // OnStartedLeading is called when a LeaderElector client starts leading
+ OnStartedLeading func(context.Context)
+ // OnStoppedLeading is called when a LeaderElector client stops leading
+ OnStoppedLeading func()
+ // OnNewLeader is called when the client observes a leader that is
+ // not the previously observed leader. This includes the first observed
+ // leader when the client starts.
+ OnNewLeader func(identity string)
+}
+
+// LeaderElector is a leader election client.
+type LeaderElector struct {
+ config LeaderElectionConfig
+ // internal bookkeeping
+ observedRecord rl.LeaderElectionRecord
+ observedRawRecord []byte
+ observedTime time.Time
+ // used to implement OnNewLeader(), may lag slightly from the
+ // value observedRecord.HolderIdentity if the transition has
+ // not yet been reported.
+ reportedLeader string
+
+ // clock is wrapper around time to allow for less flaky testing
+ clock clock.Clock
+
+ // used to lock the observedRecord
+ observedRecordLock sync.Mutex
+
+ metrics leaderMetricsAdapter
+}
+
+// Run starts the leader election loop. Run will not return
+// before leader election loop is stopped by ctx or it has
+// stopped holding the leader lease
+func (le *LeaderElector) Run(ctx context.Context) {
+ defer runtime.HandleCrash()
+ defer func() {
+ le.config.Callbacks.OnStoppedLeading()
+ }()
+
+ if !le.acquire(ctx) {
+ return // ctx signalled done
+ }
+ ctx, cancel := context.WithCancel(ctx)
+ defer cancel()
+ go le.config.Callbacks.OnStartedLeading(ctx)
+ le.renew(ctx)
+}
+
+// RunOrDie starts a client with the provided config or panics if the config
+// fails to validate. RunOrDie blocks until leader election loop is
+// stopped by ctx or it has stopped holding the leader lease
+func RunOrDie(ctx context.Context, lec LeaderElectionConfig) {
+ le, err := NewLeaderElector(lec)
+ if err != nil {
+ panic(err)
+ }
+ if lec.WatchDog != nil {
+ lec.WatchDog.SetLeaderElection(le)
+ }
+ le.Run(ctx)
+}
+
+// GetLeader returns the identity of the last observed leader or returns the empty string if
+// no leader has yet been observed.
+// This function is for informational purposes. (e.g. monitoring, logs, etc.)
+func (le *LeaderElector) GetLeader() string {
+ return le.getObservedRecord().HolderIdentity
+}
+
+// IsLeader returns true if the last observed leader was this client else returns false.
+func (le *LeaderElector) IsLeader() bool {
+ return le.getObservedRecord().HolderIdentity == le.config.Lock.Identity()
+}
+
+// acquire loops calling tryAcquireOrRenew and returns true immediately when tryAcquireOrRenew succeeds.
+// Returns false if ctx signals done.
+func (le *LeaderElector) acquire(ctx context.Context) bool {
+ ctx, cancel := context.WithCancel(ctx)
+ defer cancel()
+ succeeded := false
+ desc := le.config.Lock.Describe()
+ klog.Infof("attempting to acquire leader lease %v...", desc)
+ wait.JitterUntil(func() {
+ succeeded = le.tryAcquireOrRenew(ctx)
+ le.maybeReportTransition()
+ if !succeeded {
+ klog.V(4).Infof("failed to acquire lease %v", desc)
+ return
+ }
+ le.config.Lock.RecordEvent("became leader")
+ le.metrics.leaderOn(le.config.Name)
+ klog.Infof("successfully acquired lease %v", desc)
+ cancel()
+ }, le.config.RetryPeriod, JitterFactor, true, ctx.Done())
+ return succeeded
+}
+
+// renew loops calling tryAcquireOrRenew and returns immediately when tryAcquireOrRenew fails or ctx signals done.
+func (le *LeaderElector) renew(ctx context.Context) {
+ ctx, cancel := context.WithCancel(ctx)
+ defer cancel()
+ wait.Until(func() {
+ timeoutCtx, timeoutCancel := context.WithTimeout(ctx, le.config.RenewDeadline)
+ defer timeoutCancel()
+ err := wait.PollImmediateUntil(le.config.RetryPeriod, func() (bool, error) {
+ return le.tryAcquireOrRenew(timeoutCtx), nil
+ }, timeoutCtx.Done())
+
+ le.maybeReportTransition()
+ desc := le.config.Lock.Describe()
+ if err == nil {
+ klog.V(5).Infof("successfully renewed lease %v", desc)
+ return
+ }
+ le.config.Lock.RecordEvent("stopped leading")
+ le.metrics.leaderOff(le.config.Name)
+ klog.Infof("failed to renew lease %v: %v", desc, err)
+ cancel()
+ }, le.config.RetryPeriod, ctx.Done())
+
+ // if we hold the lease, give it up
+ if le.config.ReleaseOnCancel {
+ le.release()
+ }
+}
+
+// release attempts to release the leader lease if we have acquired it.
+func (le *LeaderElector) release() bool {
+ if !le.IsLeader() {
+ return true
+ }
+ now := metav1.Now()
+ leaderElectionRecord := rl.LeaderElectionRecord{
+ LeaderTransitions: le.observedRecord.LeaderTransitions,
+ LeaseDurationSeconds: 1,
+ RenewTime: now,
+ AcquireTime: now,
+ }
+ if err := le.config.Lock.Update(context.TODO(), leaderElectionRecord); err != nil {
+ klog.Errorf("Failed to release lock: %v", err)
+ return false
+ }
+
+ le.setObservedRecord(&leaderElectionRecord)
+ return true
+}
+
+// tryAcquireOrRenew tries to acquire a leader lease if it is not already acquired,
+// else it tries to renew the lease if it has already been acquired. Returns true
+// on success else returns false.
+func (le *LeaderElector) tryAcquireOrRenew(ctx context.Context) bool {
+ now := metav1.Now()
+ leaderElectionRecord := rl.LeaderElectionRecord{
+ HolderIdentity: le.config.Lock.Identity(),
+ LeaseDurationSeconds: int(le.config.LeaseDuration / time.Second),
+ RenewTime: now,
+ AcquireTime: now,
+ }
+
+ // 1. obtain or create the ElectionRecord
+ oldLeaderElectionRecord, oldLeaderElectionRawRecord, err := le.config.Lock.Get(ctx)
+ if err != nil {
+ if !errors.IsNotFound(err) {
+ klog.Errorf("error retrieving resource lock %v: %v", le.config.Lock.Describe(), err)
+ return false
+ }
+ if err = le.config.Lock.Create(ctx, leaderElectionRecord); err != nil {
+ klog.Errorf("error initially creating leader election record: %v", err)
+ return false
+ }
+
+ le.setObservedRecord(&leaderElectionRecord)
+
+ return true
+ }
+
+ // 2. Record obtained, check the Identity & Time
+ if !bytes.Equal(le.observedRawRecord, oldLeaderElectionRawRecord) {
+ le.setObservedRecord(oldLeaderElectionRecord)
+
+ le.observedRawRecord = oldLeaderElectionRawRecord
+ }
+ if len(oldLeaderElectionRecord.HolderIdentity) > 0 &&
+ le.observedTime.Add(le.config.LeaseDuration).After(now.Time) &&
+ !le.IsLeader() {
+ klog.V(4).Infof("lock is held by %v and has not yet expired", oldLeaderElectionRecord.HolderIdentity)
+ return false
+ }
+
+ // 3. We're going to try to update. The leaderElectionRecord is set to it's default
+ // here. Let's correct it before updating.
+ if le.IsLeader() {
+ leaderElectionRecord.AcquireTime = oldLeaderElectionRecord.AcquireTime
+ leaderElectionRecord.LeaderTransitions = oldLeaderElectionRecord.LeaderTransitions
+ } else {
+ leaderElectionRecord.LeaderTransitions = oldLeaderElectionRecord.LeaderTransitions + 1
+ }
+
+ // update the lock itself
+ if err = le.config.Lock.Update(ctx, leaderElectionRecord); err != nil {
+ klog.Errorf("Failed to update lock: %v", err)
+ return false
+ }
+
+ le.setObservedRecord(&leaderElectionRecord)
+ return true
+}
+
+func (le *LeaderElector) maybeReportTransition() {
+ if le.observedRecord.HolderIdentity == le.reportedLeader {
+ return
+ }
+ le.reportedLeader = le.observedRecord.HolderIdentity
+ if le.config.Callbacks.OnNewLeader != nil {
+ go le.config.Callbacks.OnNewLeader(le.reportedLeader)
+ }
+}
+
+// Check will determine if the current lease is expired by more than timeout.
+func (le *LeaderElector) Check(maxTolerableExpiredLease time.Duration) error {
+ if !le.IsLeader() {
+ // Currently not concerned with the case that we are hot standby
+ return nil
+ }
+ // If we are more than timeout seconds after the lease duration that is past the timeout
+ // on the lease renew. Time to start reporting ourselves as unhealthy. We should have
+ // died but conditions like deadlock can prevent this. (See #70819)
+ if le.clock.Since(le.observedTime) > le.config.LeaseDuration+maxTolerableExpiredLease {
+ return fmt.Errorf("failed election to renew leadership on lease %s", le.config.Name)
+ }
+
+ return nil
+}
+
+// setObservedRecord will set a new observedRecord and update observedTime to the current time.
+// Protect critical sections with lock.
+func (le *LeaderElector) setObservedRecord(observedRecord *rl.LeaderElectionRecord) {
+ le.observedRecordLock.Lock()
+ defer le.observedRecordLock.Unlock()
+
+ le.observedRecord = *observedRecord
+ le.observedTime = le.clock.Now()
+}
+
+// getObservedRecord returns observersRecord.
+// Protect critical sections with lock.
+func (le *LeaderElector) getObservedRecord() rl.LeaderElectionRecord {
+ le.observedRecordLock.Lock()
+ defer le.observedRecordLock.Unlock()
+
+ return le.observedRecord
+}
diff --git a/vendor/k8s.io/client-go/tools/leaderelection/metrics.go b/vendor/k8s.io/client-go/tools/leaderelection/metrics.go
new file mode 100644
index 000000000..65917bf88
--- /dev/null
+++ b/vendor/k8s.io/client-go/tools/leaderelection/metrics.go
@@ -0,0 +1,109 @@
+/*
+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 leaderelection
+
+import (
+ "sync"
+)
+
+// This file provides abstractions for setting the provider (e.g., prometheus)
+// of metrics.
+
+type leaderMetricsAdapter interface {
+ leaderOn(name string)
+ leaderOff(name string)
+}
+
+// GaugeMetric represents a single numerical value that can arbitrarily go up
+// and down.
+type SwitchMetric interface {
+ On(name string)
+ Off(name string)
+}
+
+type noopMetric struct{}
+
+func (noopMetric) On(name string) {}
+func (noopMetric) Off(name string) {}
+
+// defaultLeaderMetrics expects the caller to lock before setting any metrics.
+type defaultLeaderMetrics struct {
+ // leader's value indicates if the current process is the owner of name lease
+ leader SwitchMetric
+}
+
+func (m *defaultLeaderMetrics) leaderOn(name string) {
+ if m == nil {
+ return
+ }
+ m.leader.On(name)
+}
+
+func (m *defaultLeaderMetrics) leaderOff(name string) {
+ if m == nil {
+ return
+ }
+ m.leader.Off(name)
+}
+
+type noMetrics struct{}
+
+func (noMetrics) leaderOn(name string) {}
+func (noMetrics) leaderOff(name string) {}
+
+// MetricsProvider generates various metrics used by the leader election.
+type MetricsProvider interface {
+ NewLeaderMetric() SwitchMetric
+}
+
+type noopMetricsProvider struct{}
+
+func (_ noopMetricsProvider) NewLeaderMetric() SwitchMetric {
+ return noopMetric{}
+}
+
+var globalMetricsFactory = leaderMetricsFactory{
+ metricsProvider: noopMetricsProvider{},
+}
+
+type leaderMetricsFactory struct {
+ metricsProvider MetricsProvider
+
+ onlyOnce sync.Once
+}
+
+func (f *leaderMetricsFactory) setProvider(mp MetricsProvider) {
+ f.onlyOnce.Do(func() {
+ f.metricsProvider = mp
+ })
+}
+
+func (f *leaderMetricsFactory) newLeaderMetrics() leaderMetricsAdapter {
+ mp := f.metricsProvider
+ if mp == (noopMetricsProvider{}) {
+ return noMetrics{}
+ }
+ return &defaultLeaderMetrics{
+ leader: mp.NewLeaderMetric(),
+ }
+}
+
+// SetProvider sets the metrics provider for all subsequently created work
+// queues. Only the first call has an effect.
+func SetProvider(metricsProvider MetricsProvider) {
+ globalMetricsFactory.setProvider(metricsProvider)
+}
diff --git a/vendor/k8s.io/client-go/tools/leaderelection/resourcelock/configmaplock.go b/vendor/k8s.io/client-go/tools/leaderelection/resourcelock/configmaplock.go
new file mode 100644
index 000000000..ceb76b9cb
--- /dev/null
+++ b/vendor/k8s.io/client-go/tools/leaderelection/resourcelock/configmaplock.go
@@ -0,0 +1,122 @@
+/*
+Copyright 2017 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 resourcelock
+
+import (
+ "context"
+ "encoding/json"
+ "errors"
+ "fmt"
+
+ "k8s.io/api/core/v1"
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ corev1client "k8s.io/client-go/kubernetes/typed/core/v1"
+)
+
+// TODO: This is almost a exact replica of Endpoints lock.
+// going forwards as we self host more and more components
+// and use ConfigMaps as the means to pass that configuration
+// data we will likely move to deprecate the Endpoints lock.
+
+type ConfigMapLock struct {
+ // ConfigMapMeta should contain a Name and a Namespace of a
+ // ConfigMapMeta object that the LeaderElector will attempt to lead.
+ ConfigMapMeta metav1.ObjectMeta
+ Client corev1client.ConfigMapsGetter
+ LockConfig ResourceLockConfig
+ cm *v1.ConfigMap
+}
+
+// Get returns the election record from a ConfigMap Annotation
+func (cml *ConfigMapLock) Get(ctx context.Context) (*LeaderElectionRecord, []byte, error) {
+ var record LeaderElectionRecord
+ var err error
+ cml.cm, err = cml.Client.ConfigMaps(cml.ConfigMapMeta.Namespace).Get(ctx, cml.ConfigMapMeta.Name, metav1.GetOptions{})
+ if err != nil {
+ return nil, nil, err
+ }
+ if cml.cm.Annotations == nil {
+ cml.cm.Annotations = make(map[string]string)
+ }
+ recordStr, found := cml.cm.Annotations[LeaderElectionRecordAnnotationKey]
+ recordBytes := []byte(recordStr)
+ if found {
+ if err := json.Unmarshal(recordBytes, &record); err != nil {
+ return nil, nil, err
+ }
+ }
+ return &record, recordBytes, nil
+}
+
+// Create attempts to create a LeaderElectionRecord annotation
+func (cml *ConfigMapLock) Create(ctx context.Context, ler LeaderElectionRecord) error {
+ recordBytes, err := json.Marshal(ler)
+ if err != nil {
+ return err
+ }
+ cml.cm, err = cml.Client.ConfigMaps(cml.ConfigMapMeta.Namespace).Create(ctx, &v1.ConfigMap{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: cml.ConfigMapMeta.Name,
+ Namespace: cml.ConfigMapMeta.Namespace,
+ Annotations: map[string]string{
+ LeaderElectionRecordAnnotationKey: string(recordBytes),
+ },
+ },
+ }, metav1.CreateOptions{})
+ return err
+}
+
+// Update will update an existing annotation on a given resource.
+func (cml *ConfigMapLock) Update(ctx context.Context, ler LeaderElectionRecord) error {
+ if cml.cm == nil {
+ return errors.New("configmap not initialized, call get or create first")
+ }
+ recordBytes, err := json.Marshal(ler)
+ if err != nil {
+ return err
+ }
+ if cml.cm.Annotations == nil {
+ cml.cm.Annotations = make(map[string]string)
+ }
+ cml.cm.Annotations[LeaderElectionRecordAnnotationKey] = string(recordBytes)
+ cm, err := cml.Client.ConfigMaps(cml.ConfigMapMeta.Namespace).Update(ctx, cml.cm, metav1.UpdateOptions{})
+ if err != nil {
+ return err
+ }
+ cml.cm = cm
+ return nil
+}
+
+// RecordEvent in leader election while adding meta-data
+func (cml *ConfigMapLock) RecordEvent(s string) {
+ if cml.LockConfig.EventRecorder == nil {
+ return
+ }
+ events := fmt.Sprintf("%v %v", cml.LockConfig.Identity, s)
+ cml.LockConfig.EventRecorder.Eventf(&v1.ConfigMap{ObjectMeta: cml.cm.ObjectMeta}, v1.EventTypeNormal, "LeaderElection", events)
+}
+
+// Describe is used to convert details on current resource lock
+// into a string
+func (cml *ConfigMapLock) Describe() string {
+ return fmt.Sprintf("%v/%v", cml.ConfigMapMeta.Namespace, cml.ConfigMapMeta.Name)
+}
+
+// Identity returns the Identity of the lock
+func (cml *ConfigMapLock) Identity() string {
+ return cml.LockConfig.Identity
+}
diff --git a/vendor/k8s.io/client-go/tools/leaderelection/resourcelock/endpointslock.go b/vendor/k8s.io/client-go/tools/leaderelection/resourcelock/endpointslock.go
new file mode 100644
index 000000000..20b4c94d9
--- /dev/null
+++ b/vendor/k8s.io/client-go/tools/leaderelection/resourcelock/endpointslock.go
@@ -0,0 +1,117 @@
+/*
+Copyright 2016 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 resourcelock
+
+import (
+ "context"
+ "encoding/json"
+ "errors"
+ "fmt"
+
+ "k8s.io/api/core/v1"
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ corev1client "k8s.io/client-go/kubernetes/typed/core/v1"
+)
+
+type EndpointsLock struct {
+ // EndpointsMeta should contain a Name and a Namespace of an
+ // Endpoints object that the LeaderElector will attempt to lead.
+ EndpointsMeta metav1.ObjectMeta
+ Client corev1client.EndpointsGetter
+ LockConfig ResourceLockConfig
+ e *v1.Endpoints
+}
+
+// Get returns the election record from a Endpoints Annotation
+func (el *EndpointsLock) Get(ctx context.Context) (*LeaderElectionRecord, []byte, error) {
+ var record LeaderElectionRecord
+ var err error
+ el.e, err = el.Client.Endpoints(el.EndpointsMeta.Namespace).Get(ctx, el.EndpointsMeta.Name, metav1.GetOptions{})
+ if err != nil {
+ return nil, nil, err
+ }
+ if el.e.Annotations == nil {
+ el.e.Annotations = make(map[string]string)
+ }
+ recordStr, found := el.e.Annotations[LeaderElectionRecordAnnotationKey]
+ recordBytes := []byte(recordStr)
+ if found {
+ if err := json.Unmarshal(recordBytes, &record); err != nil {
+ return nil, nil, err
+ }
+ }
+ return &record, recordBytes, nil
+}
+
+// Create attempts to create a LeaderElectionRecord annotation
+func (el *EndpointsLock) Create(ctx context.Context, ler LeaderElectionRecord) error {
+ recordBytes, err := json.Marshal(ler)
+ if err != nil {
+ return err
+ }
+ el.e, err = el.Client.Endpoints(el.EndpointsMeta.Namespace).Create(ctx, &v1.Endpoints{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: el.EndpointsMeta.Name,
+ Namespace: el.EndpointsMeta.Namespace,
+ Annotations: map[string]string{
+ LeaderElectionRecordAnnotationKey: string(recordBytes),
+ },
+ },
+ }, metav1.CreateOptions{})
+ return err
+}
+
+// Update will update and existing annotation on a given resource.
+func (el *EndpointsLock) Update(ctx context.Context, ler LeaderElectionRecord) error {
+ if el.e == nil {
+ return errors.New("endpoint not initialized, call get or create first")
+ }
+ recordBytes, err := json.Marshal(ler)
+ if err != nil {
+ return err
+ }
+ if el.e.Annotations == nil {
+ el.e.Annotations = make(map[string]string)
+ }
+ el.e.Annotations[LeaderElectionRecordAnnotationKey] = string(recordBytes)
+ e, err := el.Client.Endpoints(el.EndpointsMeta.Namespace).Update(ctx, el.e, metav1.UpdateOptions{})
+ if err != nil {
+ return err
+ }
+ el.e = e
+ return nil
+}
+
+// RecordEvent in leader election while adding meta-data
+func (el *EndpointsLock) RecordEvent(s string) {
+ if el.LockConfig.EventRecorder == nil {
+ return
+ }
+ events := fmt.Sprintf("%v %v", el.LockConfig.Identity, s)
+ el.LockConfig.EventRecorder.Eventf(&v1.Endpoints{ObjectMeta: el.e.ObjectMeta}, v1.EventTypeNormal, "LeaderElection", events)
+}
+
+// Describe is used to convert details on current resource lock
+// into a string
+func (el *EndpointsLock) Describe() string {
+ return fmt.Sprintf("%v/%v", el.EndpointsMeta.Namespace, el.EndpointsMeta.Name)
+}
+
+// Identity returns the Identity of the lock
+func (el *EndpointsLock) Identity() string {
+ return el.LockConfig.Identity
+}
diff --git a/vendor/k8s.io/client-go/tools/leaderelection/resourcelock/interface.go b/vendor/k8s.io/client-go/tools/leaderelection/resourcelock/interface.go
new file mode 100644
index 000000000..bc77c2eda
--- /dev/null
+++ b/vendor/k8s.io/client-go/tools/leaderelection/resourcelock/interface.go
@@ -0,0 +1,161 @@
+/*
+Copyright 2016 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 resourcelock
+
+import (
+ "context"
+ "fmt"
+ clientset "k8s.io/client-go/kubernetes"
+ restclient "k8s.io/client-go/rest"
+ "time"
+
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ "k8s.io/apimachinery/pkg/runtime"
+ coordinationv1 "k8s.io/client-go/kubernetes/typed/coordination/v1"
+ corev1 "k8s.io/client-go/kubernetes/typed/core/v1"
+)
+
+const (
+ LeaderElectionRecordAnnotationKey = "control-plane.alpha.kubernetes.io/leader"
+ EndpointsResourceLock = "endpoints"
+ ConfigMapsResourceLock = "configmaps"
+ LeasesResourceLock = "leases"
+ EndpointsLeasesResourceLock = "endpointsleases"
+ ConfigMapsLeasesResourceLock = "configmapsleases"
+)
+
+// LeaderElectionRecord is the record that is stored in the leader election annotation.
+// This information should be used for observational purposes only and could be replaced
+// with a random string (e.g. UUID) with only slight modification of this code.
+// TODO(mikedanese): this should potentially be versioned
+type LeaderElectionRecord struct {
+ // HolderIdentity is the ID that owns the lease. If empty, no one owns this lease and
+ // all callers may acquire. Versions of this library prior to Kubernetes 1.14 will not
+ // attempt to acquire leases with empty identities and will wait for the full lease
+ // interval to expire before attempting to reacquire. This value is set to empty when
+ // a client voluntarily steps down.
+ HolderIdentity string `json:"holderIdentity"`
+ LeaseDurationSeconds int `json:"leaseDurationSeconds"`
+ AcquireTime metav1.Time `json:"acquireTime"`
+ RenewTime metav1.Time `json:"renewTime"`
+ LeaderTransitions int `json:"leaderTransitions"`
+}
+
+// EventRecorder records a change in the ResourceLock.
+type EventRecorder interface {
+ Eventf(obj runtime.Object, eventType, reason, message string, args ...interface{})
+}
+
+// ResourceLockConfig common data that exists across different
+// resource locks
+type ResourceLockConfig struct {
+ // Identity is the unique string identifying a lease holder across
+ // all participants in an election.
+ Identity string
+ // EventRecorder is optional.
+ EventRecorder EventRecorder
+}
+
+// Interface offers a common interface for locking on arbitrary
+// resources used in leader election. The Interface is used
+// to hide the details on specific implementations in order to allow
+// them to change over time. This interface is strictly for use
+// by the leaderelection code.
+type Interface interface {
+ // Get returns the LeaderElectionRecord
+ Get(ctx context.Context) (*LeaderElectionRecord, []byte, error)
+
+ // Create attempts to create a LeaderElectionRecord
+ Create(ctx context.Context, ler LeaderElectionRecord) error
+
+ // Update will update and existing LeaderElectionRecord
+ Update(ctx context.Context, ler LeaderElectionRecord) error
+
+ // RecordEvent is used to record events
+ RecordEvent(string)
+
+ // Identity will return the locks Identity
+ Identity() string
+
+ // Describe is used to convert details on current resource lock
+ // into a string
+ Describe() string
+}
+
+// Manufacture will create a lock of a given type according to the input parameters
+func New(lockType string, ns string, name string, coreClient corev1.CoreV1Interface, coordinationClient coordinationv1.CoordinationV1Interface, rlc ResourceLockConfig) (Interface, error) {
+ endpointsLock := &EndpointsLock{
+ EndpointsMeta: metav1.ObjectMeta{
+ Namespace: ns,
+ Name: name,
+ },
+ Client: coreClient,
+ LockConfig: rlc,
+ }
+ configmapLock := &ConfigMapLock{
+ ConfigMapMeta: metav1.ObjectMeta{
+ Namespace: ns,
+ Name: name,
+ },
+ Client: coreClient,
+ LockConfig: rlc,
+ }
+ leaseLock := &LeaseLock{
+ LeaseMeta: metav1.ObjectMeta{
+ Namespace: ns,
+ Name: name,
+ },
+ Client: coordinationClient,
+ LockConfig: rlc,
+ }
+ switch lockType {
+ case EndpointsResourceLock:
+ return endpointsLock, nil
+ case ConfigMapsResourceLock:
+ return configmapLock, nil
+ case LeasesResourceLock:
+ return leaseLock, nil
+ case EndpointsLeasesResourceLock:
+ return &MultiLock{
+ Primary: endpointsLock,
+ Secondary: leaseLock,
+ }, nil
+ case ConfigMapsLeasesResourceLock:
+ return &MultiLock{
+ Primary: configmapLock,
+ Secondary: leaseLock,
+ }, nil
+ default:
+ return nil, fmt.Errorf("Invalid lock-type %s", lockType)
+ }
+}
+
+// NewFromKubeconfig will create a lock of a given type according to the input parameters.
+// Timeout set for a client used to contact to Kubernetes should be lower than
+// RenewDeadline to keep a single hung request from forcing a leader loss.
+// Setting it to max(time.Second, RenewDeadline/2) as a reasonable heuristic.
+func NewFromKubeconfig(lockType string, ns string, name string, rlc ResourceLockConfig, kubeconfig *restclient.Config, renewDeadline time.Duration) (Interface, error) {
+ // shallow copy, do not modify the kubeconfig
+ config := *kubeconfig
+ timeout := renewDeadline / 2
+ if timeout < time.Second {
+ timeout = time.Second
+ }
+ config.Timeout = timeout
+ leaderElectionClient := clientset.NewForConfigOrDie(restclient.AddUserAgent(&config, "leader-election"))
+ return New(lockType, ns, name, leaderElectionClient.CoreV1(), leaderElectionClient.CoordinationV1(), rlc)
+}
diff --git a/vendor/k8s.io/client-go/tools/leaderelection/resourcelock/leaselock.go b/vendor/k8s.io/client-go/tools/leaderelection/resourcelock/leaselock.go
new file mode 100644
index 000000000..a40349727
--- /dev/null
+++ b/vendor/k8s.io/client-go/tools/leaderelection/resourcelock/leaselock.go
@@ -0,0 +1,135 @@
+/*
+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 resourcelock
+
+import (
+ "context"
+ "encoding/json"
+ "errors"
+ "fmt"
+
+ coordinationv1 "k8s.io/api/coordination/v1"
+ corev1 "k8s.io/api/core/v1"
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ coordinationv1client "k8s.io/client-go/kubernetes/typed/coordination/v1"
+)
+
+type LeaseLock struct {
+ // LeaseMeta should contain a Name and a Namespace of a
+ // LeaseMeta object that the LeaderElector will attempt to lead.
+ LeaseMeta metav1.ObjectMeta
+ Client coordinationv1client.LeasesGetter
+ LockConfig ResourceLockConfig
+ lease *coordinationv1.Lease
+}
+
+// Get returns the election record from a Lease spec
+func (ll *LeaseLock) Get(ctx context.Context) (*LeaderElectionRecord, []byte, error) {
+ var err error
+ ll.lease, err = ll.Client.Leases(ll.LeaseMeta.Namespace).Get(ctx, ll.LeaseMeta.Name, metav1.GetOptions{})
+ if err != nil {
+ return nil, nil, err
+ }
+ record := LeaseSpecToLeaderElectionRecord(&ll.lease.Spec)
+ recordByte, err := json.Marshal(*record)
+ if err != nil {
+ return nil, nil, err
+ }
+ return record, recordByte, nil
+}
+
+// Create attempts to create a Lease
+func (ll *LeaseLock) Create(ctx context.Context, ler LeaderElectionRecord) error {
+ var err error
+ ll.lease, err = ll.Client.Leases(ll.LeaseMeta.Namespace).Create(ctx, &coordinationv1.Lease{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: ll.LeaseMeta.Name,
+ Namespace: ll.LeaseMeta.Namespace,
+ },
+ Spec: LeaderElectionRecordToLeaseSpec(&ler),
+ }, metav1.CreateOptions{})
+ return err
+}
+
+// Update will update an existing Lease spec.
+func (ll *LeaseLock) Update(ctx context.Context, ler LeaderElectionRecord) error {
+ if ll.lease == nil {
+ return errors.New("lease not initialized, call get or create first")
+ }
+ ll.lease.Spec = LeaderElectionRecordToLeaseSpec(&ler)
+
+ lease, err := ll.Client.Leases(ll.LeaseMeta.Namespace).Update(ctx, ll.lease, metav1.UpdateOptions{})
+ if err != nil {
+ return err
+ }
+
+ ll.lease = lease
+ return nil
+}
+
+// RecordEvent in leader election while adding meta-data
+func (ll *LeaseLock) RecordEvent(s string) {
+ if ll.LockConfig.EventRecorder == nil {
+ return
+ }
+ events := fmt.Sprintf("%v %v", ll.LockConfig.Identity, s)
+ ll.LockConfig.EventRecorder.Eventf(&coordinationv1.Lease{ObjectMeta: ll.lease.ObjectMeta}, corev1.EventTypeNormal, "LeaderElection", events)
+}
+
+// Describe is used to convert details on current resource lock
+// into a string
+func (ll *LeaseLock) Describe() string {
+ return fmt.Sprintf("%v/%v", ll.LeaseMeta.Namespace, ll.LeaseMeta.Name)
+}
+
+// Identity returns the Identity of the lock
+func (ll *LeaseLock) Identity() string {
+ return ll.LockConfig.Identity
+}
+
+func LeaseSpecToLeaderElectionRecord(spec *coordinationv1.LeaseSpec) *LeaderElectionRecord {
+ var r LeaderElectionRecord
+ if spec.HolderIdentity != nil {
+ r.HolderIdentity = *spec.HolderIdentity
+ }
+ if spec.LeaseDurationSeconds != nil {
+ r.LeaseDurationSeconds = int(*spec.LeaseDurationSeconds)
+ }
+ if spec.LeaseTransitions != nil {
+ r.LeaderTransitions = int(*spec.LeaseTransitions)
+ }
+ if spec.AcquireTime != nil {
+ r.AcquireTime = metav1.Time{spec.AcquireTime.Time}
+ }
+ if spec.RenewTime != nil {
+ r.RenewTime = metav1.Time{spec.RenewTime.Time}
+ }
+ return &r
+
+}
+
+func LeaderElectionRecordToLeaseSpec(ler *LeaderElectionRecord) coordinationv1.LeaseSpec {
+ leaseDurationSeconds := int32(ler.LeaseDurationSeconds)
+ leaseTransitions := int32(ler.LeaderTransitions)
+ return coordinationv1.LeaseSpec{
+ HolderIdentity: &ler.HolderIdentity,
+ LeaseDurationSeconds: &leaseDurationSeconds,
+ AcquireTime: &metav1.MicroTime{ler.AcquireTime.Time},
+ RenewTime: &metav1.MicroTime{ler.RenewTime.Time},
+ LeaseTransitions: &leaseTransitions,
+ }
+}
diff --git a/vendor/k8s.io/client-go/tools/leaderelection/resourcelock/multilock.go b/vendor/k8s.io/client-go/tools/leaderelection/resourcelock/multilock.go
new file mode 100644
index 000000000..5ee1dcbb5
--- /dev/null
+++ b/vendor/k8s.io/client-go/tools/leaderelection/resourcelock/multilock.go
@@ -0,0 +1,104 @@
+/*
+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 resourcelock
+
+import (
+ "bytes"
+ "context"
+ "encoding/json"
+
+ apierrors "k8s.io/apimachinery/pkg/api/errors"
+)
+
+const (
+ UnknownLeader = "leaderelection.k8s.io/unknown"
+)
+
+// MultiLock is used for lock's migration
+type MultiLock struct {
+ Primary Interface
+ Secondary Interface
+}
+
+// Get returns the older election record of the lock
+func (ml *MultiLock) Get(ctx context.Context) (*LeaderElectionRecord, []byte, error) {
+ primary, primaryRaw, err := ml.Primary.Get(ctx)
+ if err != nil {
+ return nil, nil, err
+ }
+
+ secondary, secondaryRaw, err := ml.Secondary.Get(ctx)
+ if err != nil {
+ // Lock is held by old client
+ if apierrors.IsNotFound(err) && primary.HolderIdentity != ml.Identity() {
+ return primary, primaryRaw, nil
+ }
+ return nil, nil, err
+ }
+
+ if primary.HolderIdentity != secondary.HolderIdentity {
+ primary.HolderIdentity = UnknownLeader
+ primaryRaw, err = json.Marshal(primary)
+ if err != nil {
+ return nil, nil, err
+ }
+ }
+ return primary, ConcatRawRecord(primaryRaw, secondaryRaw), nil
+}
+
+// Create attempts to create both primary lock and secondary lock
+func (ml *MultiLock) Create(ctx context.Context, ler LeaderElectionRecord) error {
+ err := ml.Primary.Create(ctx, ler)
+ if err != nil && !apierrors.IsAlreadyExists(err) {
+ return err
+ }
+ return ml.Secondary.Create(ctx, ler)
+}
+
+// Update will update and existing annotation on both two resources.
+func (ml *MultiLock) Update(ctx context.Context, ler LeaderElectionRecord) error {
+ err := ml.Primary.Update(ctx, ler)
+ if err != nil {
+ return err
+ }
+ _, _, err = ml.Secondary.Get(ctx)
+ if err != nil && apierrors.IsNotFound(err) {
+ return ml.Secondary.Create(ctx, ler)
+ }
+ return ml.Secondary.Update(ctx, ler)
+}
+
+// RecordEvent in leader election while adding meta-data
+func (ml *MultiLock) RecordEvent(s string) {
+ ml.Primary.RecordEvent(s)
+ ml.Secondary.RecordEvent(s)
+}
+
+// Describe is used to convert details on current resource lock
+// into a string
+func (ml *MultiLock) Describe() string {
+ return ml.Primary.Describe()
+}
+
+// Identity returns the Identity of the lock
+func (ml *MultiLock) Identity() string {
+ return ml.Primary.Identity()
+}
+
+func ConcatRawRecord(primaryRaw, secondaryRaw []byte) []byte {
+ return bytes.Join([][]byte{primaryRaw, secondaryRaw}, []byte(","))
+}
diff --git a/vendor/modules.txt b/vendor/modules.txt
index 4258a76d6..01ec83130 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -541,16 +541,17 @@ github.com/mrunalp/fileutils
github.com/munnerz/goautoneg
# github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f
github.com/mxk/go-flowrate/flowrate
-# github.com/nxadm/tail v1.4.4
+# github.com/nxadm/tail v1.4.8
github.com/nxadm/tail
github.com/nxadm/tail/ratelimiter
github.com/nxadm/tail/util
github.com/nxadm/tail/watch
github.com/nxadm/tail/winfile
-# github.com/onsi/ginkgo v1.14.0
+# github.com/onsi/ginkgo v1.16.4
## explicit
github.com/onsi/ginkgo
github.com/onsi/ginkgo/config
+github.com/onsi/ginkgo/formatter
github.com/onsi/ginkgo/internal/codelocation
github.com/onsi/ginkgo/internal/containernode
github.com/onsi/ginkgo/internal/failer
@@ -568,14 +569,11 @@ github.com/onsi/ginkgo/reporters/stenographer
github.com/onsi/ginkgo/reporters/stenographer/support/go-colorable
github.com/onsi/ginkgo/reporters/stenographer/support/go-isatty
github.com/onsi/ginkgo/types
-# github.com/onsi/gomega v1.10.3
+# github.com/onsi/gomega v1.15.0
## explicit
github.com/onsi/gomega
github.com/onsi/gomega/format
-github.com/onsi/gomega/internal/assertion
-github.com/onsi/gomega/internal/asyncassertion
-github.com/onsi/gomega/internal/oraclematcher
-github.com/onsi/gomega/internal/testingtsupport
+github.com/onsi/gomega/internal
github.com/onsi/gomega/matchers
github.com/onsi/gomega/matchers/support/goraph/bipartitegraph
github.com/onsi/gomega/matchers/support/goraph/edge
@@ -641,6 +639,7 @@ github.com/pmezard/go-difflib/difflib
# github.com/prometheus/client_golang v1.11.0
## explicit
github.com/prometheus/client_golang/prometheus
+github.com/prometheus/client_golang/prometheus/collectors
github.com/prometheus/client_golang/prometheus/internal
github.com/prometheus/client_golang/prometheus/promhttp
github.com/prometheus/client_golang/prometheus/testutil
@@ -802,7 +801,7 @@ go.starlark.net/syntax
go.uber.org/atomic
# go.uber.org/multierr v1.6.0
go.uber.org/multierr
-# go.uber.org/zap v1.17.0
+# go.uber.org/zap v1.19.0
go.uber.org/zap
go.uber.org/zap/buffer
go.uber.org/zap/internal/bufferpool
@@ -903,6 +902,8 @@ golang.org/x/tools/internal/typeparams
# golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1
golang.org/x/xerrors
golang.org/x/xerrors/internal
+# gomodules.xyz/jsonpatch/v2 v2.2.0
+gomodules.xyz/jsonpatch/v2
# google.golang.org/appengine v1.6.7
google.golang.org/appengine/internal
google.golang.org/appengine/internal/base
@@ -1520,6 +1521,7 @@ k8s.io/client-go/listers/scheduling/v1beta1
k8s.io/client-go/listers/storage/v1
k8s.io/client-go/listers/storage/v1alpha1
k8s.io/client-go/listers/storage/v1beta1
+k8s.io/client-go/metadata
k8s.io/client-go/pkg/apis/clientauthentication
k8s.io/client-go/pkg/apis/clientauthentication/install
k8s.io/client-go/pkg/apis/clientauthentication/v1
@@ -1548,6 +1550,8 @@ k8s.io/client-go/tools/clientcmd/api
k8s.io/client-go/tools/clientcmd/api/latest
k8s.io/client-go/tools/clientcmd/api/v1
k8s.io/client-go/tools/events
+k8s.io/client-go/tools/leaderelection
+k8s.io/client-go/tools/leaderelection/resourcelock
k8s.io/client-go/tools/metrics
k8s.io/client-go/tools/pager
k8s.io/client-go/tools/record
@@ -2005,6 +2009,47 @@ sigs.k8s.io/apiserver-network-proxy/proto/header
## explicit
sigs.k8s.io/apiserver-network-proxy/konnectivity-client/pkg/client
sigs.k8s.io/apiserver-network-proxy/konnectivity-client/proto/client
+# sigs.k8s.io/controller-runtime v0.10.3
+## explicit
+sigs.k8s.io/controller-runtime
+sigs.k8s.io/controller-runtime/pkg/builder
+sigs.k8s.io/controller-runtime/pkg/cache
+sigs.k8s.io/controller-runtime/pkg/cache/internal
+sigs.k8s.io/controller-runtime/pkg/certwatcher
+sigs.k8s.io/controller-runtime/pkg/client
+sigs.k8s.io/controller-runtime/pkg/client/apiutil
+sigs.k8s.io/controller-runtime/pkg/client/config
+sigs.k8s.io/controller-runtime/pkg/cluster
+sigs.k8s.io/controller-runtime/pkg/config
+sigs.k8s.io/controller-runtime/pkg/config/v1alpha1
+sigs.k8s.io/controller-runtime/pkg/controller
+sigs.k8s.io/controller-runtime/pkg/controller/controllerutil
+sigs.k8s.io/controller-runtime/pkg/conversion
+sigs.k8s.io/controller-runtime/pkg/event
+sigs.k8s.io/controller-runtime/pkg/handler
+sigs.k8s.io/controller-runtime/pkg/healthz
+sigs.k8s.io/controller-runtime/pkg/internal/controller
+sigs.k8s.io/controller-runtime/pkg/internal/controller/metrics
+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/leaderelection
+sigs.k8s.io/controller-runtime/pkg/log
+sigs.k8s.io/controller-runtime/pkg/manager
+sigs.k8s.io/controller-runtime/pkg/manager/signals
+sigs.k8s.io/controller-runtime/pkg/metrics
+sigs.k8s.io/controller-runtime/pkg/predicate
+sigs.k8s.io/controller-runtime/pkg/ratelimiter
+sigs.k8s.io/controller-runtime/pkg/reconcile
+sigs.k8s.io/controller-runtime/pkg/recorder
+sigs.k8s.io/controller-runtime/pkg/runtime/inject
+sigs.k8s.io/controller-runtime/pkg/scheme
+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/admission
+sigs.k8s.io/controller-runtime/pkg/webhook/conversion
+sigs.k8s.io/controller-runtime/pkg/webhook/internal/metrics
# sigs.k8s.io/kustomize/api v0.8.11
sigs.k8s.io/kustomize/api/builtins
sigs.k8s.io/kustomize/api/filters/annotations
diff --git a/vendor/sigs.k8s.io/controller-runtime/.gitignore b/vendor/sigs.k8s.io/controller-runtime/.gitignore
new file mode 100644
index 000000000..c2c72faf3
--- /dev/null
+++ b/vendor/sigs.k8s.io/controller-runtime/.gitignore
@@ -0,0 +1,24 @@
+# Binaries for programs and plugins
+*.exe
+*.exe~
+*.dll
+*.so
+*.dylib
+
+# Test binary, build with `go test -c`
+*.test
+
+# Output of the go coverage tool, specifically when used with LiteIDE
+*.out
+
+# editor and IDE paraphernalia
+.idea
+*.swp
+*.swo
+*~
+
+# Vscode files
+.vscode
+
+# Tools binaries.
+hack/tools/bin
diff --git a/vendor/sigs.k8s.io/controller-runtime/.golangci.yml b/vendor/sigs.k8s.io/controller-runtime/.golangci.yml
new file mode 100644
index 000000000..a5a5dad61
--- /dev/null
+++ b/vendor/sigs.k8s.io/controller-runtime/.golangci.yml
@@ -0,0 +1,130 @@
+linters:
+ disable-all: true
+ enable:
+ - asciicheck
+ - bodyclose
+ - deadcode
+ - depguard
+ - dogsled
+ - errcheck
+ - exportloopref
+ - goconst
+ - gocritic
+ - gocyclo
+ - godot
+ - gofmt
+ - goimports
+ - goprintffuncname
+ - gosec
+ - gosimple
+ - govet
+ - ifshort
+ - importas
+ - ineffassign
+ - misspell
+ - nakedret
+ - nilerr
+ - nolintlint
+ - prealloc
+ - revive
+ - rowserrcheck
+ - staticcheck
+ - structcheck
+ - stylecheck
+ - typecheck
+ - unconvert
+ - unparam
+ - varcheck
+ - whitespace
+
+linters-settings:
+ ifshort:
+ # Maximum length of variable declaration measured in number of characters, after which linter won't suggest using short syntax.
+ max-decl-chars: 50
+ importas:
+ no-unaliased: true
+ alias:
+ # Kubernetes
+ - pkg: k8s.io/api/core/v1
+ alias: corev1
+ - pkg: k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1
+ alias: apiextensionsv1
+ - pkg: k8s.io/apimachinery/pkg/apis/meta/v1
+ alias: metav1
+ - pkg: k8s.io/apimachinery/pkg/api/errors
+ alias: apierrors
+ - pkg: k8s.io/apimachinery/pkg/util/errors
+ alias: kerrors
+ # Controller Runtime
+ - pkg: sigs.k8s.io/controller-runtime
+ alias: ctrl
+ staticcheck:
+ go: "1.16"
+ stylecheck:
+ go: "1.16"
+
+issues:
+ max-same-issues: 0
+ max-issues-per-linter: 0
+ # We are disabling default golangci exclusions because we want to help reviewers to focus on reviewing the most relevant
+ # changes in PRs and avoid nitpicking.
+ exclude-use-default: false
+ # List of regexps of issue texts to exclude, empty list by default.
+ exclude:
+ # The following are being worked on to remove their exclusion. This list should be reduced or go away all together over time.
+ # If it is decided they will not be addressed they should be moved above this comment.
+ - Subprocess launch(ed with variable|ing should be audited)
+ - (G204|G104|G307)
+ - "ST1000: at least one file in a package should have a package comment"
+ exclude-rules:
+ - linters:
+ - gosec
+ text: "G108: Profiling endpoint is automatically exposed on /debug/pprof"
+ - linters:
+ - revive
+ text: "exported: exported method .*\\.(Reconcile|SetupWithManager|SetupWebhookWithManager) should have comment or be unexported"
+ - linters:
+ - errcheck
+ text: Error return value of .((os\.)?std(out|err)\..*|.*Close|.*Flush|os\.Remove(All)?|.*print(f|ln)?|os\.(Un)?Setenv). is not checked
+ # With Go 1.16, the new embed directive can be used with an un-named import,
+ # revive (previously, golint) only allows these to be imported in a main.go, which wouldn't work for us.
+ # This directive allows the embed package to be imported with an underscore everywhere.
+ - linters:
+ - revive
+ source: _ "embed"
+ # Exclude some packages or code to require comments, for example test code, or fake clients.
+ - linters:
+ - revive
+ text: exported (method|function|type|const) (.+) should have comment or be unexported
+ source: (func|type).*Fake.*
+ - linters:
+ - revive
+ text: exported (method|function|type|const) (.+) should have comment or be unexported
+ path: fake_\.go
+ # Disable unparam "always receives" which might not be really
+ # useful when building libraries.
+ - linters:
+ - unparam
+ text: always receives
+ # Dot imports for gomega or ginkgo are allowed
+ # within test files.
+ - path: _test\.go
+ text: should not use dot imports
+ - path: _test\.go
+ text: cyclomatic complexity
+ - path: _test\.go
+ text: "G107: Potential HTTP request made with variable url"
+ # Append should be able to assign to a different var/slice.
+ - linters:
+ - gocritic
+ text: "appendAssign: append result not assigned to the same slice"
+ - linters:
+ - gocritic
+ text: "singleCaseSwitch: should rewrite switch statement to if statement"
+
+run:
+ timeout: 10m
+ skip-files:
+ - "zz_generated.*\\.go$"
+ - ".*conversion.*\\.go$"
+ allow-parallel-runners: true
diff --git a/vendor/sigs.k8s.io/controller-runtime/CONTRIBUTING.md b/vendor/sigs.k8s.io/controller-runtime/CONTRIBUTING.md
new file mode 100644
index 000000000..2c0ea1f66
--- /dev/null
+++ b/vendor/sigs.k8s.io/controller-runtime/CONTRIBUTING.md
@@ -0,0 +1,19 @@
+# Contributing guidelines
+
+## Sign the CLA
+
+Kubernetes projects require that you sign a Contributor License Agreement (CLA) before we can accept your pull requests.
+
+Please see https://git.k8s.io/community/CLA.md for more info
+
+## Contributing steps
+
+1. Submit an issue describing your proposed change to the repo in question.
+1. The [repo owners](OWNERS) will respond to your issue promptly.
+1. If your proposed change is accepted, and you haven't already done so, sign a Contributor License Agreement (see details above).
+1. Fork the desired repo, develop and test your code changes.
+1. Submit a pull request.
+
+## Test locally
+
+Run the command `make test` to test the changes locally.
diff --git a/vendor/sigs.k8s.io/controller-runtime/FAQ.md b/vendor/sigs.k8s.io/controller-runtime/FAQ.md
new file mode 100644
index 000000000..86c7f9336
--- /dev/null
+++ b/vendor/sigs.k8s.io/controller-runtime/FAQ.md
@@ -0,0 +1,81 @@
+# FAQ
+
+### Q: How do I know which type of object a controller references?
+
+**A**: Each controller should only reconcile one object type. Other
+affected objects should be mapped to a single type of root object, using
+the `EnqueueRequestForOwner` or `EnqueueRequestsFromMapFunc` event
+handlers, and potentially indices. Then, your Reconcile method should
+attempt to reconcile *all* state for that given root objects.
+
+### Q: How do I have different logic in my reconciler for different types of events (e.g. create, update, delete)?
+
+**A**: You should not. Reconcile functions should be idempotent, and
+should always reconcile state by reading all the state it needs, then
+writing updates. This allows your reconciler to correctly respond to
+generic events, adjust to skipped or coalesced events, and easily deal
+with application startup. The controller will enqueue reconcile requests
+for both old and new objects if a mapping changes, but it's your
+responsibility to make sure you have enough information to be able clean
+up state that's no longer referenced.
+
+### Q: My cache might be stale if I read from a cache! How should I deal with that?
+
+**A**: There are several different approaches that can be taken, depending
+on your situation.
+
+- When you can, take advantage of optimistic locking: use deterministic
+ names for objects you create, so that the Kubernetes API server will
+ warn you if the object already exists. Many controllers in Kubernetes
+ take this approach: the StatefulSet controller appends a specific number
+ to each pod that it creates, while the Deployment controller hashes the
+ pod template spec and appends that.
+
+- In the few cases when you cannot take advantage of deterministic names
+ (e.g. when using generateName), it may be useful in to track which
+ actions you took, and assume that they need to be repeated if they don't
+ occur after a given time (e.g. using a requeue result). This is what
+ the ReplicaSet controller does.
+
+In general, write your controller with the assumption that information
+will eventually be correct, but may be slightly out of date. Make sure
+that your reconcile function enforces the entire state of the world each
+time it runs. If none of this works for you, you can always construct
+a client that reads directly from the API server, but this is generally
+considered to be a last resort, and the two approaches above should
+generally cover most circumstances.
+
+### Q: Where's the fake client? How do I use it?
+
+**A**: The fake client
+[exists](https://godoc.org/sigs.k8s.io/controller-runtime/pkg/client/fake),
+but we generally recommend using
+[envtest.Environment](https://godoc.org/sigs.k8s.io/controller-runtime/pkg/envtest#Environment)
+to test against a real API server. In our experience, tests using fake
+clients gradually re-implement poorly-written impressions of a real API
+server, which leads to hard-to-maintain, complex test code.
+
+### Q: How should I write tests? Any suggestions for getting started?
+
+- Use the aforementioned
+ [envtest.Environment](https://godoc.org/sigs.k8s.io/controller-runtime/pkg/envtest#Environment)
+ to spin up a real API server instead of trying to mock one out.
+
+- Structure your tests to check that the state of the world is as you
+ expect it, *not* that a particular set of API calls were made, when
+ working with Kubernetes APIs. This will allow you to more easily
+ refactor and improve the internals of your controllers without changing
+ your tests.
+
+- Remember that any time you're interacting with the API server, changes
+ may have some delay between write time and reconcile time.
+
+### Q: What are these errors about no Kind being registered for a type?
+
+**A**: You're probably missing a fully-set-up Scheme. Schemes record the
+mapping between Go types and group-version-kinds in Kubernetes. In
+general, your application should have its own Scheme containing the types
+from the API groups that it needs (be they Kubernetes types or your own).
+See the [scheme builder
+docs](https://godoc.org/sigs.k8s.io/controller-runtime/pkg/scheme) for
+more information.
diff --git a/vendor/sigs.k8s.io/controller-runtime/LICENSE b/vendor/sigs.k8s.io/controller-runtime/LICENSE
new file mode 100644
index 000000000..8dada3eda
--- /dev/null
+++ b/vendor/sigs.k8s.io/controller-runtime/LICENSE
@@ -0,0 +1,201 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "{}"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright {yyyy} {name of copyright owner}
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/vendor/sigs.k8s.io/controller-runtime/Makefile b/vendor/sigs.k8s.io/controller-runtime/Makefile
new file mode 100644
index 000000000..36647c697
--- /dev/null
+++ b/vendor/sigs.k8s.io/controller-runtime/Makefile
@@ -0,0 +1,123 @@
+#!/usr/bin/env bash
+
+# Copyright 2020 The Kubernetes Authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# If you update this file, please follow
+# https://suva.sh/posts/well-documented-makefiles
+
+## --------------------------------------
+## General
+## --------------------------------------
+
+SHELL:=/usr/bin/env bash
+.DEFAULT_GOAL:=help
+
+# Use GOPROXY environment variable if set
+GOPROXY := $(shell go env GOPROXY)
+ifeq ($(GOPROXY),)
+GOPROXY := https://proxy.golang.org
+endif
+export GOPROXY
+
+# Active module mode, as we use go modules to manage dependencies
+export GO111MODULE=on
+
+# Tools.
+TOOLS_DIR := hack/tools
+TOOLS_BIN_DIR := $(TOOLS_DIR)/bin
+GOLANGCI_LINT := $(abspath $(TOOLS_BIN_DIR)/golangci-lint)
+GO_APIDIFF := $(TOOLS_BIN_DIR)/go-apidiff
+CONTROLLER_GEN := $(TOOLS_BIN_DIR)/controller-gen
+ENVTEST_DIR := $(abspath tools/setup-envtest)
+
+# The help will print out all targets with their descriptions organized bellow their categories. The categories are represented by `##@` and the target descriptions by `##`.
+# The awk commands is responsible to read the entire set of makefiles included in this invocation, looking for lines of the file as xyz: ## something, and then pretty-format the target and help. Then, if there's a line with ##@ something, that gets pretty-printed as a category.
+# More info over the usage of ANSI control characters for terminal formatting: https://en.wikipedia.org/wiki/ANSI_escape_code#SGR_parameters
+# More info over awk command: http://linuxcommand.org/lc3_adv_awk.php
+.PHONY: help
+help: ## Display this help
+ @awk 'BEGIN {FS = ":.*##"; printf "\nUsage:\n make \033[36m<target>\033[0m\n"} /^[a-zA-Z_0-9-]+:.*?##/ { printf " \033[36m%-15s\033[0m %s\n", $$1, $$2 } /^##@/ { printf "\n\033[1m%s\033[0m\n", substr($$0, 5) } ' $(MAKEFILE_LIST)
+
+## --------------------------------------
+## Testing
+## --------------------------------------
+
+.PHONY: test
+test: test-tools ## Run the script check-everything.sh which will check all.
+ TRACE=1 ./hack/check-everything.sh
+
+.PHONY: test-tools
+test-tools: ## tests the tools codebase (setup-envtest)
+ cd tools/setup-envtest && go test ./...
+
+## --------------------------------------
+## Binaries
+## --------------------------------------
+
+$(GO_APIDIFF): $(TOOLS_DIR)/go.mod # Build go-apidiff from tools folder.
+ cd $(TOOLS_DIR) && go build -tags=tools -o bin/go-apidiff github.com/joelanford/go-apidiff
+
+$(CONTROLLER_GEN): $(TOOLS_DIR)/go.mod # Build controller-gen from tools folder.
+ cd $(TOOLS_DIR) && go build -tags=tools -o bin/controller-gen sigs.k8s.io/controller-tools/cmd/controller-gen
+
+$(GOLANGCI_LINT): .github/workflows/golangci-lint.yml # Download golanci-lint using hack script into tools folder.
+ hack/ensure-golangci-lint.sh \
+ -b $(TOOLS_BIN_DIR) \
+ $(shell cat .github/workflows/golangci-lint.yml | grep version | sed 's/.*version: //')
+
+## --------------------------------------
+## Linting
+## --------------------------------------
+
+.PHONY: lint
+lint: $(GOLANGCI_LINT) ## Lint codebase
+ $(GOLANGCI_LINT) run -v $(GOLANGCI_LINT_EXTRA_ARGS)
+ cd tools/setup-envtest; $(GOLANGCI_LINT) run -v $(GOLANGCI_LINT_EXTRA_ARGS)
+
+.PHONY: lint-fix
+lint-fix: $(GOLANGCI_LINT) ## Lint the codebase and run auto-fixers if supported by the linter.
+ GOLANGCI_LINT_EXTRA_ARGS=--fix $(MAKE) lint
+
+## --------------------------------------
+## Generate
+## --------------------------------------
+
+.PHONY: modules
+modules: ## Runs go mod to ensure modules are up to date.
+ go mod tidy
+ cd $(TOOLS_DIR); go mod tidy
+ cd $(ENVTEST_DIR); go mod tidy
+
+.PHONY: generate
+generate: $(CONTROLLER_GEN) ## Runs controller-gen for internal types for config file
+ $(CONTROLLER_GEN) object paths="./pkg/config/v1alpha1/...;./examples/configfile/custom/v1alpha1/..."
+
+## --------------------------------------
+## Cleanup / Verification
+## --------------------------------------
+
+.PHONY: clean
+clean: ## Cleanup.
+ $(MAKE) clean-bin
+
+.PHONY: clean-bin
+clean-bin: ## Remove all generated binaries.
+ rm -rf hack/tools/bin
+
+.PHONY: verify-modules
+verify-modules: modules
+ @if !(git diff --quiet HEAD -- go.sum go.mod); then \
+ echo "go module files are out of date, please run 'make modules'"; exit 1; \
+ fi
diff --git a/vendor/sigs.k8s.io/controller-runtime/OWNERS b/vendor/sigs.k8s.io/controller-runtime/OWNERS
new file mode 100644
index 000000000..4b1fa044b
--- /dev/null
+++ b/vendor/sigs.k8s.io/controller-runtime/OWNERS
@@ -0,0 +1,10 @@
+# See the OWNERS docs: https://git.k8s.io/community/contributors/guide/owners.md
+
+approvers:
+ - controller-runtime-admins
+ - controller-runtime-maintainers
+ - controller-runtime-approvers
+reviewers:
+ - controller-runtime-admins
+ - controller-runtime-reviewers
+ - controller-runtime-approvers
diff --git a/vendor/sigs.k8s.io/controller-runtime/OWNERS_ALIASES b/vendor/sigs.k8s.io/controller-runtime/OWNERS_ALIASES
new file mode 100644
index 000000000..290dcc192
--- /dev/null
+++ b/vendor/sigs.k8s.io/controller-runtime/OWNERS_ALIASES
@@ -0,0 +1,40 @@
+# See the OWNERS docs: https://git.k8s.io/community/contributors/guide/owners.md
+
+aliases:
+ # active folks who can be contacted to perform admin-related
+ # tasks on the repo, or otherwise approve any PRS.
+ controller-runtime-admins:
+ - droot
+ - mengqiy
+ - pwittrock
+
+ # non-admin folks who have write-access and can approve any PRs in the repo
+ controller-runtime-maintainers:
+ - vincepri
+ - joelanford
+
+ # non-admin folks who can approve any PRs in the repo
+ controller-runtime-approvers:
+ - gerred
+ - shawn-hurley
+ - alvaroaleman
+
+ # folks who can review and LGTM any PRs in the repo (doesn't
+ # include approvers & admins -- those count too via the OWNERS
+ # file)
+ controller-runtime-reviewers:
+ - alenkacz
+ - vincepri
+ - alexeldeib
+ - varshaprasad96
+
+ # folks to can approve things in the directly-ported
+ # testing_frameworks portions of the codebase
+ testing-integration-approvers:
+ - apelisse
+ - hoegaarden
+
+ # folks who may have context on ancient history,
+ # but are no longer directly involved
+ controller-runtime-emeritus-maintainers:
+ - directxman12
diff --git a/vendor/sigs.k8s.io/controller-runtime/README.md b/vendor/sigs.k8s.io/controller-runtime/README.md
new file mode 100644
index 000000000..d857d3e76
--- /dev/null
+++ b/vendor/sigs.k8s.io/controller-runtime/README.md
@@ -0,0 +1,66 @@
+[![Go Report Card](https://goreportcard.com/badge/sigs.k8s.io/controller-runtime)](https://goreportcard.com/report/sigs.k8s.io/controller-runtime)
+[![godoc](https://godoc.org/sigs.k8s.io/controller-runtime?status.svg)](https://godoc.org/sigs.k8s.io/controller-runtime)
+
+# Kubernetes controller-runtime Project
+
+The Kubernetes controller-runtime Project is a set of go libraries for building
+Controllers. It is leveraged by [Kubebuilder](https://book.kubebuilder.io/) and
+[Operator SDK](https://github.com/operator-framework/operator-sdk). Both are
+a great place to start for new projects. See
+[Kubebuilder's Quick Start](https://book.kubebuilder.io/quick-start.html) to
+see how it can be used.
+
+Documentation:
+
+- [Package overview](https://pkg.go.dev/sigs.k8s.io/controller-runtime/pkg)
+- [Basic controller using builder](https://pkg.go.dev/sigs.k8s.io/controller-runtime/pkg/builder#example-Builder)
+- [Creating a manager](https://pkg.go.dev/sigs.k8s.io/controller-runtime/pkg/manager#example-New)
+- [Creating a controller](https://pkg.go.dev/sigs.k8s.io/controller-runtime/pkg/controller#example-New)
+- [Examples](https://github.com/kubernetes-sigs/controller-runtime/blob/master/examples)
+- [Designs](https://github.com/kubernetes-sigs/controller-runtime/blob/master/designs)
+
+# Versioning, Maintenance, and Compatibility
+
+The full documentation can be found at [VERSIONING.md](VERSIONING.md), but TL;DR:
+
+Users:
+
+- We follow [Semantic Versioning (semver)](https://semver.org)
+- Use releases with your dependency management to ensure that you get compatible code
+- The master branch contains all the latest code, some of which may break compatibility (so "normal" `go get` is not recommended)
+
+Contributors:
+
+- All code PR must be labeled with :bug: (patch fixes), :sparkles: (backwards-compatible features), or :warning: (breaking changes)
+- Breaking changes will find their way into the next major release, other changes will go into an semi-immediate patch or minor release
+- For a quick PR template suggesting the right information, use one of these PR templates:
+ * [Breaking Changes/Features](/.github/PULL_REQUEST_TEMPLATE/breaking_change.md)
+ * [Backwards-Compatible Features](/.github/PULL_REQUEST_TEMPLATE/compat_feature.md)
+ * [Bug fixes](/.github/PULL_REQUEST_TEMPLATE/bug_fix.md)
+ * [Documentation Changes](/.github/PULL_REQUEST_TEMPLATE/docs.md)
+ * [Test/Build/Other Changes](/.github/PULL_REQUEST_TEMPLATE/other.md)
+
+## FAQ
+
+See [FAQ.md](FAQ.md)
+
+## Community, discussion, contribution, and support
+
+Learn how to engage with the Kubernetes community on the [community page](http://kubernetes.io/community/).
+
+controller-runtime is a subproject of the [kubebuilder](https://github.com/kubernetes-sigs/kubebuilder) project
+in sig apimachinery.
+
+You can reach the maintainers of this project at:
+
+- Slack channel: [#kubebuilder](http://slack.k8s.io/#kubebuilder)
+- Google Group: [kubebuilder@googlegroups.com](https://groups.google.com/forum/#!forum/kubebuilder)
+
+## Contributing
+Contributions are greatly appreciated. The maintainers actively manage the issues list, and try to highlight issues suitable for newcomers.
+The project follows the typical GitHub pull request model. See [CONTRIBUTING.md](CONTRIBUTING.md) for more details.
+Before starting any work, please either comment on an existing issue, or file a new one.
+
+## Code of conduct
+
+Participation in the Kubernetes community is governed by the [Kubernetes Code of Conduct](code-of-conduct.md).
diff --git a/vendor/sigs.k8s.io/controller-runtime/SECURITY_CONTACTS b/vendor/sigs.k8s.io/controller-runtime/SECURITY_CONTACTS
new file mode 100644
index 000000000..32e6a3b90
--- /dev/null
+++ b/vendor/sigs.k8s.io/controller-runtime/SECURITY_CONTACTS
@@ -0,0 +1,14 @@
+# Defined below are the security contacts for this repo.
+#
+# They are the contact point for the Product Security Team to reach out
+# to for triaging and handling of incoming issues.
+#
+# The below names agree to abide by the
+# [Embargo Policy](https://github.com/kubernetes/sig-release/blob/master/security-release-process-documentation/security-release-process.md#embargo-policy)
+# and will be removed and replaced if they violate that agreement.
+#
+# DO NOT REPORT SECURITY VULNERABILITIES DIRECTLY TO THESE NAMES, FOLLOW THE
+# INSTRUCTIONS AT https://kubernetes.io/security/
+
+pwittrock
+droot
diff --git a/vendor/sigs.k8s.io/controller-runtime/TMP-LOGGING.md b/vendor/sigs.k8s.io/controller-runtime/TMP-LOGGING.md
new file mode 100644
index 000000000..b3cfc6651
--- /dev/null
+++ b/vendor/sigs.k8s.io/controller-runtime/TMP-LOGGING.md
@@ -0,0 +1,169 @@
+Logging Guidelines
+==================
+
+controller-runtime uses a kind of logging called *structured logging*. If
+you've used a library like Zap or logrus before, you'll be familiar with
+the concepts we use. If you've only used a logging library like the "log"
+package (in the Go standard library) or "glog" (in Kubernetes), you'll
+need to adjust how you think about logging a bit.
+
+### Getting Started With Structured Logging
+
+With structured logging, we associate a *constant* log message with some
+variable key-value pairs. For instance, suppose we wanted to log that we
+were starting reconciliation on a pod. In the Go standard library logger,
+we might write:
+
+```go
+log.Printf("starting reconciliation for pod %s/%s", podNamespace, podName)
+```
+
+In controller-runtime, we'd instead write:
+
+```go
+logger.Info("starting reconciliation", "pod", req.NamespacedNamed)
+```
+
+or even write
+
+```go
+func (r *Reconciler) Reconcile(req reconcile.Request) (reconcile.Response, error) {
+ logger := logger.WithValues("pod", req.NamespacedName)
+ // do some stuff
+ logger.Info("starting reconciliation")
+}
+```
+
+Notice how we've broken out the information that we want to convey into
+a constant message (`"starting reconciliation"`) and some key-value pairs
+that convey variable information (`"pod", req.NamespacedName`). We've
+there-by added "structure" to our logs, which makes them easier to save
+and search later, as well as correlate with metrics and events.
+
+All of controller-runtime's logging is done via
+[logr](https://github.com/go-logr/logr), a generic interface for
+structured logging. You can use whichever logging library you want to
+implement the actual mechanics of the logging. controller-runtime
+provides some helpers to make it easy to use
+[Zap](https://go.uber.org/zap) as the implementation.
+
+You can configure the logging implementation using
+`"sigs.k8s.io/controller-runtime/pkg/log".SetLogger`. That
+package also contains the convenience functions for setting up Zap.
+
+You can get a handle to the the "root" logger using
+`"sigs.k8s.io/controller-runtime/pkg/log".Log`, and can then call
+`WithName` to create individual named loggers. You can call `WithName`
+repeatedly to chain names together:
+
+```go
+logger := log.Log.WithName("controller").WithName("replicaset")
+// in reconcile...
+logger = logger.WithValues("replicaset", req.NamespacedName)
+// later on in reconcile...
+logger.Info("doing things with pods", "pod", newPod)
+```
+
+As seen above, you can also call `WithValue` to create a new sub-logger
+that always attaches some key-value pairs to a logger.
+
+Finally, you can use `V(1)` to mark a particular log line as "debug" logs:
+
+```go
+logger.V(1).Info("this is particularly verbose!", "state of the world",
+allKubernetesObjectsEverywhere)
+```
+
+While it's possible to use higher log levels, it's recommended that you
+stick with `V(1)` or `V(0)` (which is equivalent to not specifying `V`),
+and then filter later based on key-value pairs or messages; different
+numbers tend to lose meaning easily over time, and you'll be left
+wondering why particular logs lines are at `V(5)` instead of `V(7)`.
+
+## Logging errors
+
+Errors should *always* be logged with `log.Error`, which allows logr
+implementations to provide special handling of errors (for instance,
+providing stack traces in debug mode).
+
+It's acceptable to log call `log.Error` with a nil error object. This
+conveys that an error occurred in some capacity, but that no actual
+`error` object was involved.
+
+Errors returned by the `Reconcile` implementation of the `Reconciler` interface are commonly logged as a `Reconciler error`.
+It's a developer choice to create an additional error log in the `Reconcile` implementation so a more specific file name and line for the error are returned.
+
+## Logging messages
+
+- Don't put variable content in your messages -- use key-value pairs for
+ that. Never use `fmt.Sprintf` in your message.
+
+- Try to match the terminology in your messages with your key-value pairs
+ -- for instance, if you have a key-value pairs `api version`, use the
+ term `APIVersion` instead of `GroupVersion` in your message.
+
+## Logging Kubernetes Objects
+
+Kubernetes objects should be logged directly, like `log.Info("this is
+a Kubernetes object", "pod", somePod)`. controller-runtime provides
+a special encoder for Zap that will transform Kubernetes objects into
+`name, namespace, apiVersion, kind` objects, when available and not in
+development mode. Other logr implementations should implement similar
+logic.
+
+## Logging Structured Values (Key-Value pairs)
+
+- Use lower-case, space separated keys. For example `object` for objects,
+ `api version` for `APIVersion`
+
+- Be consistent across your application, and with controller-runtime when
+ possible.
+
+- Try to be brief but descriptive.
+
+- Match terminology in keys with terminology in the message.
+
+- Be careful logging non-Kubernetes objects verbatim if they're very
+ large.
+
+### Groups, Versions, and Kinds
+
+- Kinds should not be logged alone (they're meaningless alone). Use
+ a `GroupKind` object to log them instead, or a `GroupVersionKind` when
+ version is relevant.
+
+- If you need to log an API version string, use `api version` as the key
+ (formatted as with a `GroupVersion`, or as received directly from API
+ discovery).
+
+### Objects and Types
+
+- If code works with a generic Kubernetes `runtime.Object`, use the
+ `object` key. For specific objects, prefer the resource name as the key
+ (e.g. `pod` for `v1.Pod` objects).
+
+- For non-Kubernetes objects, the `object` key may also be used, if you
+ accept a generic interface.
+
+- When logging a raw type, log it using the `type` key, with a value of
+ `fmt.Sprintf("%T", typ)`
+
+- If there's specific context around a type, the key may be more specific,
+ but should end with `type` -- for instance, `OwnerType` should be logged
+ as `owner` in the context of `log.Error(err, "Could not get ObjectKinds
+ for OwnerType", `owner type`, fmt.Sprintf("%T"))`. When possible, favor
+ communicating kind instead.
+
+### Multiple things
+
+- When logging multiple things, simply pluralize the key.
+
+### controller-runtime Specifics
+
+- Reconcile requests should be logged as `request`, although normal code
+ should favor logging the key.
+
+- Reconcile keys should be logged as with the same key as if you were
+ logging the object directly (e.g. `log.Info("reconciling pod", "pod",
+ req.NamespacedName)`). This ends up having a similar effect to logging
+ the object directly.
diff --git a/vendor/sigs.k8s.io/controller-runtime/VERSIONING.md b/vendor/sigs.k8s.io/controller-runtime/VERSIONING.md
new file mode 100644
index 000000000..18779000e
--- /dev/null
+++ b/vendor/sigs.k8s.io/controller-runtime/VERSIONING.md
@@ -0,0 +1,30 @@
+# Versioning and Branching in controller-runtime
+
+We follow the [common KubeBuilder versioning guidelines][guidelines], and
+use the corresponding tooling.
+
+For the purposes of the aforementioned guidelines, controller-runtime
+counts as a "library project", but otherwise follows the guidelines
+exactly.
+
+[guidelines]: https://sigs.k8s.io/kubebuilder-release-tools/VERSIONING.md
+
+## Compatiblity and Release Support
+
+For release branches, we generally tend to support backporting one (1)
+major release (`release-{X-1}` or `release-0.{Y-1}`), but may go back
+further if the need arises and is very pressing (e.g. security updates).
+
+### Dependency Support
+
+Note the [guidelines on dependency versions][dep-versions]. Particularly:
+
+- We **DO** guarantee Kubernetes REST API compability -- if a given
+ version of controller-runtime stops working with what should be
+ a supported version of Kubernetes, this is almost certainly a bug.
+
+- We **DO NOT** guarantee any particular compability matrix between
+ kubernetes library dependencies (client-go, apimachinery, etc); Such
+ compability is infeasible due to the way those libraries are versioned.
+
+[dep-versions]: https://sigs.k8s.io/kubebuilder-release-tools/VERSIONING.md#kubernetes-version-compatibility
diff --git a/vendor/sigs.k8s.io/controller-runtime/alias.go b/vendor/sigs.k8s.io/controller-runtime/alias.go
new file mode 100644
index 000000000..29f964dcb
--- /dev/null
+++ b/vendor/sigs.k8s.io/controller-runtime/alias.go
@@ -0,0 +1,150 @@
+/*
+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 controllerruntime
+
+import (
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ "k8s.io/apimachinery/pkg/runtime/schema"
+ "sigs.k8s.io/controller-runtime/pkg/builder"
+ "sigs.k8s.io/controller-runtime/pkg/client/config"
+ cfg "sigs.k8s.io/controller-runtime/pkg/config"
+ "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
+ "sigs.k8s.io/controller-runtime/pkg/log"
+ "sigs.k8s.io/controller-runtime/pkg/manager"
+ "sigs.k8s.io/controller-runtime/pkg/manager/signals"
+ "sigs.k8s.io/controller-runtime/pkg/reconcile"
+ "sigs.k8s.io/controller-runtime/pkg/scheme"
+)
+
+// Builder builds an Application ControllerManagedBy (e.g. Operator) and returns a manager.Manager to start it.
+type Builder = builder.Builder
+
+// Request contains the information necessary to reconcile a Kubernetes object. This includes the
+// information to uniquely identify the object - its Name and Namespace. It does NOT contain information about
+// any specific Event or the object contents itself.
+type Request = reconcile.Request
+
+// Result contains the result of a Reconciler invocation.
+type Result = reconcile.Result
+
+// Manager initializes shared dependencies such as Caches and Clients, and provides them to Runnables.
+// A Manager is required to create Controllers.
+type Manager = manager.Manager
+
+// Options are the arguments for creating a new Manager.
+type Options = manager.Options
+
+// SchemeBuilder builds a new Scheme for mapping go types to Kubernetes GroupVersionKinds.
+type SchemeBuilder = scheme.Builder
+
+// GroupVersion contains the "group" and the "version", which uniquely identifies the API.
+type GroupVersion = schema.GroupVersion
+
+// GroupResource specifies a Group and a Resource, but does not force a version. This is useful for identifying
+// concepts during lookup stages without having partially valid types.
+type GroupResource = schema.GroupResource
+
+// TypeMeta describes an individual object in an API response or request
+// with strings representing the type of the object and its API schema version.
+// Structures that are versioned or persisted should inline TypeMeta.
+//
+// +k8s:deepcopy-gen=false
+type TypeMeta = metav1.TypeMeta
+
+// ObjectMeta is metadata that all persisted resources must have, which includes all objects
+// users must create.
+type ObjectMeta = metav1.ObjectMeta
+
+var (
+ // GetConfigOrDie creates a *rest.Config for talking to a Kubernetes apiserver.
+ // If --kubeconfig is set, will use the kubeconfig file at that location. Otherwise will assume running
+ // in cluster and use the cluster provided kubeconfig.
+ //
+ // Will log an error and exit if there is an error creating the rest.Config.
+ GetConfigOrDie = config.GetConfigOrDie
+
+ // GetConfig creates a *rest.Config for talking to a Kubernetes apiserver.
+ // If --kubeconfig is set, will use the kubeconfig file at that location. Otherwise will assume running
+ // in cluster and use the cluster provided kubeconfig.
+ //
+ // Config precedence
+ //
+ // * --kubeconfig flag pointing at a file
+ //
+ // * KUBECONFIG environment variable pointing at a file
+ //
+ // * In-cluster config if running in cluster
+ //
+ // * $HOME/.kube/config if exists.
+ GetConfig = config.GetConfig
+
+ // ConfigFile returns the cfg.File function for deferred config file loading,
+ // this is passed into Options{}.From() to populate the Options fields for
+ // the manager.
+ ConfigFile = cfg.File
+
+ // NewControllerManagedBy returns a new controller builder that will be started by the provided Manager.
+ NewControllerManagedBy = builder.ControllerManagedBy
+
+ // NewWebhookManagedBy returns a new webhook builder that will be started by the provided Manager.
+ NewWebhookManagedBy = builder.WebhookManagedBy
+
+ // NewManager returns a new Manager for creating Controllers.
+ NewManager = manager.New
+
+ // CreateOrUpdate creates or updates the given object obj in the Kubernetes
+ // cluster. The object's desired state should be reconciled with the existing
+ // state using the passed in ReconcileFn. obj must be a struct pointer so that
+ // obj can be updated with the content returned by the Server.
+ //
+ // It returns the executed operation and an error.
+ CreateOrUpdate = controllerutil.CreateOrUpdate
+
+ // SetControllerReference sets owner as a Controller OwnerReference on owned.
+ // This is used for garbage collection of the owned object and for
+ // reconciling the owner object on changes to owned (with a Watch + EnqueueRequestForOwner).
+ // Since only one OwnerReference can be a controller, it returns an error if
+ // there is another OwnerReference with Controller flag set.
+ SetControllerReference = controllerutil.SetControllerReference
+
+ // SetupSignalHandler registered for SIGTERM and SIGINT. A stop channel is returned
+ // which is closed on one of these signals. If a second signal is caught, the program
+ // is terminated with exit code 1.
+ SetupSignalHandler = signals.SetupSignalHandler
+
+ // Log is the base logger used by controller-runtime. It delegates
+ // to another logr.Logger. You *must* call SetLogger to
+ // get any actual logging.
+ Log = log.Log
+
+ // LoggerFrom returns a logger with predefined values from a context.Context.
+ // The logger, when used with controllers, can be expected to contain basic information about the object
+ // that's being reconciled like:
+ // - `reconciler group` and `reconciler kind` coming from the For(...) object passed in when building a controller.
+ // - `name` and `namespace` injected from the reconciliation request.
+ //
+ // This is meant to be used with the context supplied in a struct that satisfies the Reconciler interface.
+ LoggerFrom = log.FromContext
+
+ // LoggerInto takes a context and sets the logger as one of its keys.
+ //
+ // This is meant to be used in reconcilers to enrich the logger within a context with additional values.
+ LoggerInto = log.IntoContext
+
+ // SetLogger sets a concrete logging implementation for all deferred Loggers.
+ SetLogger = log.SetLogger
+)
diff --git a/vendor/sigs.k8s.io/controller-runtime/code-of-conduct.md b/vendor/sigs.k8s.io/controller-runtime/code-of-conduct.md
new file mode 100644
index 000000000..0d15c00cf
--- /dev/null
+++ b/vendor/sigs.k8s.io/controller-runtime/code-of-conduct.md
@@ -0,0 +1,3 @@
+# Kubernetes Community Code of Conduct
+
+Please refer to our [Kubernetes Community Code of Conduct](https://git.k8s.io/community/code-of-conduct.md)
diff --git a/vendor/sigs.k8s.io/controller-runtime/doc.go b/vendor/sigs.k8s.io/controller-runtime/doc.go
new file mode 100644
index 000000000..429eb129f
--- /dev/null
+++ b/vendor/sigs.k8s.io/controller-runtime/doc.go
@@ -0,0 +1,127 @@
+/*
+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 controllerruntime provides tools to construct Kubernetes-style
+// controllers that manipulate both Kubernetes CRDs and aggregated/built-in
+// Kubernetes APIs.
+//
+// It defines easy helpers for the common use cases when building CRDs, built
+// on top of customizable layers of abstraction. Common cases should be easy,
+// and uncommon cases should be possible. In general, controller-runtime tries
+// to guide users towards Kubernetes controller best-practices.
+//
+// Getting Started
+//
+// The main entrypoint for controller-runtime is this root package, which
+// contains all of the common types needed to get started building controllers:
+// import (
+// ctrl "sigs.k8s.io/controller-runtime"
+// )
+//
+// The examples in this package walk through a basic controller setup. The
+// kubebuilder book (https://book.kubebuilder.io) has some more in-depth
+// walkthroughs.
+//
+// controller-runtime favors structs with sane defaults over constructors, so
+// it's fairly common to see structs being used directly in controller-runtime.
+//
+// Organization
+//
+// A brief-ish walkthrough of the layout of this library can be found below. Each
+// package contains more information about how to use it.
+//
+// Frequently asked questions about using controller-runtime and designing
+// controllers can be found at
+// https://github.com/kubernetes-sigs/controller-runtime/blob/master/FAQ.md.
+//
+// Managers
+//
+// Every controller and webhook is ultimately run by a Manager (pkg/manager). A
+// manager is responsible for running controllers and webhooks, and setting up
+// common dependencies (pkg/runtime/inject), like shared caches and clients, as
+// well as managing leader election (pkg/leaderelection). Managers are
+// generally configured to gracefully shut down controllers on pod termination
+// by wiring up a signal handler (pkg/manager/signals).
+//
+// Controllers
+//
+// Controllers (pkg/controller) use events (pkg/event) to eventually trigger
+// reconcile requests. They may be constructed manually, but are often
+// constructed with a Builder (pkg/builder), which eases the wiring of event
+// sources (pkg/source), like Kubernetes API object changes, to event handlers
+// (pkg/handler), like "enqueue a reconcile request for the object owner".
+// Predicates (pkg/predicate) can be used to filter which events actually
+// trigger reconciles. There are pre-written utilities for the common cases, and
+// interfaces and helpers for advanced cases.
+//
+// Reconcilers
+//
+// Controller logic is implemented in terms of Reconcilers (pkg/reconcile). A
+// Reconciler implements a function which takes a reconcile Request containing
+// the name and namespace of the object to reconcile, reconciles the object,
+// and returns a Response or an error indicating whether to requeue for a
+// second round of processing.
+//
+// Clients and Caches
+//
+// Reconcilers use Clients (pkg/client) to access API objects. The default
+// client provided by the manager reads from a local shared cache (pkg/cache)
+// and writes directly to the API server, but clients can be constructed that
+// only talk to the API server, without a cache. The Cache will auto-populate
+// with watched objects, as well as when other structured objects are
+// requested. The default split client does not promise to invalidate the cache
+// during writes (nor does it promise sequential create/get coherence), and code
+// should not assume a get immediately following a create/update will return
+// the updated resource. Caches may also have indexes, which can be created via
+// a FieldIndexer (pkg/client) obtained from the manager. Indexes can used to
+// quickly and easily look up all objects with certain fields set. Reconcilers
+// may retrieve event recorders (pkg/recorder) to emit events using the
+// manager.
+//
+// Schemes
+//
+// Clients, Caches, and many other things in Kubernetes use Schemes
+// (pkg/scheme) to associate Go types to Kubernetes API Kinds
+// (Group-Version-Kinds, to be specific).
+//
+// Webhooks
+//
+// Similarly, webhooks (pkg/webhook/admission) may be implemented directly, but
+// are often constructed using a builder (pkg/webhook/admission/builder). They
+// are run via a server (pkg/webhook) which is managed by a Manager.
+//
+// Logging and Metrics
+//
+// Logging (pkg/log) in controller-runtime is done via structured logs, using a
+// log set of interfaces called logr
+// (https://godoc.org/github.com/go-logr/logr). While controller-runtime
+// provides easy setup for using Zap (https://go.uber.org/zap, pkg/log/zap),
+// you can provide any implementation of logr as the base logger for
+// controller-runtime.
+//
+// Metrics (pkg/metrics) provided by controller-runtime are registered into a
+// controller-runtime-specific Prometheus metrics registry. The manager can
+// serve these by an HTTP endpoint, and additional metrics may be registered to
+// this Registry as normal.
+//
+// Testing
+//
+// You can easily build integration and unit tests for your controllers and
+// webhooks using the test Environment (pkg/envtest). This will automatically
+// stand up a copy of etcd and kube-apiserver, and provide the correct options
+// to connect to the API server. It's designed to work well with the Ginkgo
+// testing framework, but should work with any testing setup.
+package controllerruntime
diff --git a/vendor/sigs.k8s.io/controller-runtime/go.mod b/vendor/sigs.k8s.io/controller-runtime/go.mod
new file mode 100644
index 000000000..fabf9b8f6
--- /dev/null
+++ b/vendor/sigs.k8s.io/controller-runtime/go.mod
@@ -0,0 +1,28 @@
+module sigs.k8s.io/controller-runtime
+
+go 1.16
+
+require (
+ github.com/evanphx/json-patch v4.11.0+incompatible
+ github.com/fsnotify/fsnotify v1.4.9
+ github.com/go-logr/logr v0.4.0
+ github.com/go-logr/zapr v0.4.0
+ github.com/imdario/mergo v0.3.12 // indirect
+ github.com/onsi/ginkgo v1.16.4
+ github.com/onsi/gomega v1.15.0
+ github.com/prometheus/client_golang v1.11.0
+ github.com/prometheus/client_model v0.2.0
+ go.uber.org/goleak v1.1.10
+ go.uber.org/zap v1.19.0
+ golang.org/x/sys v0.0.0-20210817190340-bfb29a6856f2
+ golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac
+ gomodules.xyz/jsonpatch/v2 v2.2.0
+ google.golang.org/appengine v1.6.7 // indirect
+ k8s.io/api v0.22.2
+ k8s.io/apiextensions-apiserver v0.22.2
+ k8s.io/apimachinery v0.22.2
+ k8s.io/client-go v0.22.2
+ k8s.io/component-base v0.22.2
+ k8s.io/utils v0.0.0-20210819203725-bdf08cb9a70a
+ sigs.k8s.io/yaml v1.2.0
+)
diff --git a/vendor/sigs.k8s.io/controller-runtime/go.sum b/vendor/sigs.k8s.io/controller-runtime/go.sum
new file mode 100644
index 000000000..293f15d33
--- /dev/null
+++ b/vendor/sigs.k8s.io/controller-runtime/go.sum
@@ -0,0 +1,769 @@
+cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
+cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
+cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
+cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
+cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
+cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
+cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
+cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To=
+cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4=
+cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M=
+cloud.google.com/go v0.54.0 h1:3ithwDMr7/3vpAMXiH+ZQnYbuIsh+OPhUPMFC9enmn0=
+cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc=
+cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
+cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
+cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
+cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
+cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
+cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk=
+cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
+cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
+cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=
+cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
+cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=
+cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=
+dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
+github.com/Azure/go-ansiterm v0.0.0-20210608223527-2377c96fe795/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8=
+github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
+github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
+github.com/Azure/go-autorest/autorest v0.11.18/go.mod h1:dSiJPy22c3u0OtOKDNttNgqpNFY/GeWa7GH/Pz56QRA=
+github.com/Azure/go-autorest/autorest/adal v0.9.13/go.mod h1:W/MM4U6nLxnIskrw4UwWzlHfGjwUS50aOsc/I3yuU8M=
+github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74=
+github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k=
+github.com/Azure/go-autorest/logger v0.2.1/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8=
+github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU=
+github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
+github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
+github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ=
+github.com/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMomdKFjzJNB0c=
+github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
+github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
+github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
+github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
+github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
+github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
+github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
+github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
+github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
+github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
+github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
+github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
+github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
+github.com/benbjohnson/clock v1.0.3/go.mod h1:bGMdMPoPVvcYyt1gHDf4J2KE153Yf9BuiUKYMaxlTDM=
+github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8=
+github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
+github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
+github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
+github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
+github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
+github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
+github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84=
+github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
+github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
+github.com/certifi/gocertifi v0.0.0-20191021191039-0944d244cd40/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA=
+github.com/certifi/gocertifi v0.0.0-20200922220541-2c3bb06c6054/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA=
+github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
+github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
+github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY=
+github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
+github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
+github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
+github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
+github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
+github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
+github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
+github.com/cockroachdb/datadriven v0.0.0-20200714090401-bf6692d28da5/go.mod h1:h6jFvWxBdQXxjopDMZyH2UVceIRfR84bdzbkoKrsWNo=
+github.com/cockroachdb/errors v1.2.4/go.mod h1:rQD95gz6FARkaKkQXUksEje/d9a6wBJoCr5oaCLELYA=
+github.com/cockroachdb/logtags v0.0.0-20190617123548-eb05cc24525f/go.mod h1:i/u985jwjWRlyHXQbwatDASoW0RMlZ/3i9yJHE2xLkI=
+github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
+github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
+github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc=
+github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
+github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
+github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
+github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
+github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
+github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
+github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
+github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
+github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
+github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
+github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE=
+github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
+github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc=
+github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
+github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
+github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
+github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
+github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
+github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
+github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
+github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
+github.com/evanphx/json-patch v0.5.2/go.mod h1:ZWS5hhDbVDyob71nXKNL0+PWn6ToqBHMikGIFbs31qQ=
+github.com/evanphx/json-patch v4.11.0+incompatible h1:glyUF9yIYtMHzn8xaKw5rMhdWcwsYV8dZHIq5567/xs=
+github.com/evanphx/json-patch v4.11.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
+github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
+github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
+github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k=
+github.com/form3tech-oss/jwt-go v3.2.3+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k=
+github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
+github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
+github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
+github.com/getsentry/raven-go v0.2.0/go.mod h1:KungGk8q33+aIAZUIVWZDr2OfAEBsO49PX4NzFV5kcQ=
+github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
+github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
+github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
+github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
+github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
+github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
+github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=
+github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
+github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
+github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
+github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas=
+github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU=
+github.com/go-logr/logr v0.4.0 h1:K7/B1jt6fIBQVd4Owv2MqGQClcgf0R266+7C/QjRcLc=
+github.com/go-logr/logr v0.4.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU=
+github.com/go-logr/zapr v0.4.0 h1:uc1uML3hRYL9/ZZPdgHS/n8Nzo+eaYL/Efxkkamf7OM=
+github.com/go-logr/zapr v0.4.0/go.mod h1:tabnROwaDl0UNxkVeFRbY8bwB37GwRv0P8lg6aAiEnk=
+github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
+github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
+github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8=
+github.com/go-openapi/jsonreference v0.19.5/go.mod h1:RdybgQwPxbL4UEjuAruzK1x3nE69AqPYEJeo/TWfEeg=
+github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
+github.com/go-openapi/swag v0.19.14/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ=
+github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
+github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
+github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
+github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
+github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
+github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
+github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
+github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
+github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
+github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
+github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
+github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
+github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
+github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
+github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
+github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
+github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
+github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
+github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
+github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
+github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
+github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
+github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
+github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
+github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
+github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
+github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
+github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
+github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
+github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
+github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
+github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM=
+github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
+github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
+github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
+github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
+github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA=
+github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
+github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
+github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
+github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
+github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
+github.com/google/gofuzz v1.1.0 h1:Hsa8mG0dQ46ij8Sl2AYJDUv1oA9/d6Vk+3LG99Oe02g=
+github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
+github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
+github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
+github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
+github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
+github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
+github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
+github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
+github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y=
+github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
+github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
+github.com/googleapis/gnostic v0.5.1/go.mod h1:6U4PtQXGIEt/Z3h5MAT7FNofLnw9vXk2cUuW7uA/OeU=
+github.com/googleapis/gnostic v0.5.5 h1:9fHAtK0uDfpveeqqo1hkEZJcFvYXAiCN3UutL8F9xHw=
+github.com/googleapis/gnostic v0.5.5/go.mod h1:7+EbHbldMins07ALC74bsA81Ovc97DwqyJO1AENw9kA=
+github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
+github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
+github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
+github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
+github.com/grpc-ecosystem/go-grpc-middleware v1.3.0/go.mod h1:z0ButlSOZa5vEBq9m2m2hlwIgKw+rp3sdCBRoJY+30Y=
+github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
+github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
+github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
+github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q=
+github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
+github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
+github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
+github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
+github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
+github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
+github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU=
+github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
+github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
+github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
+github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
+github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=
+github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
+github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
+github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
+github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
+github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ=
+github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
+github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
+github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
+github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
+github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
+github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU=
+github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
+github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
+github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
+github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
+github.com/jonboulle/clockwork v0.2.2/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8=
+github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
+github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
+github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
+github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
+github.com/json-iterator/go v1.1.11 h1:uVUAXhF2To8cbw/3xN3pxj6kk7TYKs98NIrTqPlMWAQ=
+github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
+github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
+github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
+github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
+github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
+github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
+github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
+github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
+github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
+github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
+github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
+github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
+github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
+github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
+github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
+github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
+github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
+github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
+github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
+github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
+github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
+github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
+github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
+github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
+github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
+github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
+github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 h1:I0XW9+e1XWDxdcEniV4rQAIOPUGDq67JSCiRCgGCZLI=
+github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
+github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
+github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
+github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
+github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
+github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
+github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg=
+github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
+github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
+github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
+github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c=
+github.com/moby/term v0.0.0-20210610120745-9d4ed1856297/go.mod h1:vgPCkQMyxTZ7IDy8SXRufE172gr8+K/JE/7hHFxHW3A=
+github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
+github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
+github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
+github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
+github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI=
+github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
+github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
+github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
+github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
+github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
+github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw=
+github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
+github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
+github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
+github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
+github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
+github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
+github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
+github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
+github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
+github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY=
+github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc=
+github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
+github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
+github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
+github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
+github.com/onsi/gomega v1.15.0 h1:WjP/FQ/sk43MRmnEcT+MlDw2TFvkrXlprrPST/IudjU=
+github.com/onsi/gomega v1.15.0/go.mod h1:cIuvLEne0aoVhAgh/O6ac0Op8WWw9H6eYCriF+tEHG0=
+github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
+github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
+github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
+github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
+github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
+github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
+github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
+github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA=
+github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
+github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso=
+github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
+github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=
+github.com/prometheus/client_golang v1.11.0 h1:HNkLOAEQMIDv/K+04rukrLx6ch7msSRwf3/SASFAGtQ=
+github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0=
+github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
+github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
+github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
+github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M=
+github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
+github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
+github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
+github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
+github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=
+github.com/prometheus/common v0.26.0 h1:iMAkS2TDoNWnKM+Kopnx/8tnEStIfpYA0ur0xQzzhMQ=
+github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc=
+github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
+github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
+github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
+github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
+github.com/prometheus/procfs v0.6.0 h1:mxy4L2jP6qMonqmq+aTtOx1ifVWUgG/TAmntgbh3xv4=
+github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
+github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
+github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
+github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
+github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
+github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
+github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
+github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
+github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
+github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
+github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
+github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
+github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
+github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
+github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
+github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
+github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
+github.com/soheilhy/cmux v0.1.5/go.mod h1:T7TcVDs9LWfQgPlPsdngu6I6QIoyIFZDDC6sNE1GqG0=
+github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
+github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
+github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
+github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
+github.com/spf13/cobra v1.1.3/go.mod h1:pGADOWyqRD/YMrPZigI/zbliZ2wVD/23d+is3pSWzOo=
+github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
+github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
+github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
+github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
+github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
+github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg=
+github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8=
+github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
+github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
+github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
+github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
+github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
+github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
+github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
+github.com/tmc/grpc-websocket-proxy v0.0.0-20201229170055-e5319fda7802/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
+github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
+github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
+github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
+github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
+go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
+go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4=
+go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs=
+go.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g=
+go.etcd.io/etcd/client/v2 v2.305.0/go.mod h1:h9puh54ZTgAKtEbut2oe9P4L/oqKCVB6xsXlzd7alYQ=
+go.etcd.io/etcd/client/v3 v3.5.0/go.mod h1:AIKXXVX/DQXtfTEqBryiLTUXwON+GuvO6Z7lLS/oTh0=
+go.etcd.io/etcd/pkg/v3 v3.5.0/go.mod h1:UzJGatBQ1lXChBkQF0AuAtkRQMYnHubxAEYIrC3MSsE=
+go.etcd.io/etcd/raft/v3 v3.5.0/go.mod h1:UFOHSIvO/nKwd4lhkwabrTD3cqW5yVyYYf/KlD00Szc=
+go.etcd.io/etcd/server/v3 v3.5.0/go.mod h1:3Ah5ruV+M+7RZr0+Y/5mNLwC+eQlni+mQmOVdCRJoS4=
+go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
+go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
+go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
+go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
+go.opentelemetry.io/contrib v0.20.0/go.mod h1:G/EtFaa6qaN7+LxqfIAT3GiZa7Wv5DTBUzl5H4LY0Kc=
+go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.20.0/go.mod h1:oVGt1LRbBOBq1A5BQLlUg9UaU/54aiHw8cgjV3aWZ/E=
+go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.20.0/go.mod h1:2AboqHi0CiIZU0qwhtUfCYD1GeUzvvIXWNkhDt7ZMG4=
+go.opentelemetry.io/otel v0.20.0/go.mod h1:Y3ugLH2oa81t5QO+Lty+zXf8zC9L26ax4Nzoxm/dooo=
+go.opentelemetry.io/otel/exporters/otlp v0.20.0/go.mod h1:YIieizyaN77rtLJra0buKiNBOm9XQfkPEKBeuhoMwAM=
+go.opentelemetry.io/otel/metric v0.20.0/go.mod h1:598I5tYlH1vzBjn+BTuhzTCSb/9debfNp6R3s7Pr1eU=
+go.opentelemetry.io/otel/oteltest v0.20.0/go.mod h1:L7bgKf9ZB7qCwT9Up7i9/pn0PWIa9FqQ2IQ8LoxiGnw=
+go.opentelemetry.io/otel/sdk v0.20.0/go.mod h1:g/IcepuwNsoiX5Byy2nNV0ySUF1em498m7hBWC279Yc=
+go.opentelemetry.io/otel/sdk/export/metric v0.20.0/go.mod h1:h7RBNMsDJ5pmI1zExLi+bJK+Dr8NQCh0qGhm1KDnNlE=
+go.opentelemetry.io/otel/sdk/metric v0.20.0/go.mod h1:knxiS8Xd4E/N+ZqKmUPf3gTTZ4/0TjTXukfxjzSTpHE=
+go.opentelemetry.io/otel/trace v0.20.0/go.mod h1:6GjCW8zgDjwGHGa6GkyeB8+/5vjT16gUEi0Nf1iBdgw=
+go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
+go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
+go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=
+go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
+go.uber.org/goleak v1.1.10 h1:z+mqJhf6ss6BSfSM671tgKyZBFPTTJM+HLxnhPC3wu0=
+go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A=
+go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
+go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4=
+go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
+go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
+go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo=
+go.uber.org/zap v1.19.0 h1:mZQZefskPPCMIBCSEH0v2/iUqqLrYtaeqwD6FUGUnFE=
+go.uber.org/zap v1.19.0/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI=
+golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
+golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
+golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
+golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
+golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
+golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
+golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
+golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
+golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
+golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
+golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
+golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
+golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
+golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
+golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
+golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
+golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
+golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
+golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
+golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
+golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
+golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 h1:VLliZ0d+/avPrXXH+OakdXhpJuEoBZuwh1m2j7U6Iug=
+golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
+golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
+golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
+golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
+golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
+golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
+golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
+golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
+golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
+golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
+golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
+golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
+golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
+golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
+golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
+golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
+golang.org/x/net v0.0.0-20210520170846-37e1c6afe023 h1:ADo5wSpq2gqaCGQWzk7S5vd//0iyyLeAratkEoG5dLE=
+golang.org/x/net v0.0.0-20210520170846-37e1c6afe023/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
+golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
+golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
+golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
+golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
+golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d h1:TzXSXBo42m9gQenoE3b9BGiEpg5IG2JkU5FkPIawgtw=
+golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
+golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200831180312-196b9ba8737a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20210817190340-bfb29a6856f2 h1:c8PlLMqBbOHoqtjteWm5/kbe6rNY2pbRfbIMVnepueo=
+golang.org/x/sys v0.0.0-20210817190340-bfb29a6856f2/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
+golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
+golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d h1:SZxvLBoTP5yHO3Frd4z4vrF+DBX9vMVanchswa69toE=
+golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
+golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
+golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M=
+golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac h1:7zkz7BUtwNFFqcowJ+RIgu2MaV/MapERkDIy+mwPyjs=
+golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
+golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
+golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
+golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
+golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
+golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
+golang.org/x/tools v0.0.0-20190624222133-a101b041ded4/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
+golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
+golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
+golang.org/x/tools v0.0.0-20200505023115-26f46d2f7ef8/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
+golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
+golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
+golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
+golang.org/x/tools v0.1.2 h1:kRBLX7v7Af8W7Gdbbc908OJcdgtK8bOz9Uaj8/F1ACA=
+golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
+golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
+golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+gomodules.xyz/jsonpatch/v2 v2.2.0 h1:4pT439QV83L+G9FkcCriY6EkpcK6r6bK+A5FBUMI7qY=
+gomodules.xyz/jsonpatch/v2 v2.2.0/go.mod h1:WXp+iVDkoLQqPudfQ9GBlwB2eZ5DKOnjQZCYdOS8GPY=
+google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
+google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
+google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
+google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
+google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
+google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
+google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
+google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
+google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
+google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
+google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
+google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
+google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
+google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
+google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
+google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c=
+google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
+google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
+google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
+google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
+google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
+google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
+google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
+google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
+google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
+google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA=
+google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
+google.golang.org/genproto v0.0.0-20201019141844-1ed22bb0c154/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=
+google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
+google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
+google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
+google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
+google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
+google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
+google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
+google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
+google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
+google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
+google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
+google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
+google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
+google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
+google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
+google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
+google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
+google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
+google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
+google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
+google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
+google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
+google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
+google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
+google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk=
+google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
+gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
+gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
+gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
+gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
+gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
+gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
+gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k=
+gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
+gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
+gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
+gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
+gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
+gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
+gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
+gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
+gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk=
+gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8=
+honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
+honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
+k8s.io/api v0.22.2 h1:M8ZzAD0V6725Fjg53fKeTJxGsJvRbk4TEm/fexHMtfw=
+k8s.io/api v0.22.2/go.mod h1:y3ydYpLJAaDI+BbSe2xmGcqxiWHmWjkEeIbiwHvnPR8=
+k8s.io/apiextensions-apiserver v0.22.2 h1:zK7qI8Ery7j2CaN23UCFaC1hj7dMiI87n01+nKuewd4=
+k8s.io/apiextensions-apiserver v0.22.2/go.mod h1:2E0Ve/isxNl7tWLSUDgi6+cmwHi5fQRdwGVCxbC+KFA=
+k8s.io/apimachinery v0.22.2 h1:ejz6y/zNma8clPVfNDLnPbleBo6MpoFy/HBiBqCouVk=
+k8s.io/apimachinery v0.22.2/go.mod h1:O3oNtNadZdeOMxHFVxOreoznohCpy0z6mocxbZr7oJ0=
+k8s.io/apiserver v0.22.2/go.mod h1:vrpMmbyjWrgdyOvZTSpsusQq5iigKNWv9o9KlDAbBHI=
+k8s.io/client-go v0.22.2 h1:DaSQgs02aCC1QcwUdkKZWOeaVsQjYvWv8ZazcZ6JcHc=
+k8s.io/client-go v0.22.2/go.mod h1:sAlhrkVDf50ZHx6z4K0S40wISNTarf1r800F+RlCF6U=
+k8s.io/code-generator v0.22.2/go.mod h1:eV77Y09IopzeXOJzndrDyCI88UBok2h6WxAlBwpxa+o=
+k8s.io/component-base v0.22.2 h1:vNIvE0AIrLhjX8drH0BgCNJcR4QZxMXcJzBsDplDx9M=
+k8s.io/component-base v0.22.2/go.mod h1:5Br2QhI9OTe79p+TzPe9JKNQYvEKbq9rTJDWllunGug=
+k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0=
+k8s.io/gengo v0.0.0-20201214224949-b6c5ce23f027/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E=
+k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE=
+k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y=
+k8s.io/klog/v2 v2.9.0 h1:D7HV+n1V57XeZ0m6tdRkfknthUaM06VFbWldOFh8kzM=
+k8s.io/klog/v2 v2.9.0/go.mod h1:hy9LJ/NvuK+iVyP4Ehqva4HxZG/oXyIS3n3Jmire4Ec=
+k8s.io/kube-openapi v0.0.0-20210421082810-95288971da7e h1:KLHHjkdQFomZy8+06csTWZ0m1343QqxZhR2LJ1OxCYM=
+k8s.io/kube-openapi v0.0.0-20210421082810-95288971da7e/go.mod h1:vHXdDvt9+2spS2Rx9ql3I8tycm3H9FDfdUoIuKCefvw=
+k8s.io/utils v0.0.0-20210819203725-bdf08cb9a70a h1:8dYfu/Fc9Gz2rNJKB9IQRGgQOh2clmRzNIPPY1xLY5g=
+k8s.io/utils v0.0.0-20210819203725-bdf08cb9a70a/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
+rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
+rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
+rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
+sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.22/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg=
+sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw=
+sigs.k8s.io/structured-merge-diff/v4 v4.1.2 h1:Hr/htKFmJEbtMgS/UD0N+gtgctAqz81t3nu+sPzynno=
+sigs.k8s.io/structured-merge-diff/v4 v4.1.2/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4=
+sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q=
+sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc=
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/builder/controller.go b/vendor/sigs.k8s.io/controller-runtime/pkg/builder/controller.go
new file mode 100644
index 000000000..2cd4ce9de
--- /dev/null
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/builder/controller.go
@@ -0,0 +1,316 @@
+/*
+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 builder
+
+import (
+ "fmt"
+ "strings"
+
+ "github.com/go-logr/logr"
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ "k8s.io/apimachinery/pkg/runtime/schema"
+
+ "sigs.k8s.io/controller-runtime/pkg/client"
+ "sigs.k8s.io/controller-runtime/pkg/client/apiutil"
+ "sigs.k8s.io/controller-runtime/pkg/controller"
+ "sigs.k8s.io/controller-runtime/pkg/handler"
+ "sigs.k8s.io/controller-runtime/pkg/manager"
+ "sigs.k8s.io/controller-runtime/pkg/predicate"
+ "sigs.k8s.io/controller-runtime/pkg/reconcile"
+ "sigs.k8s.io/controller-runtime/pkg/source"
+)
+
+// Supporting mocking out functions for testing.
+var newController = controller.New
+var getGvk = apiutil.GVKForObject
+
+// project represents other forms that the we can use to
+// send/receive a given resource (metadata-only, unstructured, etc).
+type objectProjection int
+
+const (
+ // projectAsNormal doesn't change the object from the form given.
+ projectAsNormal objectProjection = iota
+ // projectAsMetadata turns this into an metadata-only watch.
+ projectAsMetadata
+)
+
+// Builder builds a Controller.
+type Builder struct {
+ forInput ForInput
+ ownsInput []OwnsInput
+ watchesInput []WatchesInput
+ mgr manager.Manager
+ globalPredicates []predicate.Predicate
+ ctrl controller.Controller
+ ctrlOptions controller.Options
+ name string
+}
+
+// ControllerManagedBy returns a new controller builder that will be started by the provided Manager.
+func ControllerManagedBy(m manager.Manager) *Builder {
+ return &Builder{mgr: m}
+}
+
+// ForInput represents the information set by For method.
+type ForInput struct {
+ object client.Object
+ predicates []predicate.Predicate
+ objectProjection objectProjection
+ err error
+}
+
+// For defines the type of Object being *reconciled*, and configures the ControllerManagedBy to respond to create / delete /
+// update events by *reconciling the object*.
+// This is the equivalent of calling
+// Watches(&source.Kind{Type: apiType}, &handler.EnqueueRequestForObject{}).
+func (blder *Builder) For(object client.Object, opts ...ForOption) *Builder {
+ if blder.forInput.object != nil {
+ blder.forInput.err = fmt.Errorf("For(...) should only be called once, could not assign multiple objects for reconciliation")
+ return blder
+ }
+ input := ForInput{object: object}
+ for _, opt := range opts {
+ opt.ApplyToFor(&input)
+ }
+
+ blder.forInput = input
+ return blder
+}
+
+// OwnsInput represents the information set by Owns method.
+type OwnsInput struct {
+ object client.Object
+ predicates []predicate.Predicate
+ objectProjection objectProjection
+}
+
+// Owns defines types of Objects being *generated* by the ControllerManagedBy, and configures the ControllerManagedBy to respond to
+// create / delete / update events by *reconciling the owner object*. This is the equivalent of calling
+// Watches(&source.Kind{Type: <ForType-forInput>}, &handler.EnqueueRequestForOwner{OwnerType: apiType, IsController: true}).
+func (blder *Builder) Owns(object client.Object, opts ...OwnsOption) *Builder {
+ input := OwnsInput{object: object}
+ for _, opt := range opts {
+ opt.ApplyToOwns(&input)
+ }
+
+ blder.ownsInput = append(blder.ownsInput, input)
+ return blder
+}
+
+// WatchesInput represents the information set by Watches method.
+type WatchesInput struct {
+ src source.Source
+ eventhandler handler.EventHandler
+ predicates []predicate.Predicate
+ objectProjection objectProjection
+}
+
+// Watches exposes the lower-level ControllerManagedBy Watches functions through the builder. Consider using
+// Owns or For instead of Watches directly.
+// Specified predicates are registered only for given source.
+func (blder *Builder) Watches(src source.Source, eventhandler handler.EventHandler, opts ...WatchesOption) *Builder {
+ input := WatchesInput{src: src, eventhandler: eventhandler}
+ for _, opt := range opts {
+ opt.ApplyToWatches(&input)
+ }
+
+ blder.watchesInput = append(blder.watchesInput, input)
+ return blder
+}
+
+// WithEventFilter sets the event filters, to filter which create/update/delete/generic events eventually
+// trigger reconciliations. For example, filtering on whether the resource version has changed.
+// Given predicate is added for all watched objects.
+// Defaults to the empty list.
+func (blder *Builder) WithEventFilter(p predicate.Predicate) *Builder {
+ blder.globalPredicates = append(blder.globalPredicates, p)
+ return blder
+}
+
+// WithOptions overrides the controller options use in doController. Defaults to empty.
+func (blder *Builder) WithOptions(options controller.Options) *Builder {
+ blder.ctrlOptions = options
+ return blder
+}
+
+// WithLogger overrides the controller options's logger used.
+func (blder *Builder) WithLogger(log logr.Logger) *Builder {
+ blder.ctrlOptions.Log = log
+ return blder
+}
+
+// Named sets the name of the controller to the given name. The name shows up
+// in metrics, among other things, and thus should be a prometheus compatible name
+// (underscores and alphanumeric characters only).
+//
+// By default, controllers are named using the lowercase version of their kind.
+func (blder *Builder) Named(name string) *Builder {
+ blder.name = name
+ return blder
+}
+
+// Complete builds the Application Controller.
+func (blder *Builder) Complete(r reconcile.Reconciler) error {
+ _, err := blder.Build(r)
+ return err
+}
+
+// Build builds the Application Controller and returns the Controller it created.
+func (blder *Builder) Build(r reconcile.Reconciler) (controller.Controller, error) {
+ if r == nil {
+ return nil, fmt.Errorf("must provide a non-nil Reconciler")
+ }
+ if blder.mgr == nil {
+ return nil, fmt.Errorf("must provide a non-nil Manager")
+ }
+ if blder.forInput.err != nil {
+ return nil, blder.forInput.err
+ }
+ // Checking the reconcile type exist or not
+ if blder.forInput.object == nil {
+ return nil, fmt.Errorf("must provide an object for reconciliation")
+ }
+
+ // Set the ControllerManagedBy
+ if err := blder.doController(r); err != nil {
+ return nil, err
+ }
+
+ // Set the Watch
+ if err := blder.doWatch(); err != nil {
+ return nil, err
+ }
+
+ return blder.ctrl, nil
+}
+
+func (blder *Builder) project(obj client.Object, proj objectProjection) (client.Object, error) {
+ switch proj {
+ case projectAsNormal:
+ return obj, nil
+ case projectAsMetadata:
+ metaObj := &metav1.PartialObjectMetadata{}
+ gvk, err := getGvk(obj, blder.mgr.GetScheme())
+ if err != nil {
+ return nil, fmt.Errorf("unable to determine GVK of %T for a metadata-only watch: %w", obj, err)
+ }
+ metaObj.SetGroupVersionKind(gvk)
+ return metaObj, nil
+ default:
+ panic(fmt.Sprintf("unexpected projection type %v on type %T, should not be possible since this is an internal field", proj, obj))
+ }
+}
+
+func (blder *Builder) doWatch() error {
+ // Reconcile type
+ typeForSrc, err := blder.project(blder.forInput.object, blder.forInput.objectProjection)
+ if err != nil {
+ return err
+ }
+ src := &source.Kind{Type: typeForSrc}
+ hdler := &handler.EnqueueRequestForObject{}
+ allPredicates := append(blder.globalPredicates, blder.forInput.predicates...)
+ if err := blder.ctrl.Watch(src, hdler, allPredicates...); err != nil {
+ return err
+ }
+
+ // Watches the managed types
+ for _, own := range blder.ownsInput {
+ typeForSrc, err := blder.project(own.object, own.objectProjection)
+ if err != nil {
+ return err
+ }
+ src := &source.Kind{Type: typeForSrc}
+ hdler := &handler.EnqueueRequestForOwner{
+ OwnerType: blder.forInput.object,
+ IsController: true,
+ }
+ allPredicates := append([]predicate.Predicate(nil), blder.globalPredicates...)
+ allPredicates = append(allPredicates, own.predicates...)
+ if err := blder.ctrl.Watch(src, hdler, allPredicates...); err != nil {
+ return err
+ }
+ }
+
+ // Do the watch requests
+ for _, w := range blder.watchesInput {
+ allPredicates := append([]predicate.Predicate(nil), blder.globalPredicates...)
+ allPredicates = append(allPredicates, w.predicates...)
+
+ // If the source of this watch is of type *source.Kind, project it.
+ if srckind, ok := w.src.(*source.Kind); ok {
+ typeForSrc, err := blder.project(srckind.Type, w.objectProjection)
+ if err != nil {
+ return err
+ }
+ srckind.Type = typeForSrc
+ }
+
+ if err := blder.ctrl.Watch(w.src, w.eventhandler, allPredicates...); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+func (blder *Builder) getControllerName(gvk schema.GroupVersionKind) string {
+ if blder.name != "" {
+ return blder.name
+ }
+ return strings.ToLower(gvk.Kind)
+}
+
+func (blder *Builder) doController(r reconcile.Reconciler) error {
+ globalOpts := blder.mgr.GetControllerOptions()
+
+ ctrlOptions := blder.ctrlOptions
+ if ctrlOptions.Reconciler == nil {
+ ctrlOptions.Reconciler = r
+ }
+
+ // Retrieve the GVK from the object we're reconciling
+ // to prepopulate logger information, and to optionally generate a default name.
+ gvk, err := getGvk(blder.forInput.object, blder.mgr.GetScheme())
+ if err != nil {
+ return err
+ }
+
+ // Setup concurrency.
+ if ctrlOptions.MaxConcurrentReconciles == 0 {
+ groupKind := gvk.GroupKind().String()
+
+ if concurrency, ok := globalOpts.GroupKindConcurrency[groupKind]; ok && concurrency > 0 {
+ ctrlOptions.MaxConcurrentReconciles = concurrency
+ }
+ }
+
+ // Setup cache sync timeout.
+ if ctrlOptions.CacheSyncTimeout == 0 && globalOpts.CacheSyncTimeout != nil {
+ ctrlOptions.CacheSyncTimeout = *globalOpts.CacheSyncTimeout
+ }
+
+ // Setup the logger.
+ if ctrlOptions.Log == nil {
+ ctrlOptions.Log = blder.mgr.GetLogger()
+ }
+ ctrlOptions.Log = ctrlOptions.Log.WithValues("reconciler group", gvk.Group, "reconciler kind", gvk.Kind)
+
+ // Build the controller and return.
+ blder.ctrl, err = newController(blder.getControllerName(gvk), blder.mgr, ctrlOptions)
+ return err
+}
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/builder/doc.go b/vendor/sigs.k8s.io/controller-runtime/pkg/builder/doc.go
new file mode 100644
index 000000000..e4df1b709
--- /dev/null
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/builder/doc.go
@@ -0,0 +1,28 @@
+/*
+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 builder wraps other controller-runtime libraries and exposes simple
+// patterns for building common Controllers.
+//
+// Projects built with the builder package can trivially be rebased on top of the underlying
+// packages if the project requires more customized behavior in the future.
+package builder
+
+import (
+ logf "sigs.k8s.io/controller-runtime/pkg/internal/log"
+)
+
+var log = logf.RuntimeLog.WithName("builder")
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/builder/options.go b/vendor/sigs.k8s.io/controller-runtime/pkg/builder/options.go
new file mode 100644
index 000000000..7bb427309
--- /dev/null
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/builder/options.go
@@ -0,0 +1,117 @@
+/*
+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 builder
+
+import (
+ "sigs.k8s.io/controller-runtime/pkg/predicate"
+)
+
+// {{{ "Functional" Option Interfaces
+
+// ForOption is some configuration that modifies options for a For request.
+type ForOption interface {
+ // ApplyToFor applies this configuration to the given for input.
+ ApplyToFor(*ForInput)
+}
+
+// OwnsOption is some configuration that modifies options for a owns request.
+type OwnsOption interface {
+ // ApplyToOwns applies this configuration to the given owns input.
+ ApplyToOwns(*OwnsInput)
+}
+
+// WatchesOption is some configuration that modifies options for a watches request.
+type WatchesOption interface {
+ // ApplyToWatches applies this configuration to the given watches options.
+ ApplyToWatches(*WatchesInput)
+}
+
+// }}}
+
+// {{{ Multi-Type Options
+
+// WithPredicates sets the given predicates list.
+func WithPredicates(predicates ...predicate.Predicate) Predicates {
+ return Predicates{
+ predicates: predicates,
+ }
+}
+
+// Predicates filters events before enqueuing the keys.
+type Predicates struct {
+ predicates []predicate.Predicate
+}
+
+// ApplyToFor applies this configuration to the given ForInput options.
+func (w Predicates) ApplyToFor(opts *ForInput) {
+ opts.predicates = w.predicates
+}
+
+// ApplyToOwns applies this configuration to the given OwnsInput options.
+func (w Predicates) ApplyToOwns(opts *OwnsInput) {
+ opts.predicates = w.predicates
+}
+
+// ApplyToWatches applies this configuration to the given WatchesInput options.
+func (w Predicates) ApplyToWatches(opts *WatchesInput) {
+ opts.predicates = w.predicates
+}
+
+var _ ForOption = &Predicates{}
+var _ OwnsOption = &Predicates{}
+var _ WatchesOption = &Predicates{}
+
+// }}}
+
+// {{{ For & Owns Dual-Type options
+
+// asProjection configures the projection (currently only metadata) on the input.
+// Currently only metadata is supported. We might want to expand
+// this to arbitrary non-special local projections in the future.
+type projectAs objectProjection
+
+// ApplyToFor applies this configuration to the given ForInput options.
+func (p projectAs) ApplyToFor(opts *ForInput) {
+ opts.objectProjection = objectProjection(p)
+}
+
+// ApplyToOwns applies this configuration to the given OwnsInput options.
+func (p projectAs) ApplyToOwns(opts *OwnsInput) {
+ opts.objectProjection = objectProjection(p)
+}
+
+// ApplyToWatches applies this configuration to the given WatchesInput options.
+func (p projectAs) ApplyToWatches(opts *WatchesInput) {
+ opts.objectProjection = objectProjection(p)
+}
+
+var (
+ // OnlyMetadata tells the controller to *only* cache metadata, and to watch
+ // the the API server in metadata-only form. This is useful when watching
+ // lots of objects, really big objects, or objects for which you only know
+ // the the GVK, but not the structure. You'll need to pass
+ // metav1.PartialObjectMetadata to the client when fetching objects in your
+ // reconciler, otherwise you'll end up with a duplicate structured or
+ // unstructured cache.
+ OnlyMetadata = projectAs(projectAsMetadata)
+
+ _ ForOption = OnlyMetadata
+ _ OwnsOption = OnlyMetadata
+ _ WatchesOption = OnlyMetadata
+)
+
+// }}}
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/builder/webhook.go b/vendor/sigs.k8s.io/controller-runtime/pkg/builder/webhook.go
new file mode 100644
index 000000000..18feb1cd7
--- /dev/null
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/builder/webhook.go
@@ -0,0 +1,209 @@
+/*
+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 builder
+
+import (
+ "errors"
+ "net/http"
+ "net/url"
+ "strings"
+
+ "k8s.io/apimachinery/pkg/runtime"
+ "k8s.io/apimachinery/pkg/runtime/schema"
+ "k8s.io/client-go/rest"
+ "sigs.k8s.io/controller-runtime/pkg/client/apiutil"
+ "sigs.k8s.io/controller-runtime/pkg/manager"
+ "sigs.k8s.io/controller-runtime/pkg/webhook/admission"
+ "sigs.k8s.io/controller-runtime/pkg/webhook/conversion"
+)
+
+// WebhookBuilder builds a Webhook.
+type WebhookBuilder struct {
+ apiType runtime.Object
+ withDefaulter admission.CustomDefaulter
+ withValidator admission.CustomValidator
+ gvk schema.GroupVersionKind
+ mgr manager.Manager
+ config *rest.Config
+}
+
+// WebhookManagedBy allows inform its manager.Manager.
+func WebhookManagedBy(m manager.Manager) *WebhookBuilder {
+ return &WebhookBuilder{mgr: m}
+}
+
+// TODO(droot): update the GoDoc for conversion.
+
+// For takes a runtime.Object which should be a CR.
+// If the given object implements the admission.Defaulter interface, a MutatingWebhook will be wired for this type.
+// If the given object implements the admission.Validator interface, a ValidatingWebhook will be wired for this type.
+func (blder *WebhookBuilder) For(apiType runtime.Object) *WebhookBuilder {
+ blder.apiType = apiType
+ return blder
+}
+
+// WithDefaulter takes a admission.WithDefaulter interface, a MutatingWebhook will be wired for this type.
+func (blder *WebhookBuilder) WithDefaulter(defaulter admission.CustomDefaulter) *WebhookBuilder {
+ blder.withDefaulter = defaulter
+ return blder
+}
+
+// WithValidator takes a admission.WithValidator interface, a ValidatingWebhook will be wired for this type.
+func (blder *WebhookBuilder) WithValidator(validator admission.CustomValidator) *WebhookBuilder {
+ blder.withValidator = validator
+ return blder
+}
+
+// Complete builds the webhook.
+func (blder *WebhookBuilder) Complete() error {
+ // Set the Config
+ blder.loadRestConfig()
+
+ // Set the Webhook if needed
+ return blder.registerWebhooks()
+}
+
+func (blder *WebhookBuilder) loadRestConfig() {
+ if blder.config == nil {
+ blder.config = blder.mgr.GetConfig()
+ }
+}
+
+func (blder *WebhookBuilder) registerWebhooks() error {
+ typ, err := blder.getType()
+ if err != nil {
+ return err
+ }
+
+ // Create webhook(s) for each type
+ blder.gvk, err = apiutil.GVKForObject(typ, blder.mgr.GetScheme())
+ if err != nil {
+ return err
+ }
+
+ blder.registerDefaultingWebhook()
+ blder.registerValidatingWebhook()
+
+ err = blder.registerConversionWebhook()
+ if err != nil {
+ return err
+ }
+ return nil
+}
+
+// registerDefaultingWebhook registers a defaulting webhook if th.
+func (blder *WebhookBuilder) registerDefaultingWebhook() {
+ mwh := blder.getDefaultingWebhook()
+ if mwh != nil {
+ path := generateMutatePath(blder.gvk)
+
+ // Checking if the path is already registered.
+ // If so, just skip it.
+ if !blder.isAlreadyHandled(path) {
+ log.Info("Registering a mutating webhook",
+ "GVK", blder.gvk,
+ "path", path)
+ blder.mgr.GetWebhookServer().Register(path, mwh)
+ }
+ }
+}
+
+func (blder *WebhookBuilder) getDefaultingWebhook() *admission.Webhook {
+ if defaulter := blder.withDefaulter; defaulter != nil {
+ return admission.WithCustomDefaulter(blder.apiType, defaulter)
+ }
+ if defaulter, ok := blder.apiType.(admission.Defaulter); ok {
+ return admission.DefaultingWebhookFor(defaulter)
+ }
+ log.Info(
+ "skip registering a mutating webhook, object does not implement admission.Defaulter or WithDefaulter wasn't called",
+ "GVK", blder.gvk)
+ return nil
+}
+
+func (blder *WebhookBuilder) registerValidatingWebhook() {
+ vwh := blder.getValidatingWebhook()
+ if vwh != nil {
+ path := generateValidatePath(blder.gvk)
+
+ // Checking if the path is already registered.
+ // If so, just skip it.
+ if !blder.isAlreadyHandled(path) {
+ log.Info("Registering a validating webhook",
+ "GVK", blder.gvk,
+ "path", path)
+ blder.mgr.GetWebhookServer().Register(path, vwh)
+ }
+ }
+}
+
+func (blder *WebhookBuilder) getValidatingWebhook() *admission.Webhook {
+ if validator := blder.withValidator; validator != nil {
+ return admission.WithCustomValidator(blder.apiType, validator)
+ }
+ if validator, ok := blder.apiType.(admission.Validator); ok {
+ return admission.ValidatingWebhookFor(validator)
+ }
+ log.Info(
+ "skip registering a validating webhook, object does not implement admission.Validator or WithValidator wasn't called",
+ "GVK", blder.gvk)
+ return nil
+}
+
+func (blder *WebhookBuilder) registerConversionWebhook() error {
+ ok, err := conversion.IsConvertible(blder.mgr.GetScheme(), blder.apiType)
+ if err != nil {
+ log.Error(err, "conversion check failed", "GVK", blder.gvk)
+ return err
+ }
+ if ok {
+ if !blder.isAlreadyHandled("/convert") {
+ blder.mgr.GetWebhookServer().Register("/convert", &conversion.Webhook{})
+ }
+ log.Info("Conversion webhook enabled", "GVK", blder.gvk)
+ }
+
+ return nil
+}
+
+func (blder *WebhookBuilder) getType() (runtime.Object, error) {
+ if blder.apiType != nil {
+ return blder.apiType, nil
+ }
+ return nil, errors.New("For() must be called with a valid object")
+}
+
+func (blder *WebhookBuilder) isAlreadyHandled(path string) bool {
+ if blder.mgr.GetWebhookServer().WebhookMux == nil {
+ return false
+ }
+ h, p := blder.mgr.GetWebhookServer().WebhookMux.Handler(&http.Request{URL: &url.URL{Path: path}})
+ if p == path && h != nil {
+ return true
+ }
+ return false
+}
+
+func generateMutatePath(gvk schema.GroupVersionKind) string {
+ return "/mutate-" + strings.ReplaceAll(gvk.Group, ".", "-") + "-" +
+ gvk.Version + "-" + strings.ToLower(gvk.Kind)
+}
+
+func generateValidatePath(gvk schema.GroupVersionKind) string {
+ return "/validate-" + strings.ReplaceAll(gvk.Group, ".", "-") + "-" +
+ gvk.Version + "-" + strings.ToLower(gvk.Kind)
+}
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/cache/cache.go b/vendor/sigs.k8s.io/controller-runtime/pkg/cache/cache.go
new file mode 100644
index 000000000..f89800ca2
--- /dev/null
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/cache/cache.go
@@ -0,0 +1,231 @@
+/*
+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 cache
+
+import (
+ "context"
+ "fmt"
+ "time"
+
+ "k8s.io/apimachinery/pkg/api/meta"
+ "k8s.io/apimachinery/pkg/runtime"
+ "k8s.io/apimachinery/pkg/runtime/schema"
+ "k8s.io/client-go/kubernetes/scheme"
+ "k8s.io/client-go/rest"
+ toolscache "k8s.io/client-go/tools/cache"
+ "sigs.k8s.io/controller-runtime/pkg/cache/internal"
+ "sigs.k8s.io/controller-runtime/pkg/client"
+ "sigs.k8s.io/controller-runtime/pkg/client/apiutil"
+ logf "sigs.k8s.io/controller-runtime/pkg/internal/log"
+)
+
+var log = logf.RuntimeLog.WithName("object-cache")
+
+// Cache knows how to load Kubernetes objects, fetch informers to request
+// to receive events for Kubernetes objects (at a low-level),
+// and add indices to fields on the objects stored in the cache.
+type Cache interface {
+ // Cache acts as a client to objects stored in the cache.
+ client.Reader
+
+ // Cache loads informers and adds field indices.
+ Informers
+}
+
+// Informers knows how to create or fetch informers for different
+// group-version-kinds, and add indices to those informers. It's safe to call
+// GetInformer from multiple threads.
+type Informers interface {
+ // GetInformer fetches or constructs an informer for the given object that corresponds to a single
+ // API kind and resource.
+ GetInformer(ctx context.Context, obj client.Object) (Informer, error)
+
+ // GetInformerForKind is similar to GetInformer, except that it takes a group-version-kind, instead
+ // of the underlying object.
+ GetInformerForKind(ctx context.Context, gvk schema.GroupVersionKind) (Informer, error)
+
+ // Start runs all the informers known to this cache until the context is closed.
+ // It blocks.
+ Start(ctx context.Context) error
+
+ // WaitForCacheSync waits for all the caches to sync. Returns false if it could not sync a cache.
+ WaitForCacheSync(ctx context.Context) bool
+
+ // Informers knows how to add indices to the caches (informers) that it manages.
+ client.FieldIndexer
+}
+
+// Informer - informer allows you interact with the underlying informer.
+type Informer interface {
+ // AddEventHandler adds an event handler to the shared informer using the shared informer's resync
+ // period. Events to a single handler are delivered sequentially, but there is no coordination
+ // between different handlers.
+ AddEventHandler(handler toolscache.ResourceEventHandler)
+ // AddEventHandlerWithResyncPeriod adds an event handler to the shared informer using the
+ // specified resync period. Events to a single handler are delivered sequentially, but there is
+ // no coordination between different handlers.
+ AddEventHandlerWithResyncPeriod(handler toolscache.ResourceEventHandler, resyncPeriod time.Duration)
+ // AddIndexers adds more indexers to this store. If you call this after you already have data
+ // in the store, the results are undefined.
+ AddIndexers(indexers toolscache.Indexers) error
+ // HasSynced return true if the informers underlying store has synced.
+ HasSynced() bool
+}
+
+// SelectorsByObject associate a client.Object's GVK to a field/label selector.
+type SelectorsByObject map[client.Object]internal.Selector
+
+// Options are the optional arguments for creating a new InformersMap object.
+type Options struct {
+ // Scheme is the scheme to use for mapping objects to GroupVersionKinds
+ Scheme *runtime.Scheme
+
+ // Mapper is the RESTMapper to use for mapping GroupVersionKinds to Resources
+ Mapper meta.RESTMapper
+
+ // Resync is the base frequency the informers are resynced.
+ // Defaults to defaultResyncTime.
+ // 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
+
+ // Namespace restricts the cache's ListWatch to the desired namespace
+ // Default watches all namespaces
+ Namespace string
+
+ // SelectorsByObject restricts the cache's ListWatch to the desired
+ // fields per GVK at the specified object, the map's value must implement
+ // Selector [1] using for example a Set [2]
+ // [1] https://pkg.go.dev/k8s.io/apimachinery/pkg/fields#Selector
+ // [2] https://pkg.go.dev/k8s.io/apimachinery/pkg/fields#Set
+ SelectorsByObject SelectorsByObject
+
+ // UnsafeDisableDeepCopyByObject indicates not to deep copy objects during get or
+ // list objects per GVK at the specified object.
+ // Be very careful with this, when enabled you must DeepCopy any object before mutating it,
+ // otherwise you will mutate the object in the cache.
+ UnsafeDisableDeepCopyByObject DisableDeepCopyByObject
+}
+
+var defaultResyncTime = 10 * time.Hour
+
+// New initializes and returns a new Cache.
+func New(config *rest.Config, opts Options) (Cache, error) {
+ opts, err := defaultOpts(config, opts)
+ if err != nil {
+ return nil, err
+ }
+ selectorsByGVK, err := convertToSelectorsByGVK(opts.SelectorsByObject, opts.Scheme)
+ if err != nil {
+ return nil, err
+ }
+ disableDeepCopyByGVK, err := convertToDisableDeepCopyByGVK(opts.UnsafeDisableDeepCopyByObject, opts.Scheme)
+ if err != nil {
+ return nil, err
+ }
+ im := internal.NewInformersMap(config, opts.Scheme, opts.Mapper, *opts.Resync, opts.Namespace, selectorsByGVK, disableDeepCopyByGVK)
+ return &informerCache{InformersMap: im}, nil
+}
+
+// BuilderWithOptions returns a Cache constructor that will build the a cache
+// honoring the options argument, this is useful to specify options like
+// SelectorsByObject
+// WARNING: if SelectorsByObject is specified. filtered out resources are not
+// returned.
+// WARNING: if UnsafeDisableDeepCopy is enabled, you must DeepCopy any object
+// returned from cache get/list before mutating it.
+func BuilderWithOptions(options Options) NewCacheFunc {
+ return func(config *rest.Config, opts Options) (Cache, error) {
+ if opts.Scheme == nil {
+ opts.Scheme = options.Scheme
+ }
+ if opts.Mapper == nil {
+ opts.Mapper = options.Mapper
+ }
+ if opts.Resync == nil {
+ opts.Resync = options.Resync
+ }
+ if opts.Namespace == "" {
+ opts.Namespace = options.Namespace
+ }
+ opts.SelectorsByObject = options.SelectorsByObject
+ opts.UnsafeDisableDeepCopyByObject = options.UnsafeDisableDeepCopyByObject
+ return New(config, opts)
+ }
+}
+
+func defaultOpts(config *rest.Config, opts Options) (Options, error) {
+ // Use the default Kubernetes Scheme if unset
+ if opts.Scheme == nil {
+ opts.Scheme = scheme.Scheme
+ }
+
+ // Construct a new Mapper if unset
+ if opts.Mapper == nil {
+ var err error
+ opts.Mapper, err = apiutil.NewDiscoveryRESTMapper(config)
+ if err != nil {
+ log.WithName("setup").Error(err, "Failed to get API Group-Resources")
+ return opts, fmt.Errorf("could not create RESTMapper from config")
+ }
+ }
+
+ // Default the resync period to 10 hours if unset
+ if opts.Resync == nil {
+ opts.Resync = &defaultResyncTime
+ }
+ return opts, nil
+}
+
+func convertToSelectorsByGVK(selectorsByObject SelectorsByObject, scheme *runtime.Scheme) (internal.SelectorsByGVK, error) {
+ selectorsByGVK := internal.SelectorsByGVK{}
+ for object, selector := range selectorsByObject {
+ gvk, err := apiutil.GVKForObject(object, scheme)
+ if err != nil {
+ return nil, err
+ }
+ selectorsByGVK[gvk] = selector
+ }
+ return selectorsByGVK, 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
+}
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/cache/doc.go b/vendor/sigs.k8s.io/controller-runtime/pkg/cache/doc.go
new file mode 100644
index 000000000..e1742ac0f
--- /dev/null
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/cache/doc.go
@@ -0,0 +1,19 @@
+/*
+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 cache provides object caches that act as caching client.Reader
+// instances and help drive Kubernetes-object-based event handlers.
+package cache
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/cache/informer_cache.go b/vendor/sigs.k8s.io/controller-runtime/pkg/cache/informer_cache.go
new file mode 100644
index 000000000..90647c8e3
--- /dev/null
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/cache/informer_cache.go
@@ -0,0 +1,217 @@
+/*
+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 cache
+
+import (
+ "context"
+ "fmt"
+ "reflect"
+ "strings"
+
+ apimeta "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"
+ "k8s.io/client-go/tools/cache"
+ "sigs.k8s.io/controller-runtime/pkg/cache/internal"
+ "sigs.k8s.io/controller-runtime/pkg/client"
+ "sigs.k8s.io/controller-runtime/pkg/client/apiutil"
+)
+
+var (
+ _ Informers = &informerCache{}
+ _ client.Reader = &informerCache{}
+ _ Cache = &informerCache{}
+)
+
+// ErrCacheNotStarted is returned when trying to read from the cache that wasn't started.
+type ErrCacheNotStarted struct{}
+
+func (*ErrCacheNotStarted) Error() string {
+ return "the cache is not started, can not read objects"
+}
+
+// informerCache is a Kubernetes Object cache populated from InformersMap. informerCache wraps an InformersMap.
+type informerCache struct {
+ *internal.InformersMap
+}
+
+// Get implements Reader.
+func (ip *informerCache) Get(ctx context.Context, key client.ObjectKey, out client.Object) error {
+ gvk, err := apiutil.GVKForObject(out, ip.Scheme)
+ if err != nil {
+ return err
+ }
+
+ started, cache, err := ip.InformersMap.Get(ctx, gvk, out)
+ if err != nil {
+ return err
+ }
+
+ if !started {
+ return &ErrCacheNotStarted{}
+ }
+ return cache.Reader.Get(ctx, key, out)
+}
+
+// List implements Reader.
+func (ip *informerCache) List(ctx context.Context, out client.ObjectList, opts ...client.ListOption) error {
+ gvk, cacheTypeObj, err := ip.objectTypeForListObject(out)
+ if err != nil {
+ return err
+ }
+
+ started, cache, err := ip.InformersMap.Get(ctx, *gvk, cacheTypeObj)
+ if err != nil {
+ return err
+ }
+
+ if !started {
+ return &ErrCacheNotStarted{}
+ }
+
+ return cache.Reader.List(ctx, out, opts...)
+}
+
+// objectTypeForListObject tries to find the runtime.Object and associated GVK
+// for a single object corresponding to the passed-in list type. We need them
+// because they are used as cache map key.
+func (ip *informerCache) objectTypeForListObject(list client.ObjectList) (*schema.GroupVersionKind, runtime.Object, error) {
+ gvk, err := apiutil.GVKForObject(list, ip.Scheme)
+ if err != nil {
+ return nil, nil, err
+ }
+
+ if !strings.HasSuffix(gvk.Kind, "List") {
+ return nil, nil, fmt.Errorf("non-list type %T (kind %q) passed as output", list, gvk)
+ }
+ // we need the non-list GVK, so chop off the "List" from the end of the kind
+ gvk.Kind = gvk.Kind[:len(gvk.Kind)-4]
+ _, isUnstructured := list.(*unstructured.UnstructuredList)
+ var cacheTypeObj runtime.Object
+ if isUnstructured {
+ u := &unstructured.Unstructured{}
+ u.SetGroupVersionKind(gvk)
+ cacheTypeObj = u
+ } else {
+ itemsPtr, err := apimeta.GetItemsPtr(list)
+ if err != nil {
+ return nil, nil, err
+ }
+ // http://knowyourmeme.com/memes/this-is-fine
+ 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())
+ }
+ }
+
+ return &gvk, cacheTypeObj, nil
+}
+
+// GetInformerForKind returns the informer for the GroupVersionKind.
+func (ip *informerCache) GetInformerForKind(ctx context.Context, gvk schema.GroupVersionKind) (Informer, error) {
+ // Map the gvk to an object
+ obj, err := ip.Scheme.New(gvk)
+ if err != nil {
+ return nil, err
+ }
+
+ _, i, err := ip.InformersMap.Get(ctx, gvk, obj)
+ if err != nil {
+ return nil, err
+ }
+ return i.Informer, err
+}
+
+// GetInformer returns the informer for the obj.
+func (ip *informerCache) GetInformer(ctx context.Context, obj client.Object) (Informer, error) {
+ gvk, err := apiutil.GVKForObject(obj, ip.Scheme)
+ if err != nil {
+ return nil, err
+ }
+
+ _, i, err := ip.InformersMap.Get(ctx, gvk, obj)
+ if err != nil {
+ return nil, err
+ }
+ return i.Informer, err
+}
+
+// NeedLeaderElection implements the LeaderElectionRunnable interface
+// to indicate that this can be started without requiring the leader lock.
+func (ip *informerCache) NeedLeaderElection() bool {
+ return false
+}
+
+// IndexField adds an indexer to the underlying cache, using extraction function to get
+// value(s) from the given field. This index can then be used by passing a field selector
+// 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
+// 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 {
+ informer, err := ip.GetInformer(ctx, obj)
+ if err != nil {
+ return err
+ }
+ return indexByField(informer, field, extractValue)
+}
+
+func indexByField(indexer Informer, field string, extractor client.IndexerFunc) error {
+ indexFunc := func(objRaw interface{}) ([]string, error) {
+ // TODO(directxman12): check if this is the correct type?
+ obj, isObj := objRaw.(client.Object)
+ if !isObj {
+ return nil, fmt.Errorf("object of type %T is not an Object", objRaw)
+ }
+ meta, err := apimeta.Accessor(obj)
+ if err != nil {
+ return nil, err
+ }
+ ns := meta.GetNamespace()
+
+ rawVals := extractor(obj)
+ var vals []string
+ if ns == "" {
+ // if we're not doubling the keys for the namespaced case, just re-use what was returned to us
+ vals = rawVals
+ } else {
+ // if we need to add non-namespaced versions too, double the length
+ vals = make([]string, len(rawVals)*2)
+ }
+ for i, rawVal := range rawVals {
+ // save a namespaced variant, so that we can ask
+ // "what are all the object matching a given index *in a given namespace*"
+ vals[i] = internal.KeyToNamespacedKey(ns, rawVal)
+ if ns != "" {
+ // if we have a namespace, also inject a special index key for listing
+ // regardless of the object namespace
+ vals[i+len(rawVals)] = internal.KeyToNamespacedKey("", rawVal)
+ }
+ }
+
+ return vals, nil
+ }
+
+ return indexer.AddIndexers(cache.Indexers{internal.FieldIndexName(field): indexFunc})
+}
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/cache/internal/cache_reader.go b/vendor/sigs.k8s.io/controller-runtime/pkg/cache/internal/cache_reader.go
new file mode 100644
index 000000000..b95af18d7
--- /dev/null
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/cache/internal/cache_reader.go
@@ -0,0 +1,218 @@
+/*
+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"
+ "reflect"
+
+ apierrors "k8s.io/apimachinery/pkg/api/errors"
+ apimeta "k8s.io/apimachinery/pkg/api/meta"
+ "k8s.io/apimachinery/pkg/fields"
+ "k8s.io/apimachinery/pkg/labels"
+ "k8s.io/apimachinery/pkg/runtime"
+ "k8s.io/apimachinery/pkg/runtime/schema"
+ "k8s.io/apimachinery/pkg/selection"
+ "k8s.io/client-go/tools/cache"
+
+ "sigs.k8s.io/controller-runtime/pkg/client"
+)
+
+// CacheReader is a client.Reader.
+var _ client.Reader = &CacheReader{}
+
+// CacheReader wraps a cache.Index to implement the client.CacheReader interface for a single type.
+type CacheReader struct {
+ // indexer is the underlying indexer wrapped by this cache.
+ indexer cache.Indexer
+
+ // groupVersionKind is the group-version-kind of the resource.
+ groupVersionKind schema.GroupVersionKind
+
+ // scopeName is the scope of the resource (namespaced or cluster-scoped).
+ scopeName apimeta.RESTScopeName
+
+ // disableDeepCopy indicates not to deep copy objects during get or list objects.
+ // Be very careful with this, when enabled you must DeepCopy any object before mutating it,
+ // otherwise you will mutate the object in the cache.
+ disableDeepCopy bool
+}
+
+// Get checks the indexer for the object and writes a copy of it if found.
+func (c *CacheReader) Get(_ context.Context, key client.ObjectKey, out client.Object) error {
+ if c.scopeName == apimeta.RESTScopeNameRoot {
+ key.Namespace = ""
+ }
+ storeKey := objectKeyToStoreKey(key)
+
+ // Lookup the object from the indexer cache
+ obj, exists, err := c.indexer.GetByKey(storeKey)
+ if err != nil {
+ return err
+ }
+
+ // Not found, return an error
+ if !exists {
+ // Resource gets transformed into Kind in the error anyway, so this is fine
+ return apierrors.NewNotFound(schema.GroupResource{
+ Group: c.groupVersionKind.Group,
+ Resource: c.groupVersionKind.Kind,
+ }, key.Name)
+ }
+
+ // Verify the result is a runtime.Object
+ if _, isObj := obj.(runtime.Object); !isObj {
+ // This should never happen
+ return fmt.Errorf("cache contained %T, which is not an Object", obj)
+ }
+
+ if c.disableDeepCopy {
+ // skip deep copy which might be unsafe
+ // you must DeepCopy any object before mutating it outside
+ } else {
+ // deep copy to avoid mutating cache
+ obj = obj.(runtime.Object).DeepCopyObject()
+ }
+
+ // Copy the value of the item in the cache to the returned value
+ // TODO(directxman12): this is a terrible hack, pls fix (we should have deepcopyinto)
+ outVal := reflect.ValueOf(out)
+ objVal := reflect.ValueOf(obj)
+ if !objVal.Type().AssignableTo(outVal.Type()) {
+ return fmt.Errorf("cache had type %s, but %s was asked for", objVal.Type(), outVal.Type())
+ }
+ reflect.Indirect(outVal).Set(reflect.Indirect(objVal))
+ if !c.disableDeepCopy {
+ out.GetObjectKind().SetGroupVersionKind(c.groupVersionKind)
+ }
+
+ return nil
+}
+
+// List lists items out of the indexer and writes them to out.
+func (c *CacheReader) List(_ context.Context, out client.ObjectList, opts ...client.ListOption) error {
+ var objs []interface{}
+ var err error
+
+ listOpts := client.ListOptions{}
+ listOpts.ApplyOptions(opts)
+
+ switch {
+ case listOpts.FieldSelector != nil:
+ // TODO(directxman12): support more complicated field selectors by
+ // combining multiple indices, GetIndexers, etc
+ field, val, requiresExact := requiresExactMatch(listOpts.FieldSelector)
+ if !requiresExact {
+ return fmt.Errorf("non-exact field matches are not supported by the cache")
+ }
+ // list all objects by the field selector. If this is namespaced and we have one, ask for the
+ // namespaced index key. Otherwise, ask for the non-namespaced variant by using the fake "all namespaces"
+ // namespace.
+ objs, err = c.indexer.ByIndex(FieldIndexName(field), KeyToNamespacedKey(listOpts.Namespace, val))
+ case listOpts.Namespace != "":
+ objs, err = c.indexer.ByIndex(cache.NamespaceIndex, listOpts.Namespace)
+ default:
+ objs = c.indexer.List()
+ }
+ if err != nil {
+ return err
+ }
+ var labelSel labels.Selector
+ if listOpts.LabelSelector != nil {
+ labelSel = listOpts.LabelSelector
+ }
+
+ limitSet := listOpts.Limit > 0
+
+ runtimeObjs := make([]runtime.Object, 0, len(objs))
+ for _, item := range objs {
+ // if the Limit option is set and the number of items
+ // listed exceeds this limit, then stop reading.
+ if limitSet && int64(len(runtimeObjs)) >= listOpts.Limit {
+ break
+ }
+ obj, isObj := item.(runtime.Object)
+ if !isObj {
+ return fmt.Errorf("cache contained %T, which is not an Object", obj)
+ }
+ meta, err := apimeta.Accessor(obj)
+ if err != nil {
+ return err
+ }
+ if labelSel != nil {
+ lbls := labels.Set(meta.GetLabels())
+ if !labelSel.Matches(lbls) {
+ continue
+ }
+ }
+
+ var outObj runtime.Object
+ if c.disableDeepCopy {
+ // skip deep copy which might be unsafe
+ // you must DeepCopy any object before mutating it outside
+ outObj = obj
+ } else {
+ outObj = obj.DeepCopyObject()
+ outObj.GetObjectKind().SetGroupVersionKind(c.groupVersionKind)
+ }
+ runtimeObjs = append(runtimeObjs, outObj)
+ }
+ return apimeta.SetList(out, runtimeObjs)
+}
+
+// objectKeyToStorageKey converts an object key to store key.
+// It's akin to MetaNamespaceKeyFunc. It's separate from
+// String to allow keeping the key format easily in sync with
+// MetaNamespaceKeyFunc.
+func objectKeyToStoreKey(k client.ObjectKey) string {
+ if k.Namespace == "" {
+ return k.Name
+ }
+ return k.Namespace + "/" + k.Name
+}
+
+// requiresExactMatch checks if the given field selector is of the form `k=v` or `k==v`.
+func requiresExactMatch(sel fields.Selector) (field, val string, required bool) {
+ reqs := sel.Requirements()
+ if len(reqs) != 1 {
+ return "", "", false
+ }
+ req := reqs[0]
+ if req.Operator != selection.Equals && req.Operator != selection.DoubleEquals {
+ return "", "", false
+ }
+ return req.Field, req.Value, true
+}
+
+// FieldIndexName constructs the name of the index over the given field,
+// for use with an indexer.
+func FieldIndexName(field string) string {
+ return "field:" + field
+}
+
+// noNamespaceNamespace is used as the "namespace" when we want to list across all namespaces.
+const allNamespacesNamespace = "__all_namespaces"
+
+// KeyToNamespacedKey prefixes the given index key with a namespace
+// for use in field selector indexes.
+func KeyToNamespacedKey(ns string, baseKey string) string {
+ if ns != "" {
+ return ns + "/" + baseKey
+ }
+ return allNamespacesNamespace + "/" + baseKey
+}
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/cache/internal/deleg_map.go b/vendor/sigs.k8s.io/controller-runtime/pkg/cache/internal/deleg_map.go
new file mode 100644
index 000000000..9bfc8463f
--- /dev/null
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/cache/internal/deleg_map.go
@@ -0,0 +1,125 @@
+/*
+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,
+) *InformersMap {
+ return &InformersMap{
+ structured: newStructuredInformersMap(config, scheme, mapper, resync, namespace, selectors, disableDeepCopy),
+ unstructured: newUnstructuredInformersMap(config, scheme, mapper, resync, namespace, selectors, disableDeepCopy),
+ metadata: newMetadataInformersMap(config, scheme, mapper, resync, namespace, selectors, disableDeepCopy),
+
+ 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) *specificInformersMap {
+ return newSpecificInformersMap(config, scheme, mapper, resync, namespace, selectors, disableDeepCopy, 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) *specificInformersMap {
+ return newSpecificInformersMap(config, scheme, mapper, resync, namespace, selectors, disableDeepCopy, 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) *specificInformersMap {
+ return newSpecificInformersMap(config, scheme, mapper, resync, namespace, selectors, disableDeepCopy, createMetadataListWatch)
+}
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/cache/internal/disabledeepcopy.go b/vendor/sigs.k8s.io/controller-runtime/pkg/cache/internal/disabledeepcopy.go
new file mode 100644
index 000000000..54bd7eec9
--- /dev/null
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/cache/internal/disabledeepcopy.go
@@ -0,0 +1,35 @@
+/*
+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
+}
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/cache/internal/informers_map.go b/vendor/sigs.k8s.io/controller-runtime/pkg/cache/internal/informers_map.go
new file mode 100644
index 000000000..f8e957343
--- /dev/null
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/cache/internal/informers_map.go
@@ -0,0 +1,478 @@
+/*
+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,
+ 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,
+ disableDeepCopy: disableDeepCopy,
+ }
+ 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 SelectorsByGVK
+
+ // disableDeepCopy indicates not to deep copy objects during get or list objects.
+ disableDeepCopy DisableDeepCopyByGVK
+}
+
+// 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,
+ })
+ 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
+}
+
+type gvkFixupWatcher struct {
+ watcher watch.Interface
+ ch chan watch.Event
+ gvk schema.GroupVersionKind
+ wg sync.WaitGroup
+}
+
+func newGVKFixupWatcher(gvk schema.GroupVersionKind, watcher watch.Interface) watch.Interface {
+ ch := make(chan watch.Event)
+ w := &gvkFixupWatcher{
+ gvk: gvk,
+ watcher: watcher,
+ ch: ch,
+ }
+ w.wg.Add(1)
+ go w.run()
+ return w
+}
+
+func (w *gvkFixupWatcher) run() {
+ for e := range w.watcher.ResultChan() {
+ e.Object.GetObjectKind().SetGroupVersionKind(w.gvk)
+ w.ch <- e
+ }
+ w.wg.Done()
+}
+
+func (w *gvkFixupWatcher) Stop() {
+ w.watcher.Stop()
+ w.wg.Wait()
+ close(w.ch)
+}
+
+func (w *gvkFixupWatcher) ResultChan() <-chan watch.Event {
+ return w.ch
+}
+
+// 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 ""
+}
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/cache/internal/selector.go b/vendor/sigs.k8s.io/controller-runtime/pkg/cache/internal/selector.go
new file mode 100644
index 000000000..cd9c58000
--- /dev/null
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/cache/internal/selector.go
@@ -0,0 +1,43 @@
+/*
+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 (
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ "k8s.io/apimachinery/pkg/fields"
+ "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
+
+// Selector specify the label/field selector to fill in ListOptions.
+type Selector struct {
+ Label labels.Selector
+ Field fields.Selector
+}
+
+// ApplyToList fill in ListOptions LabelSelector and FieldSelector if needed.
+func (s Selector) ApplyToList(listOpts *metav1.ListOptions) {
+ if s.Label != nil {
+ listOpts.LabelSelector = s.Label.String()
+ }
+ if s.Field != nil {
+ listOpts.FieldSelector = s.Field.String()
+ }
+}
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/cache/multi_namespace_cache.go b/vendor/sigs.k8s.io/controller-runtime/pkg/cache/multi_namespace_cache.go
new file mode 100644
index 000000000..dc29651b0
--- /dev/null
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/cache/multi_namespace_cache.go
@@ -0,0 +1,331 @@
+/*
+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 cache
+
+import (
+ "context"
+ "fmt"
+ "time"
+
+ corev1 "k8s.io/api/core/v1"
+ apimeta "k8s.io/apimachinery/pkg/api/meta"
+ "k8s.io/apimachinery/pkg/runtime"
+ "k8s.io/apimachinery/pkg/runtime/schema"
+ "k8s.io/client-go/rest"
+ toolscache "k8s.io/client-go/tools/cache"
+ "sigs.k8s.io/controller-runtime/pkg/client"
+ "sigs.k8s.io/controller-runtime/pkg/internal/objectutil"
+)
+
+// 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.
+const globalCache = "_cluster-scope"
+
+// MultiNamespacedCacheBuilder - Builder function to create a new multi-namespaced cache.
+// This will scope the cache to a list of namespaces. Listing for all namespaces
+// will list for all the namespaces that this knows about. By default this will create
+// 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
+// you may face performance issues when using this with a high number of namespaces.
+func MultiNamespacedCacheBuilder(namespaces []string) NewCacheFunc {
+ return func(config *rest.Config, opts Options) (Cache, error) {
+ opts, err := defaultOpts(config, opts)
+ if err != nil {
+ return nil, err
+ }
+
+ 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 %v", 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
+ }
+}
+
+// multiNamespaceCache knows how to handle multiple namespaced caches
+// Use this feature when scoping permissions for your
+// operator to a list of namespaces instead of watching every namespace
+// in the cluster.
+type multiNamespaceCache struct {
+ namespaceToCache map[string]Cache
+ Scheme *runtime.Scheme
+ RESTMapper apimeta.RESTMapper
+ clusterCache Cache
+}
+
+var _ Cache = &multiNamespaceCache{}
+
+// Methods for multiNamespaceCache to conform to the Informers interface.
+func (c *multiNamespaceCache) GetInformer(ctx context.Context, obj client.Object) (Informer, error) {
+ informers := map[string]Informer{}
+
+ // If the object is clusterscoped, get the informer from clusterCache,
+ // if not use the namespaced caches.
+ isNamespaced, err := objectutil.IsAPINamespaced(obj, c.Scheme, c.RESTMapper)
+ if err != nil {
+ return nil, err
+ }
+ if !isNamespaced {
+ clusterCacheInf, err := c.clusterCache.GetInformer(ctx, obj)
+ if err != nil {
+ return nil, err
+ }
+ informers[globalCache] = clusterCacheInf
+
+ return &multiNamespaceInformer{namespaceToInformer: informers}, nil
+ }
+
+ for ns, cache := range c.namespaceToCache {
+ informer, err := cache.GetInformer(ctx, obj)
+ if err != nil {
+ return nil, err
+ }
+ informers[ns] = informer
+ }
+
+ return &multiNamespaceInformer{namespaceToInformer: informers}, nil
+}
+
+func (c *multiNamespaceCache) GetInformerForKind(ctx context.Context, gvk schema.GroupVersionKind) (Informer, error) {
+ informers := map[string]Informer{}
+
+ // If the object is clusterscoped, get the informer from clusterCache,
+ // if not use the namespaced caches.
+ isNamespaced, err := objectutil.IsAPINamespacedWithGVK(gvk, c.Scheme, c.RESTMapper)
+ if err != nil {
+ return nil, err
+ }
+ if !isNamespaced {
+ clusterCacheInf, err := c.clusterCache.GetInformerForKind(ctx, gvk)
+ if err != nil {
+ return nil, err
+ }
+ informers[globalCache] = clusterCacheInf
+
+ return &multiNamespaceInformer{namespaceToInformer: informers}, nil
+ }
+
+ for ns, cache := range c.namespaceToCache {
+ informer, err := cache.GetInformerForKind(ctx, gvk)
+ if err != nil {
+ return nil, err
+ }
+ informers[ns] = informer
+ }
+
+ return &multiNamespaceInformer{namespaceToInformer: informers}, nil
+}
+
+func (c *multiNamespaceCache) Start(ctx context.Context) error {
+ // start global cache
+ go func() {
+ err := c.clusterCache.Start(ctx)
+ if err != nil {
+ log.Error(err, "cluster scoped cache failed to start")
+ }
+ }()
+
+ // start namespaced caches
+ for ns, cache := range c.namespaceToCache {
+ go func(ns string, cache Cache) {
+ err := cache.Start(ctx)
+ if err != nil {
+ log.Error(err, "multinamespace cache failed to start namespaced informer", "namespace", ns)
+ }
+ }(ns, cache)
+ }
+
+ <-ctx.Done()
+ return nil
+}
+
+func (c *multiNamespaceCache) WaitForCacheSync(ctx context.Context) bool {
+ synced := true
+ for _, cache := range c.namespaceToCache {
+ if s := cache.WaitForCacheSync(ctx); !s {
+ synced = s
+ }
+ }
+
+ // check if cluster scoped cache has synced
+ if !c.clusterCache.WaitForCacheSync(ctx) {
+ synced = false
+ }
+ return synced
+}
+
+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)
+ if err != nil {
+ return nil //nolint:nilerr
+ }
+
+ if !isNamespaced {
+ return c.clusterCache.IndexField(ctx, obj, field, extractValue)
+ }
+
+ for _, cache := range c.namespaceToCache {
+ if err := cache.IndexField(ctx, obj, field, extractValue); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+func (c *multiNamespaceCache) Get(ctx context.Context, key client.ObjectKey, obj client.Object) error {
+ isNamespaced, err := objectutil.IsAPINamespaced(obj, c.Scheme, c.RESTMapper)
+ if err != nil {
+ return err
+ }
+
+ if !isNamespaced {
+ // Look into the global cache to fetch the object
+ return c.clusterCache.Get(ctx, key, obj)
+ }
+
+ cache, ok := c.namespaceToCache[key.Namespace]
+ if !ok {
+ return fmt.Errorf("unable to get: %v because of unknown namespace for the cache", key)
+ }
+ return cache.Get(ctx, key, obj)
+}
+
+// List multi namespace cache will get all the objects in the namespaces that the cache is watching if asked for all namespaces.
+func (c *multiNamespaceCache) List(ctx context.Context, list client.ObjectList, opts ...client.ListOption) error {
+ listOpts := client.ListOptions{}
+ listOpts.ApplyOptions(opts)
+
+ isNamespaced, err := objectutil.IsAPINamespaced(list, c.Scheme, c.RESTMapper)
+ if err != nil {
+ return err
+ }
+
+ if !isNamespaced {
+ // Look at the global cache to get the objects with the specified GVK
+ return c.clusterCache.List(ctx, list, opts...)
+ }
+
+ if listOpts.Namespace != corev1.NamespaceAll {
+ cache, ok := c.namespaceToCache[listOpts.Namespace]
+ if !ok {
+ return fmt.Errorf("unable to get: %v because of unknown namespace for the cache", listOpts.Namespace)
+ }
+ return cache.List(ctx, list, opts...)
+ }
+
+ listAccessor, err := apimeta.ListAccessor(list)
+ if err != nil {
+ return err
+ }
+
+ allItems, err := apimeta.ExtractList(list)
+ if err != nil {
+ return err
+ }
+
+ limitSet := listOpts.Limit > 0
+
+ var resourceVersion string
+ for _, cache := range c.namespaceToCache {
+ listObj := list.DeepCopyObject().(client.ObjectList)
+ err = cache.List(ctx, listObj, &listOpts)
+ if err != nil {
+ return err
+ }
+ items, err := apimeta.ExtractList(listObj)
+ if err != nil {
+ return err
+ }
+ accessor, err := apimeta.ListAccessor(listObj)
+ if err != nil {
+ return fmt.Errorf("object: %T must be a list type", list)
+ }
+ allItems = append(allItems, items...)
+ // The last list call should have the most correct resource version.
+ resourceVersion = accessor.GetResourceVersion()
+ if limitSet {
+ // decrement Limit by the number of items
+ // fetched from the current namespace.
+ listOpts.Limit -= int64(len(items))
+ // if a Limit was set and the number of
+ // items read has reached this set limit,
+ // then stop reading.
+ if listOpts.Limit == 0 {
+ break
+ }
+ }
+ }
+ listAccessor.SetResourceVersion(resourceVersion)
+
+ return apimeta.SetList(list, allItems)
+}
+
+// multiNamespaceInformer knows how to handle interacting with the underlying informer across multiple namespaces.
+type multiNamespaceInformer struct {
+ namespaceToInformer map[string]Informer
+}
+
+var _ Informer = &multiNamespaceInformer{}
+
+// AddEventHandler adds the handler to each namespaced informer.
+func (i *multiNamespaceInformer) AddEventHandler(handler toolscache.ResourceEventHandler) {
+ for _, informer := range i.namespaceToInformer {
+ informer.AddEventHandler(handler)
+ }
+}
+
+// AddEventHandlerWithResyncPeriod adds the handler with a resync period to each namespaced informer.
+func (i *multiNamespaceInformer) AddEventHandlerWithResyncPeriod(handler toolscache.ResourceEventHandler, resyncPeriod time.Duration) {
+ for _, informer := range i.namespaceToInformer {
+ informer.AddEventHandlerWithResyncPeriod(handler, resyncPeriod)
+ }
+}
+
+// AddIndexers adds the indexer for each namespaced informer.
+func (i *multiNamespaceInformer) AddIndexers(indexers toolscache.Indexers) error {
+ for _, informer := range i.namespaceToInformer {
+ err := informer.AddIndexers(indexers)
+ if err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+// HasSynced checks if each namespaced informer has synced.
+func (i *multiNamespaceInformer) HasSynced() bool {
+ for _, informer := range i.namespaceToInformer {
+ if ok := informer.HasSynced(); !ok {
+ return ok
+ }
+ }
+ return true
+}
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/certwatcher/certwatcher.go b/vendor/sigs.k8s.io/controller-runtime/pkg/certwatcher/certwatcher.go
new file mode 100644
index 000000000..e8e0e17a2
--- /dev/null
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/certwatcher/certwatcher.go
@@ -0,0 +1,163 @@
+/*
+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 certwatcher
+
+import (
+ "context"
+ "crypto/tls"
+ "sync"
+
+ "github.com/fsnotify/fsnotify"
+ logf "sigs.k8s.io/controller-runtime/pkg/internal/log"
+)
+
+var log = logf.RuntimeLog.WithName("certwatcher")
+
+// CertWatcher watches certificate and key files for changes. When either file
+// changes, it reads and parses both and calls an optional callback with the new
+// certificate.
+type CertWatcher struct {
+ sync.RWMutex
+
+ currentCert *tls.Certificate
+ watcher *fsnotify.Watcher
+
+ certPath string
+ keyPath string
+}
+
+// New returns a new CertWatcher watching the given certificate and key.
+func New(certPath, keyPath string) (*CertWatcher, error) {
+ var err error
+
+ cw := &CertWatcher{
+ certPath: certPath,
+ keyPath: keyPath,
+ }
+
+ // Initial read of certificate and key.
+ if err := cw.ReadCertificate(); err != nil {
+ return nil, err
+ }
+
+ cw.watcher, err = fsnotify.NewWatcher()
+ if err != nil {
+ return nil, err
+ }
+
+ return cw, nil
+}
+
+// GetCertificate fetches the currently loaded certificate, which may be nil.
+func (cw *CertWatcher) GetCertificate(_ *tls.ClientHelloInfo) (*tls.Certificate, error) {
+ cw.RLock()
+ defer cw.RUnlock()
+ return cw.currentCert, nil
+}
+
+// Start starts the watch on the certificate and key files.
+func (cw *CertWatcher) Start(ctx context.Context) error {
+ files := []string{cw.certPath, cw.keyPath}
+
+ for _, f := range files {
+ if err := cw.watcher.Add(f); err != nil {
+ return err
+ }
+ }
+
+ go cw.Watch()
+
+ log.Info("Starting certificate watcher")
+
+ // Block until the context is done.
+ <-ctx.Done()
+
+ return cw.watcher.Close()
+}
+
+// Watch reads events from the watcher's channel and reacts to changes.
+func (cw *CertWatcher) Watch() {
+ for {
+ select {
+ case event, ok := <-cw.watcher.Events:
+ // Channel is closed.
+ if !ok {
+ return
+ }
+
+ cw.handleEvent(event)
+
+ case err, ok := <-cw.watcher.Errors:
+ // Channel is closed.
+ if !ok {
+ return
+ }
+
+ log.Error(err, "certificate watch error")
+ }
+ }
+}
+
+// ReadCertificate reads the certificate and key files from disk, parses them,
+// and updates the current certificate on the watcher. If a callback is set, it
+// is invoked with the new certificate.
+func (cw *CertWatcher) ReadCertificate() error {
+ cert, err := tls.LoadX509KeyPair(cw.certPath, cw.keyPath)
+ if err != nil {
+ return err
+ }
+
+ cw.Lock()
+ cw.currentCert = &cert
+ cw.Unlock()
+
+ log.Info("Updated current TLS certificate")
+
+ return nil
+}
+
+func (cw *CertWatcher) handleEvent(event fsnotify.Event) {
+ // Only care about events which may modify the contents of the file.
+ if !(isWrite(event) || isRemove(event) || isCreate(event)) {
+ return
+ }
+
+ log.V(1).Info("certificate event", "event", event)
+
+ // If the file was removed, re-add the watch.
+ if isRemove(event) {
+ if err := cw.watcher.Add(event.Name); err != nil {
+ log.Error(err, "error re-watching file")
+ }
+ }
+
+ if err := cw.ReadCertificate(); err != nil {
+ log.Error(err, "error re-reading certificate")
+ }
+}
+
+func isWrite(event fsnotify.Event) bool {
+ return event.Op&fsnotify.Write == fsnotify.Write
+}
+
+func isCreate(event fsnotify.Event) bool {
+ return event.Op&fsnotify.Create == fsnotify.Create
+}
+
+func isRemove(event fsnotify.Event) bool {
+ return event.Op&fsnotify.Remove == fsnotify.Remove
+}
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/certwatcher/doc.go b/vendor/sigs.k8s.io/controller-runtime/pkg/certwatcher/doc.go
new file mode 100644
index 000000000..40c2fc0bf
--- /dev/null
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/certwatcher/doc.go
@@ -0,0 +1,23 @@
+/*
+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 certwatcher is a helper for reloading Certificates from disk to be used
+with tls servers. It provides a helper func `GetCertificate` which can be
+called from `tls.Config` and passed into your tls.Listener. For a detailed
+example server view pkg/webhook/server.go.
+*/
+package certwatcher
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/client/apiutil/apimachinery.go b/vendor/sigs.k8s.io/controller-runtime/pkg/client/apiutil/apimachinery.go
new file mode 100644
index 000000000..c92b0eaae
--- /dev/null
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/client/apiutil/apimachinery.go
@@ -0,0 +1,196 @@
+/*
+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 apiutil contains utilities for working with raw Kubernetes
+// API machinery, such as creating RESTMappers and raw REST clients,
+// and extracting the GVK of an object.
+package apiutil
+
+import (
+ "fmt"
+ "reflect"
+ "sync"
+
+ "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/client-go/discovery"
+ clientgoscheme "k8s.io/client-go/kubernetes/scheme"
+ "k8s.io/client-go/rest"
+ "k8s.io/client-go/restmapper"
+)
+
+var (
+ protobufScheme = runtime.NewScheme()
+ protobufSchemeLock sync.RWMutex
+)
+
+func init() {
+ // Currently only enabled for built-in resources which are guaranteed to implement Protocol Buffers.
+ // For custom resources, CRDs can not support Protocol Buffers but Aggregated API can.
+ // See doc: https://kubernetes.io/docs/concepts/extend-kubernetes/api-extension/custom-resources/#advanced-features-and-flexibility
+ if err := clientgoscheme.AddToScheme(protobufScheme); err != nil {
+ panic(err)
+ }
+}
+
+// AddToProtobufScheme add the given SchemeBuilder into protobufScheme, which should
+// be additional types that do support protobuf.
+func AddToProtobufScheme(addToScheme func(*runtime.Scheme) error) error {
+ protobufSchemeLock.Lock()
+ defer protobufSchemeLock.Unlock()
+ return addToScheme(protobufScheme)
+}
+
+// NewDiscoveryRESTMapper constructs a new RESTMapper based on discovery
+// information fetched by a new client with the given config.
+func NewDiscoveryRESTMapper(c *rest.Config) (meta.RESTMapper, error) {
+ // Get a mapper
+ dc, err := discovery.NewDiscoveryClientForConfig(c)
+ if err != nil {
+ return nil, err
+ }
+ gr, err := restmapper.GetAPIGroupResources(dc)
+ if err != nil {
+ return nil, err
+ }
+ return restmapper.NewDiscoveryRESTMapper(gr), nil
+}
+
+// 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) {
+ // TODO(directxman12): do we want to generalize this to arbitrary container types?
+ // I think we'd need a generalized form of scheme or something. It's a
+ // shame there's not a reliable "GetGVK" interface that works by default
+ // for unpopulated static types and populated "dynamic" types
+ // (unstructured, partial, etc)
+
+ // check for PartialObjectMetadata, which is analogous to unstructured, but isn't handled by ObjectKinds
+ _, isPartial := obj.(*metav1.PartialObjectMetadata) //nolint:ifshort
+ _, isPartialList := obj.(*metav1.PartialObjectMetadataList)
+ if isPartial || isPartialList {
+ // we require that the GVK be populated in order to recognize the object
+ gvk := obj.GetObjectKind().GroupVersionKind()
+ if len(gvk.Kind) == 0 {
+ return schema.GroupVersionKind{}, runtime.NewMissingKindErr("unstructured object has no kind")
+ }
+ if len(gvk.Version) == 0 {
+ return schema.GroupVersionKind{}, runtime.NewMissingVersionErr("unstructured object has no version")
+ }
+ return gvk, nil
+ }
+
+ gvks, isUnversioned, err := scheme.ObjectKinds(obj)
+ if err != nil {
+ return schema.GroupVersionKind{}, err
+ }
+ if isUnversioned {
+ return schema.GroupVersionKind{}, fmt.Errorf("cannot create group-version-kind for unversioned type %T", obj)
+ }
+
+ if len(gvks) < 1 {
+ return schema.GroupVersionKind{}, fmt.Errorf("no group-version-kinds associated with type %T", obj)
+ }
+ if len(gvks) > 1 {
+ // this should only trigger for things like metav1.XYZ --
+ // normal versioned types should be fine
+ return schema.GroupVersionKind{}, fmt.Errorf(
+ "multiple group-version-kinds associated with type %T, refusing to guess at one", obj)
+ }
+ return gvks[0], nil
+}
+
+// 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
+// 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) {
+ return rest.RESTClientFor(createRestConfig(gvk, isUnstructured, baseConfig, codecs))
+}
+
+// serializerWithDecodedGVK is a CodecFactory that overrides the DecoderToVersion of a WithoutConversionCodecFactory
+// 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.
+func createRestConfig(gvk schema.GroupVersionKind, isUnstructured bool, baseConfig *rest.Config, codecs serializer.CodecFactory) *rest.Config {
+ gv := gvk.GroupVersion()
+
+ cfg := rest.CopyConfig(baseConfig)
+ cfg.GroupVersion = &gv
+ if gvk.Group == "" {
+ cfg.APIPath = "/api"
+ } else {
+ cfg.APIPath = "/apis"
+ }
+ if cfg.UserAgent == "" {
+ cfg.UserAgent = rest.DefaultKubernetesUserAgent()
+ }
+ // TODO(FillZpp): In the long run, we want to check discovery or something to make sure that this is actually true.
+ if cfg.ContentType == "" && !isUnstructured {
+ protobufSchemeLock.RLock()
+ if protobufScheme.Recognizes(gvk) {
+ cfg.ContentType = runtime.ContentTypeProtobuf
+ }
+ protobufSchemeLock.RUnlock()
+ }
+
+ if isUnstructured {
+ // If the object is unstructured, we need to preserve the GVK information.
+ // Use our own custom serializer.
+ cfg.NegotiatedSerializer = serializerWithDecodedGVK{serializer.WithoutConversionCodecFactory{CodecFactory: codecs}}
+ } else {
+ cfg.NegotiatedSerializer = serializerWithTargetZeroingDecode{NegotiatedSerializer: serializer.WithoutConversionCodecFactory{CodecFactory: codecs}}
+ }
+
+ return cfg
+}
+
+type serializerWithTargetZeroingDecode struct {
+ runtime.NegotiatedSerializer
+}
+
+func (s serializerWithTargetZeroingDecode) DecoderToVersion(serializer runtime.Decoder, r runtime.GroupVersioner) runtime.Decoder {
+ return targetZeroingDecoder{upstream: s.NegotiatedSerializer.DecoderToVersion(serializer, r)}
+}
+
+type targetZeroingDecoder struct {
+ upstream runtime.Decoder
+}
+
+func (t targetZeroingDecoder) Decode(data []byte, defaults *schema.GroupVersionKind, into runtime.Object) (runtime.Object, *schema.GroupVersionKind, error) {
+ zero(into)
+ return t.upstream.Decode(data, defaults, into)
+}
+
+// zero zeros the value of a pointer.
+func zero(x interface{}) {
+ if x == nil {
+ return
+ }
+ res := reflect.ValueOf(x).Elem()
+ res.Set(reflect.Zero(res.Type()))
+}
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/client/apiutil/dynamicrestmapper.go b/vendor/sigs.k8s.io/controller-runtime/pkg/client/apiutil/dynamicrestmapper.go
new file mode 100644
index 000000000..56a00371f
--- /dev/null
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/client/apiutil/dynamicrestmapper.go
@@ -0,0 +1,285 @@
+/*
+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 (
+ "errors"
+ "sync"
+
+ "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.
+ initOnce sync.Once
+}
+
+// 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
+}
+
+// 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.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) {
+ drm.initOnce.Do(func() {
+ if drm.lazy {
+ err = drm.setStaticMapper()
+ }
+ })
+ 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 that matches the given error, 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(needsReloadErr error, 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()
+ }()
+
+ // NB(directxman12): `Is` and `As` have a confusing relationship --
+ // `Is` is like `== or does this implement .Is`, whereas `As` says
+ // `can I type-assert into`
+ needsReload := errors.As(err, &needsReloadErr)
+ 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 = errors.As(err, &needsReloadErr)
+ 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(&meta.NoResourceMatchError{}, 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(&meta.NoResourceMatchError{}, 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(&meta.NoResourceMatchError{}, 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(&meta.NoResourceMatchError{}, 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(&meta.NoKindMatchError{}, 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(&meta.NoKindMatchError{}, 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(&meta.NoResourceMatchError{}, func() error {
+ var err error
+ singular, err = drm.staticMapper.ResourceSingularizer(resource)
+ return err
+ })
+ return singular, err
+}
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/client/client.go b/vendor/sigs.k8s.io/controller-runtime/pkg/client/client.go
new file mode 100644
index 000000000..bbe36c467
--- /dev/null
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/client/client.go
@@ -0,0 +1,328 @@
+/*
+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"
+ "fmt"
+ "strings"
+
+ "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/apimachinery/pkg/runtime/serializer"
+ "k8s.io/client-go/kubernetes/scheme"
+ "k8s.io/client-go/metadata"
+ "k8s.io/client-go/rest"
+
+ "sigs.k8s.io/controller-runtime/pkg/client/apiutil"
+ "sigs.k8s.io/controller-runtime/pkg/log"
+)
+
+// WarningHandlerOptions are options for configuring a
+// warning handler for the client which is responsible
+// for surfacing API Server warnings.
+type WarningHandlerOptions struct {
+ // SuppressWarnings decides if the warnings from the
+ // API server are suppressed or surfaced in the client.
+ SuppressWarnings bool
+ // AllowDuplicateLogs does not deduplicate the to-be
+ // logged surfaced warnings messages. See
+ // log.WarningHandlerOptions for considerations
+ // regarding deuplication
+ AllowDuplicateLogs bool
+}
+
+// Options are creation options for a Client.
+type Options struct {
+ // 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
+
+ // Opts is used to configure the warning handler responsible for
+ // surfacing and handling warnings messages sent by the API server.
+ Opts WarningHandlerOptions
+}
+
+// New returns a new Client using the provided config and Options.
+// The returned client reads *and* writes directly from the server
+// (it doesn't use object caches). It understands how to work with
+// normal types (both custom resources and aggregated/built-in resources),
+// as well as unstructured types.
+//
+// In the case of normal types, the scheme will be used to look up the
+// corresponding group, version, and kind for the given type. In the
+// case of unstructured types, the group, version, and kind will be extracted
+// from the corresponding fields on the object.
+func New(config *rest.Config, options Options) (Client, error) {
+ return newClient(config, options)
+}
+
+func newClient(config *rest.Config, options Options) (*client, error) {
+ if config == nil {
+ return nil, fmt.Errorf("must provide non-nil rest.Config to client.New")
+ }
+
+ if !options.Opts.SuppressWarnings {
+ // surface warnings
+ logger := log.Log.WithName("KubeAPIWarningLogger")
+ // Set a WarningHandler, the default WarningHandler
+ // is log.KubeAPIWarningLogger with deduplication enabled.
+ // See log.KubeAPIWarningLoggerOptions for considerations
+ // regarding deduplication.
+ rest.SetDefaultWarningHandler(
+ log.NewKubeAPIWarningLogger(
+ logger,
+ log.KubeAPIWarningLoggerOptions{
+ Deduplicate: !options.Opts.AllowDuplicateLogs,
+ },
+ ),
+ )
+ }
+
+ // Init a scheme if none provided
+ if options.Scheme == nil {
+ options.Scheme = scheme.Scheme
+ }
+
+ // Init a Mapper if none provided
+ if options.Mapper == nil {
+ var err error
+ options.Mapper, err = apiutil.NewDynamicRESTMapper(config)
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ clientcache := &clientCache{
+ config: config,
+ scheme: options.Scheme,
+ mapper: options.Mapper,
+ codecs: serializer.NewCodecFactory(options.Scheme),
+
+ structuredResourceByType: make(map[schema.GroupVersionKind]*resourceMeta),
+ unstructuredResourceByType: make(map[schema.GroupVersionKind]*resourceMeta),
+ }
+
+ rawMetaClient, err := metadata.NewForConfig(config)
+ if err != nil {
+ return nil, fmt.Errorf("unable to construct metadata-only client for use as part of client: %w", err)
+ }
+
+ c := &client{
+ typedClient: typedClient{
+ cache: clientcache,
+ paramCodec: runtime.NewParameterCodec(options.Scheme),
+ },
+ unstructuredClient: unstructuredClient{
+ cache: clientcache,
+ paramCodec: noConversionParamCodec{},
+ },
+ metadataClient: metadataClient{
+ client: rawMetaClient,
+ restMapper: options.Mapper,
+ },
+ scheme: options.Scheme,
+ mapper: options.Mapper,
+ }
+
+ return c, nil
+}
+
+var _ Client = &client{}
+
+// 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 client struct {
+ typedClient typedClient
+ unstructuredClient unstructuredClient
+ metadataClient metadataClient
+ scheme *runtime.Scheme
+ mapper meta.RESTMapper
+}
+
+// resetGroupVersionKind is a helper function to restore and preserve GroupVersionKind on an object.
+func (c *client) resetGroupVersionKind(obj runtime.Object, gvk schema.GroupVersionKind) {
+ if gvk != schema.EmptyObjectKind.GroupVersionKind() {
+ if v, ok := obj.(schema.ObjectKind); ok {
+ v.SetGroupVersionKind(gvk)
+ }
+ }
+}
+
+// Scheme returns the scheme this client is using.
+func (c *client) Scheme() *runtime.Scheme {
+ return c.scheme
+}
+
+// RESTMapper returns the scheme this client is using.
+func (c *client) RESTMapper() meta.RESTMapper {
+ return c.mapper
+}
+
+// Create implements client.Client.
+func (c *client) Create(ctx context.Context, obj Object, opts ...CreateOption) error {
+ switch obj.(type) {
+ case *unstructured.Unstructured:
+ return c.unstructuredClient.Create(ctx, obj, opts...)
+ case *metav1.PartialObjectMetadata:
+ return fmt.Errorf("cannot create using only metadata")
+ default:
+ return c.typedClient.Create(ctx, obj, opts...)
+ }
+}
+
+// Update implements client.Client.
+func (c *client) Update(ctx context.Context, obj Object, opts ...UpdateOption) error {
+ defer c.resetGroupVersionKind(obj, obj.GetObjectKind().GroupVersionKind())
+ switch obj.(type) {
+ case *unstructured.Unstructured:
+ return c.unstructuredClient.Update(ctx, obj, opts...)
+ case *metav1.PartialObjectMetadata:
+ return fmt.Errorf("cannot update using only metadata -- did you mean to patch?")
+ default:
+ return c.typedClient.Update(ctx, obj, opts...)
+ }
+}
+
+// Delete implements client.Client.
+func (c *client) Delete(ctx context.Context, obj Object, opts ...DeleteOption) error {
+ switch obj.(type) {
+ case *unstructured.Unstructured:
+ return c.unstructuredClient.Delete(ctx, obj, opts...)
+ case *metav1.PartialObjectMetadata:
+ return c.metadataClient.Delete(ctx, obj, opts...)
+ default:
+ return c.typedClient.Delete(ctx, obj, opts...)
+ }
+}
+
+// DeleteAllOf implements client.Client.
+func (c *client) DeleteAllOf(ctx context.Context, obj Object, opts ...DeleteAllOfOption) error {
+ switch obj.(type) {
+ case *unstructured.Unstructured:
+ return c.unstructuredClient.DeleteAllOf(ctx, obj, opts...)
+ case *metav1.PartialObjectMetadata:
+ return c.metadataClient.DeleteAllOf(ctx, obj, opts...)
+ default:
+ return c.typedClient.DeleteAllOf(ctx, obj, opts...)
+ }
+}
+
+// Patch implements client.Client.
+func (c *client) Patch(ctx context.Context, obj Object, patch Patch, opts ...PatchOption) error {
+ defer c.resetGroupVersionKind(obj, obj.GetObjectKind().GroupVersionKind())
+ switch obj.(type) {
+ case *unstructured.Unstructured:
+ return c.unstructuredClient.Patch(ctx, obj, patch, opts...)
+ case *metav1.PartialObjectMetadata:
+ return c.metadataClient.Patch(ctx, obj, patch, opts...)
+ default:
+ return c.typedClient.Patch(ctx, obj, patch, opts...)
+ }
+}
+
+// Get implements client.Client.
+func (c *client) Get(ctx context.Context, key ObjectKey, obj Object) error {
+ switch obj.(type) {
+ case *unstructured.Unstructured:
+ return c.unstructuredClient.Get(ctx, key, obj)
+ case *metav1.PartialObjectMetadata:
+ // Metadata only object should always preserve the GVK coming in from the caller.
+ defer c.resetGroupVersionKind(obj, obj.GetObjectKind().GroupVersionKind())
+ return c.metadataClient.Get(ctx, key, obj)
+ default:
+ return c.typedClient.Get(ctx, key, obj)
+ }
+}
+
+// List implements client.Client.
+func (c *client) List(ctx context.Context, obj ObjectList, opts ...ListOption) error {
+ switch x := obj.(type) {
+ case *unstructured.UnstructuredList:
+ return c.unstructuredClient.List(ctx, obj, opts...)
+ case *metav1.PartialObjectMetadataList:
+ // Metadata only object should always preserve the GVK.
+ gvk := obj.GetObjectKind().GroupVersionKind()
+ defer c.resetGroupVersionKind(obj, gvk)
+
+ // Call the list client.
+ if err := c.metadataClient.List(ctx, obj, opts...); err != nil {
+ return err
+ }
+
+ // Restore the GVK for each item in the list.
+ itemGVK := schema.GroupVersionKind{
+ Group: gvk.Group,
+ Version: gvk.Version,
+ // TODO: this is producing unsafe guesses that don't actually work,
+ // but it matches ~99% of the cases out there.
+ Kind: strings.TrimSuffix(gvk.Kind, "List"),
+ }
+ for i := range x.Items {
+ item := &x.Items[i]
+ item.SetGroupVersionKind(itemGVK)
+ }
+
+ return nil
+ default:
+ return c.typedClient.List(ctx, obj, opts...)
+ }
+}
+
+// Status implements client.StatusClient.
+func (c *client) Status() StatusWriter {
+ return &statusWriter{client: c}
+}
+
+// statusWriter is client.StatusWriter that writes status subresource.
+type statusWriter struct {
+ client *client
+}
+
+// ensure statusWriter implements client.StatusWriter.
+var _ StatusWriter = &statusWriter{}
+
+// Update implements client.StatusWriter.
+func (sw *statusWriter) Update(ctx context.Context, obj Object, opts ...UpdateOption) error {
+ defer sw.client.resetGroupVersionKind(obj, obj.GetObjectKind().GroupVersionKind())
+ switch obj.(type) {
+ case *unstructured.Unstructured:
+ return sw.client.unstructuredClient.UpdateStatus(ctx, obj, opts...)
+ case *metav1.PartialObjectMetadata:
+ return fmt.Errorf("cannot update status using only metadata -- did you mean to patch?")
+ default:
+ return sw.client.typedClient.UpdateStatus(ctx, obj, opts...)
+ }
+}
+
+// Patch implements client.Client.
+func (sw *statusWriter) Patch(ctx context.Context, obj Object, patch Patch, opts ...PatchOption) error {
+ defer sw.client.resetGroupVersionKind(obj, obj.GetObjectKind().GroupVersionKind())
+ switch obj.(type) {
+ case *unstructured.Unstructured:
+ return sw.client.unstructuredClient.PatchStatus(ctx, obj, patch, opts...)
+ case *metav1.PartialObjectMetadata:
+ return sw.client.metadataClient.PatchStatus(ctx, obj, patch, opts...)
+ default:
+ return sw.client.typedClient.PatchStatus(ctx, obj, patch, opts...)
+ }
+}
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/client/client_cache.go b/vendor/sigs.k8s.io/controller-runtime/pkg/client/client_cache.go
new file mode 100644
index 000000000..857a0b38a
--- /dev/null
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/client/client_cache.go
@@ -0,0 +1,150 @@
+/*
+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 (
+ "strings"
+ "sync"
+
+ "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/apimachinery/pkg/runtime/serializer"
+ "k8s.io/client-go/rest"
+ "sigs.k8s.io/controller-runtime/pkg/client/apiutil"
+)
+
+// clientCache creates and caches rest clients and metadata for Kubernetes types.
+type clientCache struct {
+ // config is the rest.Config to talk to an apiserver
+ config *rest.Config
+
+ // scheme maps go structs to GroupVersionKinds
+ scheme *runtime.Scheme
+
+ // mapper maps GroupVersionKinds to Resources
+ mapper meta.RESTMapper
+
+ // codecs are used to create a REST client for a gvk
+ codecs serializer.CodecFactory
+
+ // structuredResourceByType caches structured type metadata
+ structuredResourceByType map[schema.GroupVersionKind]*resourceMeta
+ // unstructuredResourceByType caches unstructured type metadata
+ unstructuredResourceByType map[schema.GroupVersionKind]*resourceMeta
+ mu sync.RWMutex
+}
+
+// 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.
+func (c *clientCache) newResource(gvk schema.GroupVersionKind, isList, isUnstructured bool) (*resourceMeta, error) {
+ if strings.HasSuffix(gvk.Kind, "List") && isList {
+ // if this was a list, treat it as a request for the item's resource
+ gvk.Kind = gvk.Kind[:len(gvk.Kind)-4]
+ }
+
+ client, err := apiutil.RESTClientForGVK(gvk, isUnstructured, c.config, c.codecs)
+ if err != nil {
+ return nil, err
+ }
+ mapping, err := c.mapper.RESTMapping(gvk.GroupKind(), gvk.Version)
+ if err != nil {
+ return nil, err
+ }
+ return &resourceMeta{Interface: client, mapping: mapping, gvk: gvk}, nil
+}
+
+// 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.
+func (c *clientCache) getResource(obj runtime.Object) (*resourceMeta, error) {
+ gvk, err := apiutil.GVKForObject(obj, c.scheme)
+ if err != nil {
+ return nil, err
+ }
+
+ _, isUnstructured := obj.(*unstructured.Unstructured)
+ _, isUnstructuredList := obj.(*unstructured.UnstructuredList)
+ isUnstructured = isUnstructured || isUnstructuredList
+
+ // It's better to do creation work twice than to not let multiple
+ // people make requests at once
+ c.mu.RLock()
+ resourceByType := c.structuredResourceByType
+ if isUnstructured {
+ resourceByType = c.unstructuredResourceByType
+ }
+ r, known := resourceByType[gvk]
+ c.mu.RUnlock()
+
+ if known {
+ return r, nil
+ }
+
+ // Initialize a new Client
+ c.mu.Lock()
+ defer c.mu.Unlock()
+ r, err = c.newResource(gvk, meta.IsListType(obj), isUnstructured)
+ if err != nil {
+ return nil, err
+ }
+ resourceByType[gvk] = r
+ return r, err
+}
+
+// getObjMeta returns objMeta containing both type and object metadata and state.
+func (c *clientCache) getObjMeta(obj runtime.Object) (*objMeta, error) {
+ r, err := c.getResource(obj)
+ if err != nil {
+ return nil, err
+ }
+ m, err := meta.Accessor(obj)
+ if err != nil {
+ return nil, err
+ }
+ return &objMeta{resourceMeta: r, Object: m}, err
+}
+
+// resourceMeta caches state for a Kubernetes type.
+type resourceMeta struct {
+ // client is the rest client used to talk to the apiserver
+ rest.Interface
+ // gvk is the GroupVersionKind of the resourceMeta
+ gvk schema.GroupVersionKind
+ // mapping is the rest mapping
+ mapping *meta.RESTMapping
+}
+
+// isNamespaced returns true if the type is namespaced.
+func (r *resourceMeta) isNamespaced() bool {
+ return r.mapping.Scope.Name() != meta.RESTScopeNameRoot
+}
+
+// resource returns the resource name of the type.
+func (r *resourceMeta) resource() string {
+ return r.mapping.Resource.Resource
+}
+
+// objMeta stores type and object information about a Kubernetes type.
+type objMeta struct {
+ // resourceMeta contains type information for the object
+ *resourceMeta
+
+ // Object contains meta data for the object instance
+ metav1.Object
+}
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/client/codec.go b/vendor/sigs.k8s.io/controller-runtime/pkg/client/codec.go
new file mode 100644
index 000000000..9c2923106
--- /dev/null
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/client/codec.go
@@ -0,0 +1,40 @@
+/*
+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 client
+
+import (
+ "errors"
+ "net/url"
+
+ "k8s.io/apimachinery/pkg/conversion/queryparams"
+ "k8s.io/apimachinery/pkg/runtime"
+ "k8s.io/apimachinery/pkg/runtime/schema"
+)
+
+var _ runtime.ParameterCodec = noConversionParamCodec{}
+
+// noConversionParamCodec is a no-conversion codec for serializing parameters into URL query strings.
+// it's useful in scenarios with the unstructured client and arbitrary resources.
+type noConversionParamCodec struct{}
+
+func (noConversionParamCodec) EncodeParameters(obj runtime.Object, to schema.GroupVersion) (url.Values, error) {
+ return queryparams.Convert(obj)
+}
+
+func (noConversionParamCodec) DecodeParameters(parameters url.Values, from schema.GroupVersion, into runtime.Object) error {
+ return errors.New("DecodeParameters not implemented on noConversionParamCodec")
+}
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/client/config/config.go b/vendor/sigs.k8s.io/controller-runtime/pkg/client/config/config.go
new file mode 100644
index 000000000..235a7e450
--- /dev/null
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/client/config/config.go
@@ -0,0 +1,157 @@
+/*
+Copyright 2017 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 (
+ "flag"
+ "fmt"
+ "os"
+ "os/user"
+ "path"
+
+ "k8s.io/client-go/rest"
+ "k8s.io/client-go/tools/clientcmd"
+ clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
+ logf "sigs.k8s.io/controller-runtime/pkg/internal/log"
+)
+
+var (
+ kubeconfig string
+ log = logf.RuntimeLog.WithName("client").WithName("config")
+)
+
+func init() {
+ // TODO: Fix this to allow double vendoring this library but still register flags on behalf of users
+ flag.StringVar(&kubeconfig, "kubeconfig", "",
+ "Paths to a kubeconfig. Only required if out-of-cluster.")
+}
+
+// GetConfig creates a *rest.Config for talking to a Kubernetes API server.
+// If --kubeconfig is set, will use the kubeconfig file at that location. Otherwise will assume running
+// in cluster and use the cluster provided kubeconfig.
+//
+// It also applies saner defaults for QPS and burst based on the Kubernetes
+// controller manager defaults (20 QPS, 30 burst)
+//
+// Config precedence
+//
+// * --kubeconfig flag pointing at a file
+//
+// * KUBECONFIG environment variable pointing at a file
+//
+// * In-cluster config if running in cluster
+//
+// * $HOME/.kube/config if exists.
+func GetConfig() (*rest.Config, error) {
+ return GetConfigWithContext("")
+}
+
+// GetConfigWithContext creates a *rest.Config for talking to a Kubernetes API server with a specific context.
+// If --kubeconfig is set, will use the kubeconfig file at that location. Otherwise will assume running
+// in cluster and use the cluster provided kubeconfig.
+//
+// It also applies saner defaults for QPS and burst based on the Kubernetes
+// controller manager defaults (20 QPS, 30 burst)
+//
+// Config precedence
+//
+// * --kubeconfig flag pointing at a file
+//
+// * KUBECONFIG environment variable pointing at a file
+//
+// * In-cluster config if running in cluster
+//
+// * $HOME/.kube/config if exists.
+func GetConfigWithContext(context string) (*rest.Config, error) {
+ cfg, err := loadConfig(context)
+ if err != nil {
+ return nil, err
+ }
+
+ if cfg.QPS == 0.0 {
+ cfg.QPS = 20.0
+ cfg.Burst = 30.0
+ }
+
+ return cfg, nil
+}
+
+// loadInClusterConfig is a function used to load the in-cluster
+// Kubernetes client config. This variable makes is possible to
+// test the precedence of loading the config.
+var loadInClusterConfig = rest.InClusterConfig
+
+// loadConfig loads a REST Config as per the rules specified in GetConfig.
+func loadConfig(context string) (*rest.Config, error) {
+ // If a flag is specified with the config location, use that
+ if len(kubeconfig) > 0 {
+ return loadConfigWithContext("", &clientcmd.ClientConfigLoadingRules{ExplicitPath: kubeconfig}, context)
+ }
+
+ // If the recommended kubeconfig env variable is not specified,
+ // try the in-cluster config.
+ kubeconfigPath := os.Getenv(clientcmd.RecommendedConfigPathEnvVar)
+ if len(kubeconfigPath) == 0 {
+ if c, err := loadInClusterConfig(); err == nil {
+ return c, nil
+ }
+ }
+
+ // If the recommended kubeconfig env variable is set, or there
+ // is no in-cluster config, try the default recommended locations.
+ //
+ // NOTE: For default config file locations, upstream only checks
+ // $HOME for the user's home directory, but we can also try
+ // os/user.HomeDir when $HOME is unset.
+ //
+ // TODO(jlanford): could this be done upstream?
+ loadingRules := clientcmd.NewDefaultClientConfigLoadingRules()
+ if _, ok := os.LookupEnv("HOME"); !ok {
+ u, err := user.Current()
+ if err != nil {
+ return nil, fmt.Errorf("could not get current user: %v", err)
+ }
+ loadingRules.Precedence = append(loadingRules.Precedence, path.Join(u.HomeDir, clientcmd.RecommendedHomeDir, clientcmd.RecommendedFileName))
+ }
+
+ return loadConfigWithContext("", loadingRules, context)
+}
+
+func loadConfigWithContext(apiServerURL string, loader clientcmd.ClientConfigLoader, context string) (*rest.Config, error) {
+ return clientcmd.NewNonInteractiveDeferredLoadingClientConfig(
+ loader,
+ &clientcmd.ConfigOverrides{
+ ClusterInfo: clientcmdapi.Cluster{
+ Server: apiServerURL,
+ },
+ CurrentContext: context,
+ }).ClientConfig()
+}
+
+// GetConfigOrDie creates a *rest.Config for talking to a Kubernetes apiserver.
+// If --kubeconfig is set, will use the kubeconfig file at that location. Otherwise will assume running
+// in cluster and use the cluster provided kubeconfig.
+//
+// Will log an error and exit if there is an error creating the rest.Config.
+func GetConfigOrDie() *rest.Config {
+ config, err := GetConfig()
+ if err != nil {
+ log.Error(err, "unable to get kubeconfig")
+ os.Exit(1)
+ }
+ return config
+}
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/client/config/doc.go b/vendor/sigs.k8s.io/controller-runtime/pkg/client/config/doc.go
new file mode 100644
index 000000000..796c9cf59
--- /dev/null
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/client/config/doc.go
@@ -0,0 +1,18 @@
+/*
+Copyright 2017 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+// Package config contains libraries for initializing REST configs for talking to the Kubernetes API
+package config
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/client/doc.go b/vendor/sigs.k8s.io/controller-runtime/pkg/client/doc.go
new file mode 100644
index 000000000..2965e5fa9
--- /dev/null
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/client/doc.go
@@ -0,0 +1,49 @@
+/*
+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 contains functionality for interacting with Kubernetes API
+// servers.
+//
+// Clients
+//
+// Clients are split into two interfaces -- Readers and Writers. Readers
+// get and list, while writers create, update, and delete.
+//
+// The New function can be used to create a new client that talks directly
+// to the API server.
+//
+// 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
+// be used to have a client whose Reader is different from the Writer.
+//
+// Options
+//
+// Many client operations in Kubernetes support options. These options are
+// represented as variadic arguments at the end of a given method call.
+// For instance, to use a label selector on list, you can call
+// err := someReader.List(context.Background(), &podList, client.MatchingLabels{"somelabel": "someval"})
+//
+// Indexing
+//
+// Indexes may be added to caches using a FieldIndexer. This allows you to easily
+// and efficiently look up objects with certain properties. You can then make
+// use of the index by specifying a field selector on calls to List on the Reader
+// corresponding to the given Cache.
+//
+// For instance, a Secret controller might have an index on the
+// `.spec.volumes.secret.secretName` field in Pod objects, so that it could
+// easily look up all pods that reference a given secret.
+package client
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/client/dryrun.go b/vendor/sigs.k8s.io/controller-runtime/pkg/client/dryrun.go
new file mode 100644
index 000000000..ea25ea253
--- /dev/null
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/client/dryrun.go
@@ -0,0 +1,106 @@
+/*
+Copyright 2020 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package client
+
+import (
+ "context"
+
+ "k8s.io/apimachinery/pkg/api/meta"
+ "k8s.io/apimachinery/pkg/runtime"
+)
+
+// NewDryRunClient wraps an existing client and enforces DryRun mode
+// on all mutating api calls.
+func NewDryRunClient(c Client) Client {
+ return &dryRunClient{client: c}
+}
+
+var _ Client = &dryRunClient{}
+
+// dryRunClient is a Client that wraps another Client in order to enforce DryRun mode.
+type dryRunClient struct {
+ client Client
+}
+
+// Scheme returns the scheme this client is using.
+func (c *dryRunClient) Scheme() *runtime.Scheme {
+ return c.client.Scheme()
+}
+
+// RESTMapper returns the rest mapper this client is using.
+func (c *dryRunClient) RESTMapper() meta.RESTMapper {
+ return c.client.RESTMapper()
+}
+
+// Create implements client.Client.
+func (c *dryRunClient) Create(ctx context.Context, obj Object, opts ...CreateOption) error {
+ return c.client.Create(ctx, obj, append(opts, DryRunAll)...)
+}
+
+// Update implements client.Client.
+func (c *dryRunClient) Update(ctx context.Context, obj Object, opts ...UpdateOption) error {
+ return c.client.Update(ctx, obj, append(opts, DryRunAll)...)
+}
+
+// Delete implements client.Client.
+func (c *dryRunClient) Delete(ctx context.Context, obj Object, opts ...DeleteOption) error {
+ return c.client.Delete(ctx, obj, append(opts, DryRunAll)...)
+}
+
+// DeleteAllOf implements client.Client.
+func (c *dryRunClient) DeleteAllOf(ctx context.Context, obj Object, opts ...DeleteAllOfOption) error {
+ return c.client.DeleteAllOf(ctx, obj, append(opts, DryRunAll)...)
+}
+
+// Patch implements client.Client.
+func (c *dryRunClient) Patch(ctx context.Context, obj Object, patch Patch, opts ...PatchOption) error {
+ return c.client.Patch(ctx, obj, patch, append(opts, DryRunAll)...)
+}
+
+// Get implements client.Client.
+func (c *dryRunClient) Get(ctx context.Context, key ObjectKey, obj Object) error {
+ return c.client.Get(ctx, key, obj)
+}
+
+// List implements client.Client.
+func (c *dryRunClient) List(ctx context.Context, obj ObjectList, opts ...ListOption) error {
+ return c.client.List(ctx, obj, opts...)
+}
+
+// Status implements client.StatusClient.
+func (c *dryRunClient) Status() StatusWriter {
+ return &dryRunStatusWriter{client: c.client.Status()}
+}
+
+// ensure dryRunStatusWriter implements client.StatusWriter.
+var _ StatusWriter = &dryRunStatusWriter{}
+
+// dryRunStatusWriter is client.StatusWriter that writes status subresource with dryRun mode
+// enforced.
+type dryRunStatusWriter struct {
+ client StatusWriter
+}
+
+// Update implements client.StatusWriter.
+func (sw *dryRunStatusWriter) Update(ctx context.Context, obj Object, opts ...UpdateOption) error {
+ return sw.client.Update(ctx, obj, append(opts, DryRunAll)...)
+}
+
+// Patch implements client.StatusWriter.
+func (sw *dryRunStatusWriter) Patch(ctx context.Context, obj Object, patch Patch, opts ...PatchOption) error {
+ return sw.client.Patch(ctx, obj, patch, append(opts, DryRunAll)...)
+}
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/client/interfaces.go b/vendor/sigs.k8s.io/controller-runtime/pkg/client/interfaces.go
new file mode 100644
index 000000000..58c2ece15
--- /dev/null
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/client/interfaces.go
@@ -0,0 +1,145 @@
+/*
+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"
+
+ apierrors "k8s.io/apimachinery/pkg/api/errors"
+
+ "k8s.io/apimachinery/pkg/api/meta"
+ "k8s.io/apimachinery/pkg/runtime"
+ "k8s.io/apimachinery/pkg/types"
+ "k8s.io/apimachinery/pkg/watch"
+)
+
+// ObjectKey identifies a Kubernetes Object.
+type ObjectKey = types.NamespacedName
+
+// ObjectKeyFromObject returns the ObjectKey given a runtime.Object.
+func ObjectKeyFromObject(obj Object) ObjectKey {
+ return ObjectKey{Namespace: obj.GetNamespace(), Name: obj.GetName()}
+}
+
+// Patch is a patch that can be applied to a Kubernetes object.
+type Patch interface {
+ // Type is the PatchType of the patch.
+ Type() types.PatchType
+ // Data is the raw data representing the patch.
+ Data(obj Object) ([]byte, error)
+}
+
+// TODO(directxman12): is there a sane way to deal with get/delete options?
+
+// Reader knows how to read and list Kubernetes objects.
+type Reader interface {
+ // Get retrieves an obj for the given object key from the Kubernetes Cluster.
+ // obj must be a struct pointer so that obj can be updated with the response
+ // returned by the Server.
+ Get(ctx context.Context, key ObjectKey, obj Object) error
+
+ // List retrieves list of objects for a given namespace and list options. On a
+ // successful call, Items field in the list will be populated with the
+ // result returned from the server.
+ List(ctx context.Context, list ObjectList, opts ...ListOption) error
+}
+
+// Writer knows how to create, delete, and update Kubernetes objects.
+type Writer interface {
+ // Create saves the object obj in the Kubernetes cluster.
+ Create(ctx context.Context, obj Object, opts ...CreateOption) error
+
+ // Delete deletes the given obj from Kubernetes cluster.
+ Delete(ctx context.Context, obj Object, opts ...DeleteOption) error
+
+ // Update updates the given obj in the Kubernetes cluster. obj must be a
+ // struct pointer so that obj can be updated with the content returned by the Server.
+ Update(ctx context.Context, obj Object, opts ...UpdateOption) error
+
+ // Patch patches the given obj in the Kubernetes cluster. obj must be a
+ // struct pointer so that obj can be updated with the content returned by the Server.
+ Patch(ctx context.Context, obj Object, patch Patch, opts ...PatchOption) error
+
+ // DeleteAllOf deletes all objects of the given type matching the given options.
+ DeleteAllOf(ctx context.Context, obj Object, opts ...DeleteAllOfOption) error
+}
+
+// StatusClient knows how to create a client which can update status subresource
+// for kubernetes objects.
+type StatusClient interface {
+ Status() StatusWriter
+}
+
+// StatusWriter knows how to update status subresource of a Kubernetes object.
+type StatusWriter interface {
+ // Update updates the fields corresponding to the status subresource for the
+ // given obj. obj must be a struct pointer so that obj can be updated
+ // with the content returned by the Server.
+ Update(ctx context.Context, obj Object, opts ...UpdateOption) error
+
+ // Patch patches the given object's subresource. obj must be a struct
+ // pointer so that obj can be updated with the content returned by the
+ // Server.
+ Patch(ctx context.Context, obj Object, patch Patch, opts ...PatchOption) error
+}
+
+// Client knows how to perform CRUD operations on Kubernetes objects.
+type Client interface {
+ Reader
+ Writer
+ StatusClient
+
+ // Scheme returns the scheme this client is using.
+ Scheme() *runtime.Scheme
+ // RESTMapper returns the rest this client is using.
+ RESTMapper() meta.RESTMapper
+}
+
+// WithWatch supports Watch on top of the CRUD operations supported by
+// the normal Client. Its intended use-case are CLI apps that need to wait for
+// events.
+type WithWatch interface {
+ Client
+ Watch(ctx context.Context, obj ObjectList, opts ...ListOption) (watch.Interface, error)
+}
+
+// IndexerFunc knows how to take an object and turn it into a series
+// of non-namespaced keys. Namespaced objects are automatically given
+// namespaced and non-spaced variants, so keys do not need to include namespace.
+type IndexerFunc func(Object) []string
+
+// FieldIndexer knows how to index over a particular "field" such that it
+// can later be used by a field selector.
+type FieldIndexer interface {
+ // IndexFields adds an index with the given field name on the given object type
+ // by using the given function to extract the value for that field. If you want
+ // compatibility with the Kubernetes API server, only return one key, and only use
+ // fields that the API server supports. Otherwise, you can return multiple keys,
+ // and "equality" in the field selector means that at least one key matches the value.
+ // The FieldIndexer will automatically take care of indexing over namespace
+ // and supporting efficient all-namespace queries.
+ IndexField(ctx context.Context, obj Object, field string, extractValue IndexerFunc) error
+}
+
+// IgnoreNotFound returns nil on NotFound errors.
+// All other values that are not NotFound errors or nil are returned unmodified.
+func IgnoreNotFound(err error) error {
+ if apierrors.IsNotFound(err) {
+ return nil
+ }
+ return err
+}
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/client/metadata_client.go b/vendor/sigs.k8s.io/controller-runtime/pkg/client/metadata_client.go
new file mode 100644
index 000000000..59747463a
--- /dev/null
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/client/metadata_client.go
@@ -0,0 +1,195 @@
+/*
+Copyright 2020 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package client
+
+import (
+ "context"
+ "fmt"
+ "strings"
+
+ "k8s.io/apimachinery/pkg/api/meta"
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ "k8s.io/apimachinery/pkg/runtime/schema"
+ "k8s.io/client-go/metadata"
+)
+
+// TODO(directxman12): we could rewrite this on top of the low-level REST
+// client to avoid the extra shallow copy at the end, but I'm not sure it's
+// worth it -- the metadata client deals with falling back to loading the whole
+// object on older API servers, etc, and we'd have to reproduce that.
+
+// metadataClient is a client that reads & writes metadata-only requests to/from the API server.
+type metadataClient struct {
+ client metadata.Interface
+ restMapper meta.RESTMapper
+}
+
+func (mc *metadataClient) getResourceInterface(gvk schema.GroupVersionKind, ns string) (metadata.ResourceInterface, error) {
+ mapping, err := mc.restMapper.RESTMapping(gvk.GroupKind(), gvk.Version)
+ if err != nil {
+ return nil, err
+ }
+ if mapping.Scope.Name() == meta.RESTScopeNameRoot {
+ return mc.client.Resource(mapping.Resource), nil
+ }
+ return mc.client.Resource(mapping.Resource).Namespace(ns), nil
+}
+
+// Delete implements client.Client.
+func (mc *metadataClient) Delete(ctx context.Context, obj Object, opts ...DeleteOption) error {
+ metadata, ok := obj.(*metav1.PartialObjectMetadata)
+ if !ok {
+ return fmt.Errorf("metadata client did not understand object: %T", obj)
+ }
+
+ resInt, err := mc.getResourceInterface(metadata.GroupVersionKind(), metadata.Namespace)
+ if err != nil {
+ return err
+ }
+
+ deleteOpts := DeleteOptions{}
+ deleteOpts.ApplyOptions(opts)
+
+ return resInt.Delete(ctx, metadata.Name, *deleteOpts.AsDeleteOptions())
+}
+
+// DeleteAllOf implements client.Client.
+func (mc *metadataClient) DeleteAllOf(ctx context.Context, obj Object, opts ...DeleteAllOfOption) error {
+ metadata, ok := obj.(*metav1.PartialObjectMetadata)
+ if !ok {
+ return fmt.Errorf("metadata client did not understand object: %T", obj)
+ }
+
+ deleteAllOfOpts := DeleteAllOfOptions{}
+ deleteAllOfOpts.ApplyOptions(opts)
+
+ resInt, err := mc.getResourceInterface(metadata.GroupVersionKind(), deleteAllOfOpts.ListOptions.Namespace)
+ if err != nil {
+ return err
+ }
+
+ return resInt.DeleteCollection(ctx, *deleteAllOfOpts.AsDeleteOptions(), *deleteAllOfOpts.AsListOptions())
+}
+
+// Patch implements client.Client.
+func (mc *metadataClient) Patch(ctx context.Context, obj Object, patch Patch, opts ...PatchOption) error {
+ metadata, ok := obj.(*metav1.PartialObjectMetadata)
+ if !ok {
+ return fmt.Errorf("metadata client did not understand object: %T", obj)
+ }
+
+ gvk := metadata.GroupVersionKind()
+ resInt, err := mc.getResourceInterface(gvk, metadata.Namespace)
+ if err != nil {
+ return err
+ }
+
+ data, err := patch.Data(obj)
+ if err != nil {
+ return err
+ }
+
+ patchOpts := &PatchOptions{}
+ patchOpts.ApplyOptions(opts)
+
+ res, err := resInt.Patch(ctx, metadata.Name, patch.Type(), data, *patchOpts.AsPatchOptions())
+ if err != nil {
+ return err
+ }
+ *metadata = *res
+ metadata.SetGroupVersionKind(gvk) // restore the GVK, which isn't set on metadata
+ return nil
+}
+
+// Get implements client.Client.
+func (mc *metadataClient) Get(ctx context.Context, key ObjectKey, obj Object) error {
+ metadata, ok := obj.(*metav1.PartialObjectMetadata)
+ if !ok {
+ return fmt.Errorf("metadata client did not understand object: %T", obj)
+ }
+
+ gvk := metadata.GroupVersionKind()
+
+ resInt, err := mc.getResourceInterface(gvk, key.Namespace)
+ if err != nil {
+ return err
+ }
+
+ res, err := resInt.Get(ctx, key.Name, metav1.GetOptions{})
+ if err != nil {
+ return err
+ }
+ *metadata = *res
+ metadata.SetGroupVersionKind(gvk) // restore the GVK, which isn't set on metadata
+ return nil
+}
+
+// List implements client.Client.
+func (mc *metadataClient) List(ctx context.Context, obj ObjectList, opts ...ListOption) error {
+ metadata, ok := obj.(*metav1.PartialObjectMetadataList)
+ if !ok {
+ return fmt.Errorf("metadata client did not understand object: %T", obj)
+ }
+
+ gvk := metadata.GroupVersionKind()
+ if strings.HasSuffix(gvk.Kind, "List") {
+ gvk.Kind = gvk.Kind[:len(gvk.Kind)-4]
+ }
+
+ listOpts := ListOptions{}
+ listOpts.ApplyOptions(opts)
+
+ resInt, err := mc.getResourceInterface(gvk, listOpts.Namespace)
+ if err != nil {
+ return err
+ }
+
+ res, err := resInt.List(ctx, *listOpts.AsListOptions())
+ if err != nil {
+ return err
+ }
+ *metadata = *res
+ metadata.SetGroupVersionKind(gvk) // restore the GVK, which isn't set on metadata
+ return nil
+}
+
+func (mc *metadataClient) PatchStatus(ctx context.Context, obj Object, patch Patch, opts ...PatchOption) error {
+ metadata, ok := obj.(*metav1.PartialObjectMetadata)
+ if !ok {
+ return fmt.Errorf("metadata client did not understand object: %T", obj)
+ }
+
+ gvk := metadata.GroupVersionKind()
+ resInt, err := mc.getResourceInterface(gvk, metadata.Namespace)
+ if err != nil {
+ return err
+ }
+
+ data, err := patch.Data(obj)
+ if err != nil {
+ return err
+ }
+
+ patchOpts := &PatchOptions{}
+ res, err := resInt.Patch(ctx, metadata.Name, patch.Type(), data, *patchOpts.AsPatchOptions(), "status")
+ if err != nil {
+ return err
+ }
+ *metadata = *res
+ metadata.SetGroupVersionKind(gvk) // restore the GVK, which isn't set on metadata
+ return nil
+}
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/client/namespaced_client.go b/vendor/sigs.k8s.io/controller-runtime/pkg/client/namespaced_client.go
new file mode 100644
index 000000000..557598727
--- /dev/null
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/client/namespaced_client.go
@@ -0,0 +1,213 @@
+/*
+Copyright 2020 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package client
+
+import (
+ "context"
+ "fmt"
+
+ "k8s.io/apimachinery/pkg/api/meta"
+ "k8s.io/apimachinery/pkg/runtime"
+ "sigs.k8s.io/controller-runtime/pkg/internal/objectutil"
+)
+
+// NewNamespacedClient wraps an existing client enforcing the namespace value.
+// All functions using this client will have the same namespace declared here.
+func NewNamespacedClient(c Client, ns string) Client {
+ return &namespacedClient{
+ client: c,
+ namespace: ns,
+ }
+}
+
+var _ Client = &namespacedClient{}
+
+// namespacedClient is a Client that wraps another Client in order to enforce the specified namespace value.
+type namespacedClient struct {
+ namespace string
+ client Client
+}
+
+// Scheme returns the scheme this client is using.
+func (n *namespacedClient) Scheme() *runtime.Scheme {
+ return n.client.Scheme()
+}
+
+// RESTMapper returns the scheme this client is using.
+func (n *namespacedClient) RESTMapper() meta.RESTMapper {
+ return n.client.RESTMapper()
+}
+
+// Create implements clinet.Client.
+func (n *namespacedClient) Create(ctx context.Context, obj Object, opts ...CreateOption) error {
+ isNamespaceScoped, err := objectutil.IsAPINamespaced(obj, n.Scheme(), n.RESTMapper())
+ if err != nil {
+ return fmt.Errorf("error finding the scope of the object: %v", err)
+ }
+
+ objectNamespace := obj.GetNamespace()
+ if objectNamespace != n.namespace && objectNamespace != "" {
+ return fmt.Errorf("namespace %s of the object %s does not match the namespace %s on the client", objectNamespace, obj.GetName(), n.namespace)
+ }
+
+ if isNamespaceScoped && objectNamespace == "" {
+ obj.SetNamespace(n.namespace)
+ }
+ return n.client.Create(ctx, obj, opts...)
+}
+
+// Update implements client.Client.
+func (n *namespacedClient) Update(ctx context.Context, obj Object, opts ...UpdateOption) error {
+ isNamespaceScoped, err := objectutil.IsAPINamespaced(obj, n.Scheme(), n.RESTMapper())
+ if err != nil {
+ return fmt.Errorf("error finding the scope of the object: %v", err)
+ }
+
+ objectNamespace := obj.GetNamespace()
+ if objectNamespace != n.namespace && objectNamespace != "" {
+ return fmt.Errorf("namespace %s of the object %s does not match the namespace %s on the client", objectNamespace, obj.GetName(), n.namespace)
+ }
+
+ if isNamespaceScoped && objectNamespace == "" {
+ obj.SetNamespace(n.namespace)
+ }
+ return n.client.Update(ctx, obj, opts...)
+}
+
+// Delete implements client.Client.
+func (n *namespacedClient) Delete(ctx context.Context, obj Object, opts ...DeleteOption) error {
+ isNamespaceScoped, err := objectutil.IsAPINamespaced(obj, n.Scheme(), n.RESTMapper())
+ if err != nil {
+ return fmt.Errorf("error finding the scope of the object: %v", err)
+ }
+
+ objectNamespace := obj.GetNamespace()
+ if objectNamespace != n.namespace && objectNamespace != "" {
+ return fmt.Errorf("namespace %s of the object %s does not match the namespace %s on the client", objectNamespace, obj.GetName(), n.namespace)
+ }
+
+ if isNamespaceScoped && objectNamespace == "" {
+ obj.SetNamespace(n.namespace)
+ }
+ return n.client.Delete(ctx, obj, opts...)
+}
+
+// DeleteAllOf implements client.Client.
+func (n *namespacedClient) DeleteAllOf(ctx context.Context, obj Object, opts ...DeleteAllOfOption) error {
+ isNamespaceScoped, err := objectutil.IsAPINamespaced(obj, n.Scheme(), n.RESTMapper())
+ if err != nil {
+ return fmt.Errorf("error finding the scope of the object: %v", err)
+ }
+
+ if isNamespaceScoped {
+ opts = append(opts, InNamespace(n.namespace))
+ }
+ return n.client.DeleteAllOf(ctx, obj, opts...)
+}
+
+// Patch implements client.Client.
+func (n *namespacedClient) Patch(ctx context.Context, obj Object, patch Patch, opts ...PatchOption) error {
+ isNamespaceScoped, err := objectutil.IsAPINamespaced(obj, n.Scheme(), n.RESTMapper())
+ if err != nil {
+ return fmt.Errorf("error finding the scope of the object: %v", err)
+ }
+
+ objectNamespace := obj.GetNamespace()
+ if objectNamespace != n.namespace && objectNamespace != "" {
+ return fmt.Errorf("namespace %s of the object %s does not match the namespace %s on the client", objectNamespace, obj.GetName(), n.namespace)
+ }
+
+ if isNamespaceScoped && objectNamespace == "" {
+ obj.SetNamespace(n.namespace)
+ }
+ return n.client.Patch(ctx, obj, patch, opts...)
+}
+
+// Get implements client.Client.
+func (n *namespacedClient) Get(ctx context.Context, key ObjectKey, obj Object) error {
+ isNamespaceScoped, err := objectutil.IsAPINamespaced(obj, n.Scheme(), n.RESTMapper())
+ if err != nil {
+ return fmt.Errorf("error finding the scope of the object: %v", err)
+ }
+ if isNamespaceScoped {
+ if key.Namespace != "" && key.Namespace != n.namespace {
+ return fmt.Errorf("namespace %s provided for the object %s does not match the namesapce %s on the client", key.Namespace, obj.GetName(), n.namespace)
+ }
+ key.Namespace = n.namespace
+ }
+ return n.client.Get(ctx, key, obj)
+}
+
+// List implements client.Client.
+func (n *namespacedClient) List(ctx context.Context, obj ObjectList, opts ...ListOption) error {
+ if n.namespace != "" {
+ opts = append(opts, InNamespace(n.namespace))
+ }
+ return n.client.List(ctx, obj, opts...)
+}
+
+// Status implements client.StatusClient.
+func (n *namespacedClient) Status() StatusWriter {
+ return &namespacedClientStatusWriter{StatusClient: n.client.Status(), namespace: n.namespace, namespacedclient: n}
+}
+
+// ensure namespacedClientStatusWriter implements client.StatusWriter.
+var _ StatusWriter = &namespacedClientStatusWriter{}
+
+type namespacedClientStatusWriter struct {
+ StatusClient StatusWriter
+ namespace string
+ namespacedclient Client
+}
+
+// Update implements client.StatusWriter.
+func (nsw *namespacedClientStatusWriter) Update(ctx context.Context, obj Object, opts ...UpdateOption) error {
+ isNamespaceScoped, err := objectutil.IsAPINamespaced(obj, nsw.namespacedclient.Scheme(), nsw.namespacedclient.RESTMapper())
+
+ if err != nil {
+ return fmt.Errorf("error finding the scope of the object: %v", err)
+ }
+
+ objectNamespace := obj.GetNamespace()
+ if objectNamespace != nsw.namespace && objectNamespace != "" {
+ return fmt.Errorf("namespace %s of the object %s does not match the namespace %s on the client", objectNamespace, obj.GetName(), nsw.namespace)
+ }
+
+ if isNamespaceScoped && objectNamespace == "" {
+ obj.SetNamespace(nsw.namespace)
+ }
+ return nsw.StatusClient.Update(ctx, obj, opts...)
+}
+
+// Patch implements client.StatusWriter.
+func (nsw *namespacedClientStatusWriter) Patch(ctx context.Context, obj Object, patch Patch, opts ...PatchOption) error {
+ isNamespaceScoped, err := objectutil.IsAPINamespaced(obj, nsw.namespacedclient.Scheme(), nsw.namespacedclient.RESTMapper())
+
+ if err != nil {
+ return fmt.Errorf("error finding the scope of the object: %v", err)
+ }
+
+ objectNamespace := obj.GetNamespace()
+ if objectNamespace != nsw.namespace && objectNamespace != "" {
+ return fmt.Errorf("namespace %s of the object %s does not match the namespace %s on the client", objectNamespace, obj.GetName(), nsw.namespace)
+ }
+
+ if isNamespaceScoped && objectNamespace == "" {
+ obj.SetNamespace(nsw.namespace)
+ }
+ return nsw.StatusClient.Patch(ctx, obj, patch, opts...)
+}
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/client/object.go b/vendor/sigs.k8s.io/controller-runtime/pkg/client/object.go
new file mode 100644
index 000000000..31e334d6c
--- /dev/null
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/client/object.go
@@ -0,0 +1,77 @@
+/*
+Copyright 2020 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package client
+
+import (
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ "k8s.io/apimachinery/pkg/runtime"
+)
+
+// Object is a Kubernetes object, allows functions to work indistinctly with
+// any resource that implements both Object interfaces.
+//
+// Semantically, these are objects which are both serializable (runtime.Object)
+// and identifiable (metav1.Object) -- think any object which you could write
+// as YAML or JSON, and then `kubectl create`.
+//
+// Code-wise, this means that any object which embeds both ObjectMeta (which
+// provides metav1.Object) and TypeMeta (which provides half of runtime.Object)
+// and has a `DeepCopyObject` implementation (the other half of runtime.Object)
+// will implement this by default.
+//
+// For example, nearly all the built-in types are Objects, as well as all
+// KubeBuilder-generated CRDs (unless you do something real funky to them).
+//
+// By and large, most things that implement runtime.Object also implement
+// Object -- it's very rare to have *just* a runtime.Object implementation (the
+// cases tend to be funky built-in types like Webhook payloads that don't have
+// a `metadata` field).
+//
+// Notice that XYZList types are distinct: they implement ObjectList instead.
+type Object interface {
+ metav1.Object
+ runtime.Object
+}
+
+// ObjectList is a Kubernetes object list, allows functions to work
+// indistinctly with any resource that implements both runtime.Object and
+// metav1.ListInterface interfaces.
+//
+// Semantically, this is any object which may be serialized (ObjectMeta), and
+// is a kubernetes list wrapper (has items, pagination fields, etc) -- think
+// the wrapper used in a response from a `kubectl list --output yaml` call.
+//
+// Code-wise, this means that any object which embedds both ListMeta (which
+// provides metav1.ListInterface) and TypeMeta (which provides half of
+// runtime.Object) and has a `DeepCopyObject` implementation (the other half of
+// runtime.Object) will implement this by default.
+//
+// For example, nearly all the built-in XYZList types are ObjectLists, as well
+// as the XYZList types for all KubeBuilder-generated CRDs (unless you do
+// something real funky to them).
+//
+// By and large, most things that are XYZList and implement runtime.Object also
+// implement ObjectList -- it's very rare to have *just* a runtime.Object
+// implementation (the cases tend to be funky built-in types like Webhook
+// payloads that don't have a `metadata` field).
+//
+// This is similar to Object, which is almost always implemented by the items
+// in the list themselves.
+type ObjectList interface {
+ metav1.ListInterface
+ runtime.Object
+}
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/client/options.go b/vendor/sigs.k8s.io/controller-runtime/pkg/client/options.go
new file mode 100644
index 000000000..aa2299eac
--- /dev/null
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/client/options.go
@@ -0,0 +1,697 @@
+/*
+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 (
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ "k8s.io/apimachinery/pkg/fields"
+ "k8s.io/apimachinery/pkg/labels"
+ "k8s.io/apimachinery/pkg/selection"
+)
+
+// {{{ "Functional" Option Interfaces
+
+// CreateOption is some configuration that modifies options for a create request.
+type CreateOption interface {
+ // ApplyToCreate applies this configuration to the given create options.
+ ApplyToCreate(*CreateOptions)
+}
+
+// DeleteOption is some configuration that modifies options for a delete request.
+type DeleteOption interface {
+ // ApplyToDelete applies this configuration to the given delete options.
+ ApplyToDelete(*DeleteOptions)
+}
+
+// ListOption is some configuration that modifies options for a list request.
+type ListOption interface {
+ // ApplyToList applies this configuration to the given list options.
+ ApplyToList(*ListOptions)
+}
+
+// UpdateOption is some configuration that modifies options for a update request.
+type UpdateOption interface {
+ // ApplyToUpdate applies this configuration to the given update options.
+ ApplyToUpdate(*UpdateOptions)
+}
+
+// PatchOption is some configuration that modifies options for a patch request.
+type PatchOption interface {
+ // ApplyToPatch applies this configuration to the given patch options.
+ ApplyToPatch(*PatchOptions)
+}
+
+// DeleteAllOfOption is some configuration that modifies options for a delete request.
+type DeleteAllOfOption interface {
+ // ApplyToDeleteAllOf applies this configuration to the given deletecollection options.
+ ApplyToDeleteAllOf(*DeleteAllOfOptions)
+}
+
+// }}}
+
+// {{{ Multi-Type Options
+
+// DryRunAll sets the "dry run" option to "all", executing all
+// validation, etc without persisting the change to storage.
+var DryRunAll = dryRunAll{}
+
+type dryRunAll struct{}
+
+// ApplyToCreate applies this configuration to the given create options.
+func (dryRunAll) ApplyToCreate(opts *CreateOptions) {
+ opts.DryRun = []string{metav1.DryRunAll}
+}
+
+// ApplyToUpdate applies this configuration to the given update options.
+func (dryRunAll) ApplyToUpdate(opts *UpdateOptions) {
+ opts.DryRun = []string{metav1.DryRunAll}
+}
+
+// ApplyToPatch applies this configuration to the given patch options.
+func (dryRunAll) ApplyToPatch(opts *PatchOptions) {
+ opts.DryRun = []string{metav1.DryRunAll}
+}
+
+// ApplyToPatch applies this configuration to the given delete options.
+func (dryRunAll) ApplyToDelete(opts *DeleteOptions) {
+ opts.DryRun = []string{metav1.DryRunAll}
+}
+func (dryRunAll) ApplyToDeleteAllOf(opts *DeleteAllOfOptions) {
+ opts.DryRun = []string{metav1.DryRunAll}
+}
+
+// FieldOwner set the field manager name for the given server-side apply patch.
+type FieldOwner string
+
+// ApplyToPatch applies this configuration to the given patch options.
+func (f FieldOwner) ApplyToPatch(opts *PatchOptions) {
+ opts.FieldManager = string(f)
+}
+
+// ApplyToCreate applies this configuration to the given create options.
+func (f FieldOwner) ApplyToCreate(opts *CreateOptions) {
+ opts.FieldManager = string(f)
+}
+
+// ApplyToUpdate applies this configuration to the given update options.
+func (f FieldOwner) ApplyToUpdate(opts *UpdateOptions) {
+ opts.FieldManager = string(f)
+}
+
+// }}}
+
+// {{{ Create Options
+
+// CreateOptions contains options for create requests. It's generally a subset
+// of metav1.CreateOptions.
+type CreateOptions struct {
+ // When present, indicates that modifications should not be
+ // persisted. An invalid or unrecognized dryRun directive will
+ // result in an error response and no further processing of the
+ // request. Valid values are:
+ // - All: all dry run stages will be processed
+ DryRun []string
+
+ // FieldManager is the name of the user or component submitting
+ // this request. It must be set with server-side apply.
+ FieldManager string
+
+ // Raw represents raw CreateOptions, as passed to the API server.
+ Raw *metav1.CreateOptions
+}
+
+// AsCreateOptions returns these options as a metav1.CreateOptions.
+// This may mutate the Raw field.
+func (o *CreateOptions) AsCreateOptions() *metav1.CreateOptions {
+ if o == nil {
+ return &metav1.CreateOptions{}
+ }
+ if o.Raw == nil {
+ o.Raw = &metav1.CreateOptions{}
+ }
+
+ o.Raw.DryRun = o.DryRun
+ o.Raw.FieldManager = o.FieldManager
+ return o.Raw
+}
+
+// ApplyOptions applies the given create options on these options,
+// and then returns itself (for convenient chaining).
+func (o *CreateOptions) ApplyOptions(opts []CreateOption) *CreateOptions {
+ for _, opt := range opts {
+ opt.ApplyToCreate(o)
+ }
+ return o
+}
+
+// ApplyToCreate implements CreateOption.
+func (o *CreateOptions) ApplyToCreate(co *CreateOptions) {
+ if o.DryRun != nil {
+ co.DryRun = o.DryRun
+ }
+ if o.FieldManager != "" {
+ co.FieldManager = o.FieldManager
+ }
+ if o.Raw != nil {
+ co.Raw = o.Raw
+ }
+}
+
+var _ CreateOption = &CreateOptions{}
+
+// }}}
+
+// {{{ Delete Options
+
+// DeleteOptions contains options for delete requests. It's generally a subset
+// of metav1.DeleteOptions.
+type DeleteOptions struct {
+ // GracePeriodSeconds is the duration in seconds before the object should be
+ // deleted. Value must be non-negative integer. The value zero indicates
+ // delete immediately. If this value is nil, the default grace period for the
+ // specified type will be used.
+ GracePeriodSeconds *int64
+
+ // Preconditions must be fulfilled before a deletion is carried out. If not
+ // possible, a 409 Conflict status will be returned.
+ Preconditions *metav1.Preconditions
+
+ // PropagationPolicy determined whether and how garbage collection will be
+ // performed. Either this field or OrphanDependents may be set, but not both.
+ // The default policy is decided by the existing finalizer set in the
+ // metadata.finalizers and the resource-specific default policy.
+ // Acceptable values are: 'Orphan' - orphan the dependents; 'Background' -
+ // allow the garbage collector to delete the dependents in the background;
+ // 'Foreground' - a cascading policy that deletes all dependents in the
+ // foreground.
+ PropagationPolicy *metav1.DeletionPropagation
+
+ // Raw represents raw DeleteOptions, as passed to the API server.
+ Raw *metav1.DeleteOptions
+
+ // When present, indicates that modifications should not be
+ // persisted. An invalid or unrecognized dryRun directive will
+ // result in an error response and no further processing of the
+ // request. Valid values are:
+ // - All: all dry run stages will be processed
+ DryRun []string
+}
+
+// AsDeleteOptions returns these options as a metav1.DeleteOptions.
+// This may mutate the Raw field.
+func (o *DeleteOptions) AsDeleteOptions() *metav1.DeleteOptions {
+ if o == nil {
+ return &metav1.DeleteOptions{}
+ }
+ if o.Raw == nil {
+ o.Raw = &metav1.DeleteOptions{}
+ }
+
+ o.Raw.GracePeriodSeconds = o.GracePeriodSeconds
+ o.Raw.Preconditions = o.Preconditions
+ o.Raw.PropagationPolicy = o.PropagationPolicy
+ o.Raw.DryRun = o.DryRun
+ return o.Raw
+}
+
+// ApplyOptions applies the given delete options on these options,
+// and then returns itself (for convenient chaining).
+func (o *DeleteOptions) ApplyOptions(opts []DeleteOption) *DeleteOptions {
+ for _, opt := range opts {
+ opt.ApplyToDelete(o)
+ }
+ return o
+}
+
+var _ DeleteOption = &DeleteOptions{}
+
+// ApplyToDelete implements DeleteOption.
+func (o *DeleteOptions) ApplyToDelete(do *DeleteOptions) {
+ if o.GracePeriodSeconds != nil {
+ do.GracePeriodSeconds = o.GracePeriodSeconds
+ }
+ if o.Preconditions != nil {
+ do.Preconditions = o.Preconditions
+ }
+ if o.PropagationPolicy != nil {
+ do.PropagationPolicy = o.PropagationPolicy
+ }
+ if o.Raw != nil {
+ do.Raw = o.Raw
+ }
+ if o.DryRun != nil {
+ do.DryRun = o.DryRun
+ }
+}
+
+// GracePeriodSeconds sets the grace period for the deletion
+// to the given number of seconds.
+type GracePeriodSeconds int64
+
+// ApplyToDelete applies this configuration to the given delete options.
+func (s GracePeriodSeconds) ApplyToDelete(opts *DeleteOptions) {
+ secs := int64(s)
+ opts.GracePeriodSeconds = &secs
+}
+
+// ApplyToDeleteAllOf applies this configuration to the given an List options.
+func (s GracePeriodSeconds) ApplyToDeleteAllOf(opts *DeleteAllOfOptions) {
+ s.ApplyToDelete(&opts.DeleteOptions)
+}
+
+// Preconditions must be fulfilled before an operation (update, delete, etc.) is carried out.
+type Preconditions metav1.Preconditions
+
+// ApplyToDelete applies this configuration to the given delete options.
+func (p Preconditions) ApplyToDelete(opts *DeleteOptions) {
+ preconds := metav1.Preconditions(p)
+ opts.Preconditions = &preconds
+}
+
+// ApplyToDeleteAllOf applies this configuration to the given an List options.
+func (p Preconditions) ApplyToDeleteAllOf(opts *DeleteAllOfOptions) {
+ p.ApplyToDelete(&opts.DeleteOptions)
+}
+
+// PropagationPolicy determined whether and how garbage collection will be
+// performed. Either this field or OrphanDependents may be set, but not both.
+// The default policy is decided by the existing finalizer set in the
+// metadata.finalizers and the resource-specific default policy.
+// Acceptable values are: 'Orphan' - orphan the dependents; 'Background' -
+// allow the garbage collector to delete the dependents in the background;
+// 'Foreground' - a cascading policy that deletes all dependents in the
+// foreground.
+type PropagationPolicy metav1.DeletionPropagation
+
+// ApplyToDelete applies the given delete options on these options.
+// It will propagate to the dependents of the object to let the garbage collector handle it.
+func (p PropagationPolicy) ApplyToDelete(opts *DeleteOptions) {
+ policy := metav1.DeletionPropagation(p)
+ opts.PropagationPolicy = &policy
+}
+
+// ApplyToDeleteAllOf applies this configuration to the given an List options.
+func (p PropagationPolicy) ApplyToDeleteAllOf(opts *DeleteAllOfOptions) {
+ p.ApplyToDelete(&opts.DeleteOptions)
+}
+
+// }}}
+
+// {{{ List Options
+
+// ListOptions contains options for limiting or filtering results.
+// It's generally a subset of metav1.ListOptions, with support for
+// pre-parsed selectors (since generally, selectors will be executed
+// against the cache).
+type ListOptions struct {
+ // LabelSelector filters results by label. Use SetLabelSelector to
+ // set from raw string form.
+ LabelSelector labels.Selector
+ // FieldSelector filters results by a particular field. In order
+ // to use this with cache-based implementations, restrict usage to
+ // a single field-value pair that's been added to the indexers.
+ FieldSelector fields.Selector
+
+ // Namespace represents the namespace to list for, or empty for
+ // non-namespaced objects, or to list across all namespaces.
+ Namespace string
+
+ // Limit specifies the maximum number of results to return from the server. The server may
+ // not support this field on all resource types, but if it does and more results remain it
+ // will set the continue field on the returned list object. This field is not supported if watch
+ // is true in the Raw ListOptions.
+ Limit int64
+ // Continue is a token returned by the server that lets a client retrieve chunks of results
+ // from the server by specifying limit. The server may reject requests for continuation tokens
+ // it does not recognize and will return a 410 error if the token can no longer be used because
+ // it has expired. This field is not supported if watch is true in the Raw ListOptions.
+ Continue string
+
+ // Raw represents raw ListOptions, as passed to the API server. Note
+ // that these may not be respected by all implementations of interface,
+ // and the LabelSelector, FieldSelector, Limit and Continue fields are ignored.
+ Raw *metav1.ListOptions
+}
+
+var _ ListOption = &ListOptions{}
+
+// ApplyToList implements ListOption for ListOptions.
+func (o *ListOptions) ApplyToList(lo *ListOptions) {
+ if o.LabelSelector != nil {
+ lo.LabelSelector = o.LabelSelector
+ }
+ if o.FieldSelector != nil {
+ lo.FieldSelector = o.FieldSelector
+ }
+ if o.Namespace != "" {
+ lo.Namespace = o.Namespace
+ }
+ if o.Raw != nil {
+ lo.Raw = o.Raw
+ }
+ if o.Limit > 0 {
+ lo.Limit = o.Limit
+ }
+ if o.Continue != "" {
+ lo.Continue = o.Continue
+ }
+}
+
+// AsListOptions returns these options as a flattened metav1.ListOptions.
+// This may mutate the Raw field.
+func (o *ListOptions) AsListOptions() *metav1.ListOptions {
+ if o == nil {
+ return &metav1.ListOptions{}
+ }
+ if o.Raw == nil {
+ o.Raw = &metav1.ListOptions{}
+ }
+ if o.LabelSelector != nil {
+ o.Raw.LabelSelector = o.LabelSelector.String()
+ }
+ if o.FieldSelector != nil {
+ o.Raw.FieldSelector = o.FieldSelector.String()
+ }
+ if !o.Raw.Watch {
+ o.Raw.Limit = o.Limit
+ o.Raw.Continue = o.Continue
+ }
+ return o.Raw
+}
+
+// ApplyOptions applies the given list options on these options,
+// and then returns itself (for convenient chaining).
+func (o *ListOptions) ApplyOptions(opts []ListOption) *ListOptions {
+ for _, opt := range opts {
+ opt.ApplyToList(o)
+ }
+ return o
+}
+
+// MatchingLabels filters the list/delete operation on the given set of labels.
+type MatchingLabels map[string]string
+
+// ApplyToList applies this configuration to the given list options.
+func (m MatchingLabels) ApplyToList(opts *ListOptions) {
+ // TODO(directxman12): can we avoid reserializing this over and over?
+ sel := labels.SelectorFromValidatedSet(map[string]string(m))
+ opts.LabelSelector = sel
+}
+
+// ApplyToDeleteAllOf applies this configuration to the given an List options.
+func (m MatchingLabels) ApplyToDeleteAllOf(opts *DeleteAllOfOptions) {
+ m.ApplyToList(&opts.ListOptions)
+}
+
+// HasLabels filters the list/delete operation checking if the set of labels exists
+// without checking their values.
+type HasLabels []string
+
+// ApplyToList applies this configuration to the given list options.
+func (m HasLabels) ApplyToList(opts *ListOptions) {
+ sel := labels.NewSelector()
+ for _, label := range m {
+ r, err := labels.NewRequirement(label, selection.Exists, nil)
+ if err == nil {
+ sel = sel.Add(*r)
+ }
+ }
+ opts.LabelSelector = sel
+}
+
+// ApplyToDeleteAllOf applies this configuration to the given an List options.
+func (m HasLabels) ApplyToDeleteAllOf(opts *DeleteAllOfOptions) {
+ m.ApplyToList(&opts.ListOptions)
+}
+
+// MatchingLabelsSelector filters the list/delete operation on the given label
+// selector (or index in the case of cached lists). A struct is used because
+// labels.Selector is an interface, which cannot be aliased.
+type MatchingLabelsSelector struct {
+ labels.Selector
+}
+
+// ApplyToList applies this configuration to the given list options.
+func (m MatchingLabelsSelector) ApplyToList(opts *ListOptions) {
+ opts.LabelSelector = m
+}
+
+// ApplyToDeleteAllOf applies this configuration to the given an List options.
+func (m MatchingLabelsSelector) ApplyToDeleteAllOf(opts *DeleteAllOfOptions) {
+ m.ApplyToList(&opts.ListOptions)
+}
+
+// MatchingFields filters the list/delete operation on the given field Set
+// (or index in the case of cached lists).
+type MatchingFields fields.Set
+
+// ApplyToList applies this configuration to the given list options.
+func (m MatchingFields) ApplyToList(opts *ListOptions) {
+ // TODO(directxman12): can we avoid re-serializing this?
+ sel := fields.Set(m).AsSelector()
+ opts.FieldSelector = sel
+}
+
+// ApplyToDeleteAllOf applies this configuration to the given an List options.
+func (m MatchingFields) ApplyToDeleteAllOf(opts *DeleteAllOfOptions) {
+ m.ApplyToList(&opts.ListOptions)
+}
+
+// MatchingFieldsSelector filters the list/delete operation on the given field
+// selector (or index in the case of cached lists). A struct is used because
+// fields.Selector is an interface, which cannot be aliased.
+type MatchingFieldsSelector struct {
+ fields.Selector
+}
+
+// ApplyToList applies this configuration to the given list options.
+func (m MatchingFieldsSelector) ApplyToList(opts *ListOptions) {
+ opts.FieldSelector = m
+}
+
+// ApplyToDeleteAllOf applies this configuration to the given an List options.
+func (m MatchingFieldsSelector) ApplyToDeleteAllOf(opts *DeleteAllOfOptions) {
+ m.ApplyToList(&opts.ListOptions)
+}
+
+// InNamespace restricts the list/delete operation to the given namespace.
+type InNamespace string
+
+// ApplyToList applies this configuration to the given list options.
+func (n InNamespace) ApplyToList(opts *ListOptions) {
+ opts.Namespace = string(n)
+}
+
+// ApplyToDeleteAllOf applies this configuration to the given an List options.
+func (n InNamespace) ApplyToDeleteAllOf(opts *DeleteAllOfOptions) {
+ n.ApplyToList(&opts.ListOptions)
+}
+
+// Limit specifies the maximum number of results to return from the server.
+// Limit does not implement DeleteAllOfOption interface because the server
+// does not support setting it for deletecollection operations.
+type Limit int64
+
+// ApplyToList applies this configuration to the given an list options.
+func (l Limit) ApplyToList(opts *ListOptions) {
+ opts.Limit = int64(l)
+}
+
+// Continue sets a continuation token to retrieve chunks of results when using limit.
+// Continue does not implement DeleteAllOfOption interface because the server
+// does not support setting it for deletecollection operations.
+type Continue string
+
+// ApplyToList applies this configuration to the given an List options.
+func (c Continue) ApplyToList(opts *ListOptions) {
+ opts.Continue = string(c)
+}
+
+// }}}
+
+// {{{ Update Options
+
+// UpdateOptions contains options for create requests. It's generally a subset
+// of metav1.UpdateOptions.
+type UpdateOptions struct {
+ // When present, indicates that modifications should not be
+ // persisted. An invalid or unrecognized dryRun directive will
+ // result in an error response and no further processing of the
+ // request. Valid values are:
+ // - All: all dry run stages will be processed
+ DryRun []string
+
+ // FieldManager is the name of the user or component submitting
+ // this request. It must be set with server-side apply.
+ FieldManager string
+
+ // Raw represents raw UpdateOptions, as passed to the API server.
+ Raw *metav1.UpdateOptions
+}
+
+// AsUpdateOptions returns these options as a metav1.UpdateOptions.
+// This may mutate the Raw field.
+func (o *UpdateOptions) AsUpdateOptions() *metav1.UpdateOptions {
+ if o == nil {
+ return &metav1.UpdateOptions{}
+ }
+ if o.Raw == nil {
+ o.Raw = &metav1.UpdateOptions{}
+ }
+
+ o.Raw.DryRun = o.DryRun
+ o.Raw.FieldManager = o.FieldManager
+ return o.Raw
+}
+
+// ApplyOptions applies the given update options on these options,
+// and then returns itself (for convenient chaining).
+func (o *UpdateOptions) ApplyOptions(opts []UpdateOption) *UpdateOptions {
+ for _, opt := range opts {
+ opt.ApplyToUpdate(o)
+ }
+ return o
+}
+
+var _ UpdateOption = &UpdateOptions{}
+
+// ApplyToUpdate implements UpdateOption.
+func (o *UpdateOptions) ApplyToUpdate(uo *UpdateOptions) {
+ if o.DryRun != nil {
+ uo.DryRun = o.DryRun
+ }
+ if o.FieldManager != "" {
+ uo.FieldManager = o.FieldManager
+ }
+ if o.Raw != nil {
+ uo.Raw = o.Raw
+ }
+}
+
+// }}}
+
+// {{{ Patch Options
+
+// PatchOptions contains options for patch requests.
+type PatchOptions struct {
+ // When present, indicates that modifications should not be
+ // persisted. An invalid or unrecognized dryRun directive will
+ // result in an error response and no further processing of the
+ // request. Valid values are:
+ // - All: all dry run stages will be processed
+ DryRun []string
+
+ // Force is going to "force" Apply requests. It means user will
+ // re-acquire conflicting fields owned by other people. Force
+ // flag must be unset for non-apply patch requests.
+ // +optional
+ Force *bool
+
+ // FieldManager is the name of the user or component submitting
+ // this request. It must be set with server-side apply.
+ FieldManager string
+
+ // Raw represents raw PatchOptions, as passed to the API server.
+ Raw *metav1.PatchOptions
+}
+
+// ApplyOptions applies the given patch options on these options,
+// and then returns itself (for convenient chaining).
+func (o *PatchOptions) ApplyOptions(opts []PatchOption) *PatchOptions {
+ for _, opt := range opts {
+ opt.ApplyToPatch(o)
+ }
+ return o
+}
+
+// AsPatchOptions returns these options as a metav1.PatchOptions.
+// This may mutate the Raw field.
+func (o *PatchOptions) AsPatchOptions() *metav1.PatchOptions {
+ if o == nil {
+ return &metav1.PatchOptions{}
+ }
+ if o.Raw == nil {
+ o.Raw = &metav1.PatchOptions{}
+ }
+
+ o.Raw.DryRun = o.DryRun
+ o.Raw.Force = o.Force
+ o.Raw.FieldManager = o.FieldManager
+ return o.Raw
+}
+
+var _ PatchOption = &PatchOptions{}
+
+// ApplyToPatch implements PatchOptions.
+func (o *PatchOptions) ApplyToPatch(po *PatchOptions) {
+ if o.DryRun != nil {
+ po.DryRun = o.DryRun
+ }
+ if o.Force != nil {
+ po.Force = o.Force
+ }
+ if o.FieldManager != "" {
+ po.FieldManager = o.FieldManager
+ }
+ if o.Raw != nil {
+ po.Raw = o.Raw
+ }
+}
+
+// ForceOwnership indicates that in case of conflicts with server-side apply,
+// the client should acquire ownership of the conflicting field. Most
+// controllers should use this.
+var ForceOwnership = forceOwnership{}
+
+type forceOwnership struct{}
+
+func (forceOwnership) ApplyToPatch(opts *PatchOptions) {
+ definitelyTrue := true
+ opts.Force = &definitelyTrue
+}
+
+// }}}
+
+// {{{ DeleteAllOf Options
+
+// these are all just delete options and list options
+
+// DeleteAllOfOptions contains options for deletecollection (deleteallof) requests.
+// It's just list and delete options smooshed together.
+type DeleteAllOfOptions struct {
+ ListOptions
+ DeleteOptions
+}
+
+// ApplyOptions applies the given deleteallof options on these options,
+// and then returns itself (for convenient chaining).
+func (o *DeleteAllOfOptions) ApplyOptions(opts []DeleteAllOfOption) *DeleteAllOfOptions {
+ for _, opt := range opts {
+ opt.ApplyToDeleteAllOf(o)
+ }
+ return o
+}
+
+var _ DeleteAllOfOption = &DeleteAllOfOptions{}
+
+// ApplyToDeleteAllOf implements DeleteAllOfOption.
+func (o *DeleteAllOfOptions) ApplyToDeleteAllOf(do *DeleteAllOfOptions) {
+ o.ApplyToList(&do.ListOptions)
+ o.ApplyToDelete(&do.DeleteOptions)
+}
+
+// }}}
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/client/patch.go b/vendor/sigs.k8s.io/controller-runtime/pkg/client/patch.go
new file mode 100644
index 000000000..10984c534
--- /dev/null
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/client/patch.go
@@ -0,0 +1,213 @@
+/*
+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 (
+ "fmt"
+
+ jsonpatch "github.com/evanphx/json-patch"
+ "k8s.io/apimachinery/pkg/types"
+ "k8s.io/apimachinery/pkg/util/json"
+ "k8s.io/apimachinery/pkg/util/strategicpatch"
+)
+
+var (
+ // Apply uses server-side apply to patch the given object.
+ Apply Patch = applyPatch{}
+
+ // Merge uses the raw object as a merge patch, without modifications.
+ // Use MergeFrom if you wish to compute a diff instead.
+ Merge Patch = mergePatch{}
+)
+
+type patch struct {
+ patchType types.PatchType
+ data []byte
+}
+
+// Type implements Patch.
+func (s *patch) Type() types.PatchType {
+ return s.patchType
+}
+
+// Data implements Patch.
+func (s *patch) Data(obj Object) ([]byte, error) {
+ return s.data, nil
+}
+
+// RawPatch constructs a new Patch with the given PatchType and data.
+func RawPatch(patchType types.PatchType, data []byte) Patch {
+ return &patch{patchType, data}
+}
+
+// MergeFromWithOptimisticLock can be used if clients want to make sure a patch
+// is being applied to the latest resource version of an object.
+//
+// The behavior is similar to what an Update would do, without the need to send the
+// whole object. Usually this method is useful if you might have multiple clients
+// acting on the same object and the same API version, but with different versions of the Go structs.
+//
+// For example, an "older" copy of a Widget that has fields A and B, and a "newer" copy with A, B, and C.
+// Sending an update using the older struct definition results in C being dropped, whereas using a patch does not.
+type MergeFromWithOptimisticLock struct{}
+
+// ApplyToMergeFrom applies this configuration to the given patch options.
+func (m MergeFromWithOptimisticLock) ApplyToMergeFrom(in *MergeFromOptions) {
+ in.OptimisticLock = true
+}
+
+// MergeFromOption is some configuration that modifies options for a merge-from patch data.
+type MergeFromOption interface {
+ // ApplyToMergeFrom applies this configuration to the given patch options.
+ ApplyToMergeFrom(*MergeFromOptions)
+}
+
+// MergeFromOptions contains options to generate a merge-from patch data.
+type MergeFromOptions struct {
+ // OptimisticLock, when true, includes `metadata.resourceVersion` into the final
+ // patch data. If the `resourceVersion` field doesn't match what's stored,
+ // the operation results in a conflict and clients will need to try again.
+ OptimisticLock bool
+}
+
+type mergeFromPatch struct {
+ patchType types.PatchType
+ createPatch func(originalJSON, modifiedJSON []byte, dataStruct interface{}) ([]byte, error)
+ from Object
+ opts MergeFromOptions
+}
+
+// Type implements Patch.
+func (s *mergeFromPatch) Type() types.PatchType {
+ return s.patchType
+}
+
+// Data implements Patch.
+func (s *mergeFromPatch) Data(obj Object) ([]byte, error) {
+ original := s.from
+ modified := obj
+
+ if s.opts.OptimisticLock {
+ version := original.GetResourceVersion()
+ if len(version) == 0 {
+ return nil, fmt.Errorf("cannot use OptimisticLock, object %q does not have any resource version we can use", original)
+ }
+
+ original = original.DeepCopyObject().(Object)
+ original.SetResourceVersion("")
+
+ modified = modified.DeepCopyObject().(Object)
+ modified.SetResourceVersion(version)
+ }
+
+ originalJSON, err := json.Marshal(original)
+ if err != nil {
+ return nil, err
+ }
+
+ modifiedJSON, err := json.Marshal(modified)
+ if err != nil {
+ return nil, err
+ }
+
+ data, err := s.createPatch(originalJSON, modifiedJSON, obj)
+ if err != nil {
+ return nil, err
+ }
+
+ return data, nil
+}
+
+func createMergePatch(originalJSON, modifiedJSON []byte, _ interface{}) ([]byte, error) {
+ return jsonpatch.CreateMergePatch(originalJSON, modifiedJSON)
+}
+
+func createStrategicMergePatch(originalJSON, modifiedJSON []byte, dataStruct interface{}) ([]byte, error) {
+ return strategicpatch.CreateTwoWayMergePatch(originalJSON, modifiedJSON, dataStruct)
+}
+
+// MergeFrom creates a Patch that patches using the merge-patch strategy with the given object as base.
+// The difference between MergeFrom and StrategicMergeFrom lays in the handling of modified list fields.
+// When using MergeFrom, existing lists will be completely replaced by new lists.
+// When using StrategicMergeFrom, the list field's `patchStrategy` is respected if specified in the API type,
+// e.g. the existing list is not replaced completely but rather merged with the new one using the list's `patchMergeKey`.
+// See https://kubernetes.io/docs/tasks/manage-kubernetes-objects/update-api-object-kubectl-patch/ for more details on
+// the difference between merge-patch and strategic-merge-patch.
+func MergeFrom(obj Object) Patch {
+ return &mergeFromPatch{patchType: types.MergePatchType, createPatch: createMergePatch, from: obj}
+}
+
+// MergeFromWithOptions creates a Patch that patches using the merge-patch strategy with the given object as base.
+// See MergeFrom for more details.
+func MergeFromWithOptions(obj Object, opts ...MergeFromOption) Patch {
+ options := &MergeFromOptions{}
+ for _, opt := range opts {
+ opt.ApplyToMergeFrom(options)
+ }
+ return &mergeFromPatch{patchType: types.MergePatchType, createPatch: createMergePatch, from: obj, opts: *options}
+}
+
+// StrategicMergeFrom creates a Patch that patches using the strategic-merge-patch strategy with the given object as base.
+// The difference between MergeFrom and StrategicMergeFrom lays in the handling of modified list fields.
+// When using MergeFrom, existing lists will be completely replaced by new lists.
+// When using StrategicMergeFrom, the list field's `patchStrategy` is respected if specified in the API type,
+// e.g. the existing list is not replaced completely but rather merged with the new one using the list's `patchMergeKey`.
+// See https://kubernetes.io/docs/tasks/manage-kubernetes-objects/update-api-object-kubectl-patch/ for more details on
+// the difference between merge-patch and strategic-merge-patch.
+// Please note, that CRDs don't support strategic-merge-patch, see
+// https://kubernetes.io/docs/concepts/extend-kubernetes/api-extension/custom-resources/#advanced-features-and-flexibility
+func StrategicMergeFrom(obj Object, opts ...MergeFromOption) Patch {
+ options := &MergeFromOptions{}
+ for _, opt := range opts {
+ opt.ApplyToMergeFrom(options)
+ }
+ return &mergeFromPatch{patchType: types.StrategicMergePatchType, createPatch: createStrategicMergePatch, from: obj, opts: *options}
+}
+
+// mergePatch uses a raw merge strategy to patch the object.
+type mergePatch struct{}
+
+// Type implements Patch.
+func (p mergePatch) Type() types.PatchType {
+ return types.MergePatchType
+}
+
+// Data implements Patch.
+func (p mergePatch) Data(obj Object) ([]byte, error) {
+ // NB(directxman12): we might technically want to be using an actual encoder
+ // here (in case some more performant encoder is introduced) but this is
+ // correct and sufficient for our uses (it's what the JSON serializer in
+ // client-go does, more-or-less).
+ return json.Marshal(obj)
+}
+
+// applyPatch uses server-side apply to patch the object.
+type applyPatch struct{}
+
+// Type implements Patch.
+func (p applyPatch) Type() types.PatchType {
+ return types.ApplyPatchType
+}
+
+// Data implements Patch.
+func (p applyPatch) Data(obj Object) ([]byte, error) {
+ // NB(directxman12): we might technically want to be using an actual encoder
+ // here (in case some more performant encoder is introduced) but this is
+ // correct and sufficient for our uses (it's what the JSON serializer in
+ // client-go does, more-or-less).
+ return json.Marshal(obj)
+}
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/client/split.go b/vendor/sigs.k8s.io/controller-runtime/pkg/client/split.go
new file mode 100644
index 000000000..bf4b861f3
--- /dev/null
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/client/split.go
@@ -0,0 +1,141 @@
+/*
+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,
+ }, nil
+}
+
+type delegatingClient struct {
+ Reader
+ Writer
+ StatusClient
+
+ 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) error {
+ if isUncached, err := d.shouldBypassCache(obj); err != nil {
+ return err
+ } else if isUncached {
+ return d.ClientReader.Get(ctx, key, obj)
+ }
+ return d.CacheReader.Get(ctx, key, obj)
+}
+
+// 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...)
+}
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/client/typed_client.go b/vendor/sigs.k8s.io/controller-runtime/pkg/client/typed_client.go
new file mode 100644
index 000000000..dde7b21f2
--- /dev/null
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/client/typed_client.go
@@ -0,0 +1,205 @@
+/*
+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"
+
+ "k8s.io/apimachinery/pkg/runtime"
+)
+
+var _ Reader = &typedClient{}
+var _ Writer = &typedClient{}
+var _ StatusWriter = &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 {
+ cache *clientCache
+ paramCodec runtime.ParameterCodec
+}
+
+// Create implements client.Client.
+func (c *typedClient) Create(ctx context.Context, obj Object, opts ...CreateOption) error {
+ o, err := c.cache.getObjMeta(obj)
+ if err != nil {
+ return err
+ }
+
+ createOpts := &CreateOptions{}
+ createOpts.ApplyOptions(opts)
+ return o.Post().
+ NamespaceIfScoped(o.GetNamespace(), o.isNamespaced()).
+ Resource(o.resource()).
+ Body(obj).
+ VersionedParams(createOpts.AsCreateOptions(), c.paramCodec).
+ Do(ctx).
+ Into(obj)
+}
+
+// Update implements client.Client.
+func (c *typedClient) Update(ctx context.Context, obj Object, opts ...UpdateOption) error {
+ o, err := c.cache.getObjMeta(obj)
+ if err != nil {
+ return err
+ }
+
+ updateOpts := &UpdateOptions{}
+ updateOpts.ApplyOptions(opts)
+ return o.Put().
+ NamespaceIfScoped(o.GetNamespace(), o.isNamespaced()).
+ Resource(o.resource()).
+ Name(o.GetName()).
+ Body(obj).
+ VersionedParams(updateOpts.AsUpdateOptions(), c.paramCodec).
+ Do(ctx).
+ Into(obj)
+}
+
+// Delete implements client.Client.
+func (c *typedClient) Delete(ctx context.Context, obj Object, opts ...DeleteOption) error {
+ o, err := c.cache.getObjMeta(obj)
+ if err != nil {
+ return err
+ }
+
+ deleteOpts := DeleteOptions{}
+ deleteOpts.ApplyOptions(opts)
+
+ return o.Delete().
+ NamespaceIfScoped(o.GetNamespace(), o.isNamespaced()).
+ Resource(o.resource()).
+ Name(o.GetName()).
+ Body(deleteOpts.AsDeleteOptions()).
+ Do(ctx).
+ Error()
+}
+
+// DeleteAllOf implements client.Client.
+func (c *typedClient) DeleteAllOf(ctx context.Context, obj Object, opts ...DeleteAllOfOption) error {
+ o, err := c.cache.getObjMeta(obj)
+ if err != nil {
+ return err
+ }
+
+ deleteAllOfOpts := DeleteAllOfOptions{}
+ deleteAllOfOpts.ApplyOptions(opts)
+
+ return o.Delete().
+ NamespaceIfScoped(deleteAllOfOpts.ListOptions.Namespace, o.isNamespaced()).
+ Resource(o.resource()).
+ VersionedParams(deleteAllOfOpts.AsListOptions(), c.paramCodec).
+ Body(deleteAllOfOpts.AsDeleteOptions()).
+ Do(ctx).
+ Error()
+}
+
+// Patch implements client.Client.
+func (c *typedClient) Patch(ctx context.Context, obj Object, patch Patch, opts ...PatchOption) error {
+ o, err := c.cache.getObjMeta(obj)
+ if err != nil {
+ return err
+ }
+
+ data, err := patch.Data(obj)
+ if err != nil {
+ return err
+ }
+
+ patchOpts := &PatchOptions{}
+ return o.Patch(patch.Type()).
+ NamespaceIfScoped(o.GetNamespace(), o.isNamespaced()).
+ Resource(o.resource()).
+ Name(o.GetName()).
+ VersionedParams(patchOpts.ApplyOptions(opts).AsPatchOptions(), c.paramCodec).
+ Body(data).
+ Do(ctx).
+ Into(obj)
+}
+
+// Get implements client.Client.
+func (c *typedClient) Get(ctx context.Context, key ObjectKey, obj Object) error {
+ r, err := c.cache.getResource(obj)
+ if err != nil {
+ return err
+ }
+ return r.Get().
+ NamespaceIfScoped(key.Namespace, r.isNamespaced()).
+ Resource(r.resource()).
+ Name(key.Name).Do(ctx).Into(obj)
+}
+
+// List implements client.Client.
+func (c *typedClient) List(ctx context.Context, obj ObjectList, opts ...ListOption) error {
+ r, err := c.cache.getResource(obj)
+ if err != nil {
+ return err
+ }
+ listOpts := ListOptions{}
+ listOpts.ApplyOptions(opts)
+ return r.Get().
+ NamespaceIfScoped(listOpts.Namespace, r.isNamespaced()).
+ Resource(r.resource()).
+ VersionedParams(listOpts.AsListOptions(), c.paramCodec).
+ Do(ctx).
+ Into(obj)
+}
+
+// UpdateStatus used by StatusWriter to write status.
+func (c *typedClient) UpdateStatus(ctx context.Context, obj Object, opts ...UpdateOption) error {
+ o, err := c.cache.getObjMeta(obj)
+ if err != nil {
+ return err
+ }
+ // TODO(droot): examine the returned error and check if it error needs to be
+ // wrapped to improve the UX ?
+ // It will be nice to receive an error saying the object doesn't implement
+ // status subresource and check CRD definition
+ return o.Put().
+ NamespaceIfScoped(o.GetNamespace(), o.isNamespaced()).
+ Resource(o.resource()).
+ Name(o.GetName()).
+ SubResource("status").
+ Body(obj).
+ VersionedParams((&UpdateOptions{}).ApplyOptions(opts).AsUpdateOptions(), c.paramCodec).
+ Do(ctx).
+ Into(obj)
+}
+
+// PatchStatus used by StatusWriter to write status.
+func (c *typedClient) PatchStatus(ctx context.Context, obj Object, patch Patch, opts ...PatchOption) error {
+ o, err := c.cache.getObjMeta(obj)
+ if err != nil {
+ return err
+ }
+
+ data, err := patch.Data(obj)
+ if err != nil {
+ return err
+ }
+
+ patchOpts := &PatchOptions{}
+ return o.Patch(patch.Type()).
+ NamespaceIfScoped(o.GetNamespace(), o.isNamespaced()).
+ Resource(o.resource()).
+ Name(o.GetName()).
+ SubResource("status").
+ Body(data).
+ VersionedParams(patchOpts.ApplyOptions(opts).AsPatchOptions(), c.paramCodec).
+ Do(ctx).
+ Into(obj)
+}
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/client/unstructured_client.go b/vendor/sigs.k8s.io/controller-runtime/pkg/client/unstructured_client.go
new file mode 100644
index 000000000..dcf15be27
--- /dev/null
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/client/unstructured_client.go
@@ -0,0 +1,277 @@
+/*
+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"
+ "fmt"
+ "strings"
+
+ "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
+ "k8s.io/apimachinery/pkg/runtime"
+)
+
+var _ Reader = &unstructuredClient{}
+var _ Writer = &unstructuredClient{}
+var _ StatusWriter = &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 {
+ cache *clientCache
+ paramCodec runtime.ParameterCodec
+}
+
+// Create implements client.Client.
+func (uc *unstructuredClient) Create(ctx context.Context, obj Object, opts ...CreateOption) error {
+ u, ok := obj.(*unstructured.Unstructured)
+ if !ok {
+ return fmt.Errorf("unstructured client did not understand object: %T", obj)
+ }
+
+ gvk := u.GroupVersionKind()
+
+ o, err := uc.cache.getObjMeta(obj)
+ if err != nil {
+ return err
+ }
+
+ createOpts := &CreateOptions{}
+ createOpts.ApplyOptions(opts)
+ result := o.Post().
+ NamespaceIfScoped(o.GetNamespace(), o.isNamespaced()).
+ Resource(o.resource()).
+ Body(obj).
+ VersionedParams(createOpts.AsCreateOptions(), uc.paramCodec).
+ Do(ctx).
+ Into(obj)
+
+ u.SetGroupVersionKind(gvk)
+ return result
+}
+
+// Update implements client.Client.
+func (uc *unstructuredClient) Update(ctx context.Context, obj Object, opts ...UpdateOption) error {
+ u, ok := obj.(*unstructured.Unstructured)
+ if !ok {
+ return fmt.Errorf("unstructured client did not understand object: %T", obj)
+ }
+
+ gvk := u.GroupVersionKind()
+
+ o, err := uc.cache.getObjMeta(obj)
+ if err != nil {
+ return err
+ }
+
+ updateOpts := UpdateOptions{}
+ updateOpts.ApplyOptions(opts)
+ result := o.Put().
+ NamespaceIfScoped(o.GetNamespace(), o.isNamespaced()).
+ Resource(o.resource()).
+ Name(o.GetName()).
+ Body(obj).
+ VersionedParams(updateOpts.AsUpdateOptions(), uc.paramCodec).
+ Do(ctx).
+ Into(obj)
+
+ u.SetGroupVersionKind(gvk)
+ return result
+}
+
+// Delete implements client.Client.
+func (uc *unstructuredClient) Delete(ctx context.Context, obj Object, opts ...DeleteOption) error {
+ _, ok := obj.(*unstructured.Unstructured)
+ if !ok {
+ return fmt.Errorf("unstructured client did not understand object: %T", obj)
+ }
+
+ o, err := uc.cache.getObjMeta(obj)
+ if err != nil {
+ return err
+ }
+
+ deleteOpts := DeleteOptions{}
+ deleteOpts.ApplyOptions(opts)
+ return o.Delete().
+ NamespaceIfScoped(o.GetNamespace(), o.isNamespaced()).
+ Resource(o.resource()).
+ Name(o.GetName()).
+ Body(deleteOpts.AsDeleteOptions()).
+ Do(ctx).
+ Error()
+}
+
+// DeleteAllOf implements client.Client.
+func (uc *unstructuredClient) DeleteAllOf(ctx context.Context, obj Object, opts ...DeleteAllOfOption) error {
+ _, ok := obj.(*unstructured.Unstructured)
+ if !ok {
+ return fmt.Errorf("unstructured client did not understand object: %T", obj)
+ }
+
+ o, err := uc.cache.getObjMeta(obj)
+ if err != nil {
+ return err
+ }
+
+ deleteAllOfOpts := DeleteAllOfOptions{}
+ deleteAllOfOpts.ApplyOptions(opts)
+ return o.Delete().
+ NamespaceIfScoped(deleteAllOfOpts.ListOptions.Namespace, o.isNamespaced()).
+ Resource(o.resource()).
+ VersionedParams(deleteAllOfOpts.AsListOptions(), uc.paramCodec).
+ Body(deleteAllOfOpts.AsDeleteOptions()).
+ Do(ctx).
+ Error()
+}
+
+// Patch implements client.Client.
+func (uc *unstructuredClient) Patch(ctx context.Context, obj Object, patch Patch, opts ...PatchOption) error {
+ _, ok := obj.(*unstructured.Unstructured)
+ if !ok {
+ return fmt.Errorf("unstructured client did not understand object: %T", obj)
+ }
+
+ o, err := uc.cache.getObjMeta(obj)
+ if err != nil {
+ return err
+ }
+
+ data, err := patch.Data(obj)
+ if err != nil {
+ return err
+ }
+
+ patchOpts := &PatchOptions{}
+ return o.Patch(patch.Type()).
+ NamespaceIfScoped(o.GetNamespace(), o.isNamespaced()).
+ Resource(o.resource()).
+ Name(o.GetName()).
+ VersionedParams(patchOpts.ApplyOptions(opts).AsPatchOptions(), uc.paramCodec).
+ Body(data).
+ Do(ctx).
+ Into(obj)
+}
+
+// Get implements client.Client.
+func (uc *unstructuredClient) Get(ctx context.Context, key ObjectKey, obj Object) error {
+ u, ok := obj.(*unstructured.Unstructured)
+ if !ok {
+ return fmt.Errorf("unstructured client did not understand object: %T", obj)
+ }
+
+ gvk := u.GroupVersionKind()
+
+ r, err := uc.cache.getResource(obj)
+ if err != nil {
+ return err
+ }
+
+ result := r.Get().
+ NamespaceIfScoped(key.Namespace, r.isNamespaced()).
+ Resource(r.resource()).
+ Name(key.Name).
+ Do(ctx).
+ Into(obj)
+
+ u.SetGroupVersionKind(gvk)
+
+ return result
+}
+
+// List implements client.Client.
+func (uc *unstructuredClient) List(ctx context.Context, obj ObjectList, opts ...ListOption) error {
+ u, ok := obj.(*unstructured.UnstructuredList)
+ if !ok {
+ return fmt.Errorf("unstructured client did not understand object: %T", obj)
+ }
+
+ gvk := u.GroupVersionKind()
+ if strings.HasSuffix(gvk.Kind, "List") {
+ gvk.Kind = gvk.Kind[:len(gvk.Kind)-4]
+ }
+
+ listOpts := ListOptions{}
+ listOpts.ApplyOptions(opts)
+
+ r, err := uc.cache.getResource(obj)
+ if err != nil {
+ return err
+ }
+
+ return r.Get().
+ NamespaceIfScoped(listOpts.Namespace, r.isNamespaced()).
+ Resource(r.resource()).
+ VersionedParams(listOpts.AsListOptions(), uc.paramCodec).
+ Do(ctx).
+ Into(obj)
+}
+
+func (uc *unstructuredClient) UpdateStatus(ctx context.Context, obj Object, opts ...UpdateOption) error {
+ _, ok := obj.(*unstructured.Unstructured)
+ if !ok {
+ return fmt.Errorf("unstructured client did not understand object: %T", obj)
+ }
+
+ o, err := uc.cache.getObjMeta(obj)
+ if err != nil {
+ return err
+ }
+
+ return o.Put().
+ NamespaceIfScoped(o.GetNamespace(), o.isNamespaced()).
+ Resource(o.resource()).
+ Name(o.GetName()).
+ SubResource("status").
+ Body(obj).
+ VersionedParams((&UpdateOptions{}).ApplyOptions(opts).AsUpdateOptions(), uc.paramCodec).
+ Do(ctx).
+ Into(obj)
+}
+
+func (uc *unstructuredClient) PatchStatus(ctx context.Context, obj Object, patch Patch, opts ...PatchOption) error {
+ u, ok := obj.(*unstructured.Unstructured)
+ if !ok {
+ return fmt.Errorf("unstructured client did not understand object: %T", obj)
+ }
+
+ gvk := u.GroupVersionKind()
+
+ o, err := uc.cache.getObjMeta(obj)
+ if err != nil {
+ return err
+ }
+
+ data, err := patch.Data(obj)
+ if err != nil {
+ return err
+ }
+
+ patchOpts := &PatchOptions{}
+ result := o.Patch(patch.Type()).
+ NamespaceIfScoped(o.GetNamespace(), o.isNamespaced()).
+ Resource(o.resource()).
+ Name(o.GetName()).
+ SubResource("status").
+ Body(data).
+ VersionedParams(patchOpts.ApplyOptions(opts).AsPatchOptions(), uc.paramCodec).
+ Do(ctx).
+ Into(u)
+
+ u.SetGroupVersionKind(gvk)
+ return result
+}
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/client/watch.go b/vendor/sigs.k8s.io/controller-runtime/pkg/client/watch.go
new file mode 100644
index 000000000..765ca5daa
--- /dev/null
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/client/watch.go
@@ -0,0 +1,118 @@
+/*
+Copyright 2020 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package client
+
+import (
+ "context"
+ "strings"
+
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
+ "k8s.io/apimachinery/pkg/watch"
+ "k8s.io/client-go/dynamic"
+ "k8s.io/client-go/rest"
+)
+
+// NewWithWatch returns a new WithWatch.
+func NewWithWatch(config *rest.Config, options Options) (WithWatch, error) {
+ client, err := newClient(config, options)
+ if err != nil {
+ return nil, err
+ }
+ dynamicClient, err := dynamic.NewForConfig(config)
+ if err != nil {
+ return nil, err
+ }
+ return &watchingClient{client: client, dynamic: dynamicClient}, nil
+}
+
+type watchingClient struct {
+ *client
+ dynamic dynamic.Interface
+}
+
+func (w *watchingClient) Watch(ctx context.Context, list ObjectList, opts ...ListOption) (watch.Interface, error) {
+ switch l := list.(type) {
+ case *unstructured.UnstructuredList:
+ return w.unstructuredWatch(ctx, l, opts...)
+ case *metav1.PartialObjectMetadataList:
+ return w.metadataWatch(ctx, l, opts...)
+ default:
+ return w.typedWatch(ctx, l, opts...)
+ }
+}
+
+func (w *watchingClient) listOpts(opts ...ListOption) ListOptions {
+ listOpts := ListOptions{}
+ listOpts.ApplyOptions(opts)
+ if listOpts.Raw == nil {
+ listOpts.Raw = &metav1.ListOptions{}
+ }
+ listOpts.Raw.Watch = true
+
+ return listOpts
+}
+
+func (w *watchingClient) metadataWatch(ctx context.Context, obj *metav1.PartialObjectMetadataList, opts ...ListOption) (watch.Interface, error) {
+ gvk := obj.GroupVersionKind()
+ if strings.HasSuffix(gvk.Kind, "List") {
+ gvk.Kind = gvk.Kind[:len(gvk.Kind)-4]
+ }
+
+ listOpts := w.listOpts(opts...)
+
+ resInt, err := w.client.metadataClient.getResourceInterface(gvk, listOpts.Namespace)
+ if err != nil {
+ return nil, err
+ }
+
+ return resInt.Watch(ctx, *listOpts.AsListOptions())
+}
+
+func (w *watchingClient) unstructuredWatch(ctx context.Context, obj *unstructured.UnstructuredList, opts ...ListOption) (watch.Interface, error) {
+ gvk := obj.GroupVersionKind()
+ if strings.HasSuffix(gvk.Kind, "List") {
+ gvk.Kind = gvk.Kind[:len(gvk.Kind)-4]
+ }
+
+ r, err := w.client.unstructuredClient.cache.getResource(obj)
+ if err != nil {
+ return nil, err
+ }
+
+ listOpts := w.listOpts(opts...)
+
+ if listOpts.Namespace != "" && r.isNamespaced() {
+ return w.dynamic.Resource(r.mapping.Resource).Namespace(listOpts.Namespace).Watch(ctx, *listOpts.AsListOptions())
+ }
+ return w.dynamic.Resource(r.mapping.Resource).Watch(ctx, *listOpts.AsListOptions())
+}
+
+func (w *watchingClient) typedWatch(ctx context.Context, obj ObjectList, opts ...ListOption) (watch.Interface, error) {
+ r, err := w.client.typedClient.cache.getResource(obj)
+ if err != nil {
+ return nil, err
+ }
+
+ listOpts := w.listOpts(opts...)
+
+ return r.Get().
+ NamespaceIfScoped(listOpts.Namespace, r.isNamespaced()).
+ Resource(r.resource()).
+ VersionedParams(listOpts.AsListOptions(), w.client.typedClient.paramCodec).
+ Watch(ctx)
+}
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/cluster/cluster.go b/vendor/sigs.k8s.io/controller-runtime/pkg/cluster/cluster.go
new file mode 100644
index 000000000..dfd0fa9dd
--- /dev/null
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/cluster/cluster.go
@@ -0,0 +1,270 @@
+/*
+Copyright 2020 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package cluster
+
+import (
+ "context"
+ "errors"
+ "time"
+
+ "github.com/go-logr/logr"
+ "k8s.io/apimachinery/pkg/api/meta"
+ "k8s.io/apimachinery/pkg/runtime"
+ "k8s.io/client-go/kubernetes/scheme"
+ "k8s.io/client-go/rest"
+ "k8s.io/client-go/tools/record"
+ "sigs.k8s.io/controller-runtime/pkg/client/apiutil"
+ logf "sigs.k8s.io/controller-runtime/pkg/internal/log"
+
+ "sigs.k8s.io/controller-runtime/pkg/cache"
+ "sigs.k8s.io/controller-runtime/pkg/client"
+ intrec "sigs.k8s.io/controller-runtime/pkg/internal/recorder"
+)
+
+// Cluster provides various methods to interact with a cluster.
+type Cluster interface {
+ // SetFields will set any dependencies on an object for which the object has implemented the inject
+ // interface - e.g. inject.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() *rest.Config
+
+ // GetScheme returns an initialized Scheme
+ GetScheme() *runtime.Scheme
+
+ // GetClient returns a client configured with the Config. This client may
+ // not be a fully "direct" client -- it may read from a cache, for
+ // instance. See Options.NewClient for more information on how the default
+ // implementation works.
+ GetClient() client.Client
+
+ // GetFieldIndexer returns a client.FieldIndexer configured with the client
+ GetFieldIndexer() client.FieldIndexer
+
+ // GetCache returns a cache.Cache
+ GetCache() cache.Cache
+
+ // GetEventRecorderFor returns a new EventRecorder for the provided name
+ GetEventRecorderFor(name string) record.EventRecorder
+
+ // GetRESTMapper returns a RESTMapper
+ GetRESTMapper() meta.RESTMapper
+
+ // GetAPIReader returns a reader that will be configured to use the API server.
+ // This should be used sparingly and only when the client does not fit your
+ // use case.
+ GetAPIReader() client.Reader
+
+ // Start starts the cluster
+ Start(ctx context.Context) error
+}
+
+// Options are the possible options that can be configured for a Cluster.
+type Options 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
+
+ // MapperProvider provides the rest mapper used to map go types to Kubernetes APIs
+ MapperProvider func(c *rest.Config) (meta.RESTMapper, error)
+
+ // Logger is the logger that should be used by this Cluster.
+ // If none is set, it defaults to log.Log global logger.
+ Logger logr.Logger
+
+ // SyncPeriod determines the minimum frequency at which watched resources are
+ // reconciled. A lower period will correct entropy more quickly, but reduce
+ // responsiveness to change if there are many watched resources. Change this
+ // value only if you know what you are doing. Defaults to 10 hours if unset.
+ // there will a 10 percent jitter between the SyncPeriod of all controllers
+ // so that all controllers will not send list requests simultaneously.
+ SyncPeriod *time.Duration
+
+ // Namespace if specified restricts the manager's cache to watch objects in
+ // the desired namespace Defaults to all namespaces
+ //
+ // Note: If a namespace is specified, controllers can still Watch for a
+ // cluster-scoped resource (e.g Node). For namespaced resources the cache
+ // will only hold objects from the desired namespace.
+ Namespace string
+
+ // 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 NewClientFunc
+
+ // ClientDisableCacheFor tells the client that, if any cache is used, to bypass it
+ // for the given objects.
+ ClientDisableCacheFor []client.Object
+
+ // DryRunClient specifies whether the client should be configured to enforce
+ // dryRun mode.
+ DryRunClient bool
+
+ // EventBroadcaster records Events emitted by the manager and sends them to the Kubernetes API
+ // Use this to customize the event correlator and spam filter
+ //
+ // Deprecated: using this may cause goroutine leaks if the lifetime of your manager or controllers
+ // is shorter than the lifetime of your process.
+ EventBroadcaster record.EventBroadcaster
+
+ // makeBroadcaster allows deferring the creation of the broadcaster to
+ // avoid leaking goroutines if we never call Start on this manager. It also
+ // returns whether or not this is a "owned" broadcaster, and as such should be
+ // stopped with the manager.
+ makeBroadcaster intrec.EventBroadcasterProducer
+
+ // Dependency injection for testing
+ newRecorderProvider func(config *rest.Config, scheme *runtime.Scheme, logger logr.Logger, makeBroadcaster intrec.EventBroadcasterProducer) (*intrec.Provider, error)
+}
+
+// Option can be used to manipulate Options.
+type Option func(*Options)
+
+// New constructs a brand new cluster.
+func New(config *rest.Config, opts ...Option) (Cluster, error) {
+ if config == nil {
+ return nil, errors.New("must specify Config")
+ }
+
+ options := Options{}
+ for _, opt := range opts {
+ opt(&options)
+ }
+ options = setOptionsDefaults(options)
+
+ // Create the mapper provider
+ mapper, err := options.MapperProvider(config)
+ if err != nil {
+ options.Logger.Error(err, "Failed to get API Group-Resources")
+ return nil, err
+ }
+
+ // 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})
+ if err != nil {
+ return nil, err
+ }
+
+ clientOptions := client.Options{Scheme: options.Scheme, Mapper: mapper}
+
+ apiReader, err := client.New(config, clientOptions)
+ if err != nil {
+ return nil, err
+ }
+
+ writeObj, err := options.NewClient(cache, config, clientOptions, options.ClientDisableCacheFor...)
+ if err != nil {
+ return nil, err
+ }
+
+ if options.DryRunClient {
+ writeObj = client.NewDryRunClient(writeObj)
+ }
+
+ // 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
+ // 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)
+ if err != nil {
+ return nil, err
+ }
+
+ return &cluster{
+ config: config,
+ scheme: options.Scheme,
+ cache: cache,
+ fieldIndexes: cache,
+ client: writeObj,
+ apiReader: apiReader,
+ recorderProvider: recorderProvider,
+ mapper: mapper,
+ logger: options.Logger,
+ }, nil
+}
+
+// setOptionsDefaults set default values for Options fields.
+func setOptionsDefaults(options Options) Options {
+ // Use the Kubernetes client-go scheme if none is specified
+ if options.Scheme == nil {
+ options.Scheme = scheme.Scheme
+ }
+
+ if options.MapperProvider == nil {
+ options.MapperProvider = func(c *rest.Config) (meta.RESTMapper, error) {
+ return apiutil.NewDynamicRESTMapper(c)
+ }
+ }
+
+ // Allow users to define how to create a new client
+ if options.NewClient == nil {
+ options.NewClient = DefaultNewClient
+ }
+
+ // Allow newCache to be mocked
+ if options.NewCache == nil {
+ options.NewCache = cache.New
+ }
+
+ // Allow newRecorderProvider to be mocked
+ if options.newRecorderProvider == nil {
+ options.newRecorderProvider = intrec.NewProvider
+ }
+
+ // This is duplicated with pkg/manager, we need it here to provide
+ // the user with an EventBroadcaster and there for the Leader election
+ if options.EventBroadcaster == nil {
+ // defer initialization to avoid leaking by default
+ options.makeBroadcaster = func() (record.EventBroadcaster, bool) {
+ return record.NewBroadcaster(), true
+ }
+ } else {
+ options.makeBroadcaster = func() (record.EventBroadcaster, bool) {
+ return options.EventBroadcaster, false
+ }
+ }
+
+ if options.Logger == nil {
+ options.Logger = logf.RuntimeLog.WithName("cluster")
+ }
+
+ return options
+}
+
+// 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)
+
+// DefaultNewClient creates the default caching client.
+func DefaultNewClient(cache cache.Cache, config *rest.Config, options client.Options, uncachedObjects ...client.Object) (client.Client, error) {
+ c, err := client.New(config, options)
+ if err != nil {
+ return nil, err
+ }
+
+ return client.NewDelegatingClient(client.NewDelegatingClientInput{
+ CacheReader: cache,
+ Client: c,
+ UncachedObjects: uncachedObjects,
+ })
+}
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/cluster/internal.go b/vendor/sigs.k8s.io/controller-runtime/pkg/cluster/internal.go
new file mode 100644
index 000000000..125e1d144
--- /dev/null
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/cluster/internal.go
@@ -0,0 +1,128 @@
+/*
+Copyright 2020 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package cluster
+
+import (
+ "context"
+
+ "github.com/go-logr/logr"
+ "k8s.io/apimachinery/pkg/api/meta"
+ "k8s.io/apimachinery/pkg/runtime"
+ "k8s.io/client-go/rest"
+ "k8s.io/client-go/tools/record"
+
+ "sigs.k8s.io/controller-runtime/pkg/cache"
+ "sigs.k8s.io/controller-runtime/pkg/client"
+ intrec "sigs.k8s.io/controller-runtime/pkg/internal/recorder"
+ "sigs.k8s.io/controller-runtime/pkg/runtime/inject"
+)
+
+type cluster struct {
+ // config is the rest.config used to talk to the apiserver. Required.
+ config *rest.Config
+
+ // scheme is the scheme injected into Controllers, EventHandlers, Sources and Predicates. Defaults
+ // to scheme.scheme.
+ scheme *runtime.Scheme
+
+ 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 client.Reader
+
+ // fieldIndexes knows how to add field indexes over the Cache used by this controller,
+ // which can later be consumed via field selectors from the injected client.
+ fieldIndexes client.FieldIndexer
+
+ // recorderProvider is used to generate event recorders that will be injected into Controllers
+ // (and EventHandlers, Sources and Predicates).
+ recorderProvider *intrec.Provider
+
+ // mapper is used to map resources to kind, and map kind and version.
+ mapper meta.RESTMapper
+
+ // Logger is the logger that should be used by this manager.
+ // If none is set, it defaults to log.Log global 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 {
+ return c.config
+}
+
+func (c *cluster) GetClient() client.Client {
+ return c.client
+}
+
+func (c *cluster) GetScheme() *runtime.Scheme {
+ return c.scheme
+}
+
+func (c *cluster) GetFieldIndexer() client.FieldIndexer {
+ return c.fieldIndexes
+}
+
+func (c *cluster) GetCache() cache.Cache {
+ return c.cache
+}
+
+func (c *cluster) GetEventRecorderFor(name string) record.EventRecorder {
+ return c.recorderProvider.GetEventRecorderFor(name)
+}
+
+func (c *cluster) GetRESTMapper() meta.RESTMapper {
+ return c.mapper
+}
+
+func (c *cluster) GetAPIReader() client.Reader {
+ return c.apiReader
+}
+
+func (c *cluster) GetLogger() logr.Logger {
+ return c.logger
+}
+
+func (c *cluster) Start(ctx context.Context) error {
+ defer c.recorderProvider.Stop(ctx)
+ return c.cache.Start(ctx)
+}
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/config/config.go b/vendor/sigs.k8s.io/controller-runtime/pkg/config/config.go
new file mode 100644
index 000000000..f23b02df0
--- /dev/null
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/config/config.go
@@ -0,0 +1,112 @@
+/*
+Copyright 2020 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package config
+
+import (
+ "fmt"
+ ioutil "io/ioutil"
+ "sync"
+
+ "k8s.io/apimachinery/pkg/runtime"
+ "k8s.io/apimachinery/pkg/runtime/serializer"
+ utilruntime "k8s.io/apimachinery/pkg/util/runtime"
+ "sigs.k8s.io/controller-runtime/pkg/config/v1alpha1"
+)
+
+// ControllerManagerConfiguration defines the functions necessary to parse a config file
+// and to configure the Options struct for the ctrl.Manager.
+type ControllerManagerConfiguration interface {
+ runtime.Object
+
+ // Complete returns the versioned configuration
+ Complete() (v1alpha1.ControllerManagerConfigurationSpec, error)
+}
+
+// DeferredFileLoader is used to configure the decoder for loading controller
+// runtime component config types.
+type DeferredFileLoader struct {
+ ControllerManagerConfiguration
+ path string
+ scheme *runtime.Scheme
+ once sync.Once
+ err error
+}
+
+// File will set up the deferred file loader for the configuration
+// this will also configure the defaults for the loader if nothing is
+//
+// Defaults:
+// Path: "./config.yaml"
+// Kind: GenericControllerManagerConfiguration
+func File() *DeferredFileLoader {
+ scheme := runtime.NewScheme()
+ utilruntime.Must(v1alpha1.AddToScheme(scheme))
+ return &DeferredFileLoader{
+ path: "./config.yaml",
+ ControllerManagerConfiguration: &v1alpha1.ControllerManagerConfiguration{},
+ scheme: scheme,
+ }
+}
+
+// Complete will use sync.Once to set the scheme.
+func (d *DeferredFileLoader) Complete() (v1alpha1.ControllerManagerConfigurationSpec, error) {
+ d.once.Do(d.loadFile)
+ if d.err != nil {
+ return v1alpha1.ControllerManagerConfigurationSpec{}, d.err
+ }
+ return d.ControllerManagerConfiguration.Complete()
+}
+
+// AtPath will set the path to load the file for the decoder.
+func (d *DeferredFileLoader) AtPath(path string) *DeferredFileLoader {
+ d.path = path
+ return d
+}
+
+// OfKind will set the type to be used for decoding the file into.
+func (d *DeferredFileLoader) OfKind(obj ControllerManagerConfiguration) *DeferredFileLoader {
+ d.ControllerManagerConfiguration = obj
+ return d
+}
+
+// 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.
+func (d *DeferredFileLoader) loadFile() {
+ if d.scheme == nil {
+ d.err = fmt.Errorf("scheme not supplied to controller configuration loader")
+ return
+ }
+
+ content, err := ioutil.ReadFile(d.path)
+ if err != nil {
+ d.err = fmt.Errorf("could not read file at %s", d.path)
+ return
+ }
+
+ codecs := serializer.NewCodecFactory(d.scheme)
+
+ // Regardless of if the bytes are of any external version,
+ // it will be read successfully and converted into the internal version
+ if err = runtime.DecodeInto(codecs.UniversalDecoder(), content, d.ControllerManagerConfiguration); err != nil {
+ d.err = fmt.Errorf("could not decode file into runtime.Object")
+ }
+}
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/config/doc.go b/vendor/sigs.k8s.io/controller-runtime/pkg/config/doc.go
new file mode 100644
index 000000000..ebd8243f3
--- /dev/null
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/config/doc.go
@@ -0,0 +1,25 @@
+/*
+Copyright 2020 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+// Package config contains functionality for interacting with ComponentConfig
+// files
+//
+// 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
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/config/v1alpha1/doc.go b/vendor/sigs.k8s.io/controller-runtime/pkg/config/v1alpha1/doc.go
new file mode 100644
index 000000000..1e3adbafb
--- /dev/null
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/config/v1alpha1/doc.go
@@ -0,0 +1,20 @@
+/*
+Copyright 2020 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+// Package v1alpha1 provides the ControllerManagerConfiguration used for
+// configuring ctrl.Manager
+// +kubebuilder:object:generate=true
+package v1alpha1
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/config/v1alpha1/register.go b/vendor/sigs.k8s.io/controller-runtime/pkg/config/v1alpha1/register.go
new file mode 100644
index 000000000..9efdbc066
--- /dev/null
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/config/v1alpha1/register.go
@@ -0,0 +1,37 @@
+/*
+Copyright 2020 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package v1alpha1
+
+import (
+ "k8s.io/apimachinery/pkg/runtime/schema"
+ "sigs.k8s.io/controller-runtime/pkg/scheme"
+)
+
+var (
+ // GroupVersion is group version used to register these objects.
+ GroupVersion = schema.GroupVersion{Group: "controller-runtime.sigs.k8s.io", Version: "v1alpha1"}
+
+ // SchemeBuilder is used to add go types to the GroupVersionKind scheme.
+ SchemeBuilder = &scheme.Builder{GroupVersion: GroupVersion}
+
+ // AddToScheme adds the types in this group-version to the given scheme.
+ AddToScheme = SchemeBuilder.AddToScheme
+)
+
+func init() {
+ SchemeBuilder.Register(&ControllerManagerConfiguration{})
+}
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/config/v1alpha1/types.go b/vendor/sigs.k8s.io/controller-runtime/pkg/config/v1alpha1/types.go
new file mode 100644
index 000000000..e67b62e51
--- /dev/null
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/config/v1alpha1/types.go
@@ -0,0 +1,157 @@
+/*
+Copyright 2020 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package v1alpha1
+
+import (
+ "time"
+
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+
+ configv1alpha1 "k8s.io/component-base/config/v1alpha1"
+)
+
+// ControllerManagerConfigurationSpec defines the desired state of GenericControllerManagerConfiguration.
+type ControllerManagerConfigurationSpec struct {
+ // SyncPeriod determines the minimum frequency at which watched resources are
+ // reconciled. A lower period will correct entropy more quickly, but reduce
+ // responsiveness to change if there are many watched resources. Change this
+ // value only if you know what you are doing. Defaults to 10 hours if unset.
+ // there will a 10 percent jitter between the SyncPeriod of all controllers
+ // so that all controllers will not send list requests simultaneously.
+ // +optional
+ SyncPeriod *metav1.Duration `json:"syncPeriod,omitempty"`
+
+ // LeaderElection is the LeaderElection config to be used when configuring
+ // the manager.Manager leader election
+ // +optional
+ LeaderElection *configv1alpha1.LeaderElectionConfiguration `json:"leaderElection,omitempty"`
+
+ // CacheNamespace if specified restricts the manager's cache to watch objects in
+ // the desired namespace Defaults to all namespaces
+ //
+ // Note: If a namespace is specified, controllers can still Watch for a
+ // cluster-scoped resource (e.g Node). For namespaced resources the cache
+ // will only hold objects from the desired namespace.
+ // +optional
+ CacheNamespace string `json:"cacheNamespace,omitempty"`
+
+ // GracefulShutdownTimeout is the duration given to runnable to stop before the manager actually returns on stop.
+ // To disable graceful shutdown, set to time.Duration(0)
+ // To use graceful shutdown without timeout, set to a negative duration, e.G. time.Duration(-1)
+ // The graceful shutdown is skipped for safety reasons in case the leader election lease is lost.
+ GracefulShutdownTimeout *metav1.Duration `json:"gracefulShutDown,omitempty"`
+
+ // Controller contains global configuration options for controllers
+ // registered within this manager.
+ // +optional
+ Controller *ControllerConfigurationSpec `json:"controller,omitempty"`
+
+ // Metrics contains thw controller metrics configuration
+ // +optional
+ Metrics ControllerMetrics `json:"metrics,omitempty"`
+
+ // Health contains the controller health configuration
+ // +optional
+ Health ControllerHealth `json:"health,omitempty"`
+
+ // Webhook contains the controllers webhook configuration
+ // +optional
+ Webhook ControllerWebhook `json:"webhook,omitempty"`
+}
+
+// ControllerConfigurationSpec defines the global configuration for
+// controllers registered with the manager.
+type ControllerConfigurationSpec struct {
+ // GroupKindConcurrency is a map from a Kind to the number of concurrent reconciliation
+ // allowed for that controller.
+ //
+ // When a controller is registered within this manager using the builder utilities,
+ // users have to specify the type the controller reconciles in the For(...) call.
+ // If the object's kind passed matches one of the keys in this map, the concurrency
+ // for that controller is set to the number specified.
+ //
+ // The key is expected to be consistent in form with GroupKind.String(),
+ // e.g. ReplicaSet in apps group (regardless of version) would be `ReplicaSet.apps`.
+ //
+ // +optional
+ GroupKindConcurrency map[string]int `json:"groupKindConcurrency,omitempty"`
+
+ // CacheSyncTimeout refers to the time limit set to wait for syncing caches.
+ // Defaults to 2 minutes if not set.
+ // +optional
+ CacheSyncTimeout *time.Duration `json:"cacheSyncTimeout,omitempty"`
+}
+
+// ControllerMetrics defines the metrics configs.
+type ControllerMetrics struct {
+ // BindAddress is the TCP address that the controller should bind to
+ // for serving prometheus metrics.
+ // It can be set to "0" to disable the metrics serving.
+ // +optional
+ BindAddress string `json:"bindAddress,omitempty"`
+}
+
+// ControllerHealth defines the health configs.
+type ControllerHealth struct {
+ // HealthProbeBindAddress is the TCP address that the controller should bind to
+ // for serving health probes
+ // +optional
+ HealthProbeBindAddress string `json:"healthProbeBindAddress,omitempty"`
+
+ // ReadinessEndpointName, defaults to "readyz"
+ // +optional
+ ReadinessEndpointName string `json:"readinessEndpointName,omitempty"`
+
+ // LivenessEndpointName, defaults to "healthz"
+ // +optional
+ LivenessEndpointName string `json:"livenessEndpointName,omitempty"`
+}
+
+// ControllerWebhook defines the webhook server for the controller.
+type ControllerWebhook struct {
+ // Port is the port that the webhook server serves at.
+ // It is used to set webhook.Server.Port.
+ // +optional
+ Port *int `json:"port,omitempty"`
+
+ // Host is the hostname that the webhook server binds to.
+ // It is used to set webhook.Server.Host.
+ // +optional
+ Host string `json:"host,omitempty"`
+
+ // CertDir is the directory that contains the server key and certificate.
+ // if not set, webhook server would look up the server key and certificate in
+ // {TempDir}/k8s-webhook-server/serving-certs. The server key and certificate
+ // must be named tls.key and tls.crt, respectively.
+ // +optional
+ CertDir string `json:"certDir,omitempty"`
+}
+
+// +kubebuilder:object:root=true
+
+// ControllerManagerConfiguration is the Schema for the GenericControllerManagerConfigurations API.
+type ControllerManagerConfiguration struct {
+ metav1.TypeMeta `json:",inline"`
+
+ // ControllerManagerConfiguration returns the contfigurations for controllers
+ ControllerManagerConfigurationSpec `json:",inline"`
+}
+
+// Complete returns the configuration for controller-runtime.
+func (c *ControllerManagerConfigurationSpec) Complete() (ControllerManagerConfigurationSpec, error) {
+ return *c, nil
+}
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/config/v1alpha1/zz_generated.deepcopy.go b/vendor/sigs.k8s.io/controller-runtime/pkg/config/v1alpha1/zz_generated.deepcopy.go
new file mode 100644
index 000000000..752fa9754
--- /dev/null
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/config/v1alpha1/zz_generated.deepcopy.go
@@ -0,0 +1,152 @@
+// +build !ignore_autogenerated
+
+// Code generated by controller-gen. DO NOT EDIT.
+
+package v1alpha1
+
+import (
+ "k8s.io/apimachinery/pkg/apis/meta/v1"
+ runtime "k8s.io/apimachinery/pkg/runtime"
+ configv1alpha1 "k8s.io/component-base/config/v1alpha1"
+ timex "time"
+)
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *ControllerConfigurationSpec) DeepCopyInto(out *ControllerConfigurationSpec) {
+ *out = *in
+ if in.GroupKindConcurrency != nil {
+ in, out := &in.GroupKindConcurrency, &out.GroupKindConcurrency
+ *out = make(map[string]int, len(*in))
+ for key, val := range *in {
+ (*out)[key] = val
+ }
+ }
+ if in.CacheSyncTimeout != nil {
+ in, out := &in.CacheSyncTimeout, &out.CacheSyncTimeout
+ *out = new(timex.Duration)
+ **out = **in
+ }
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ControllerConfigurationSpec.
+func (in *ControllerConfigurationSpec) DeepCopy() *ControllerConfigurationSpec {
+ if in == nil {
+ return nil
+ }
+ out := new(ControllerConfigurationSpec)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *ControllerHealth) DeepCopyInto(out *ControllerHealth) {
+ *out = *in
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ControllerHealth.
+func (in *ControllerHealth) DeepCopy() *ControllerHealth {
+ if in == nil {
+ return nil
+ }
+ out := new(ControllerHealth)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *ControllerManagerConfiguration) DeepCopyInto(out *ControllerManagerConfiguration) {
+ *out = *in
+ out.TypeMeta = in.TypeMeta
+ in.ControllerManagerConfigurationSpec.DeepCopyInto(&out.ControllerManagerConfigurationSpec)
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ControllerManagerConfiguration.
+func (in *ControllerManagerConfiguration) DeepCopy() *ControllerManagerConfiguration {
+ if in == nil {
+ return nil
+ }
+ out := new(ControllerManagerConfiguration)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
+func (in *ControllerManagerConfiguration) DeepCopyObject() runtime.Object {
+ if c := in.DeepCopy(); c != nil {
+ return c
+ }
+ return nil
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *ControllerManagerConfigurationSpec) DeepCopyInto(out *ControllerManagerConfigurationSpec) {
+ *out = *in
+ if in.SyncPeriod != nil {
+ in, out := &in.SyncPeriod, &out.SyncPeriod
+ *out = new(v1.Duration)
+ **out = **in
+ }
+ if in.LeaderElection != nil {
+ in, out := &in.LeaderElection, &out.LeaderElection
+ *out = new(configv1alpha1.LeaderElectionConfiguration)
+ (*in).DeepCopyInto(*out)
+ }
+ if in.GracefulShutdownTimeout != nil {
+ in, out := &in.GracefulShutdownTimeout, &out.GracefulShutdownTimeout
+ *out = new(v1.Duration)
+ **out = **in
+ }
+ if in.Controller != nil {
+ in, out := &in.Controller, &out.Controller
+ *out = new(ControllerConfigurationSpec)
+ (*in).DeepCopyInto(*out)
+ }
+ out.Metrics = in.Metrics
+ out.Health = in.Health
+ in.Webhook.DeepCopyInto(&out.Webhook)
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ControllerManagerConfigurationSpec.
+func (in *ControllerManagerConfigurationSpec) DeepCopy() *ControllerManagerConfigurationSpec {
+ if in == nil {
+ return nil
+ }
+ out := new(ControllerManagerConfigurationSpec)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *ControllerMetrics) DeepCopyInto(out *ControllerMetrics) {
+ *out = *in
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ControllerMetrics.
+func (in *ControllerMetrics) DeepCopy() *ControllerMetrics {
+ if in == nil {
+ return nil
+ }
+ out := new(ControllerMetrics)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *ControllerWebhook) DeepCopyInto(out *ControllerWebhook) {
+ *out = *in
+ if in.Port != nil {
+ in, out := &in.Port, &out.Port
+ *out = new(int)
+ **out = **in
+ }
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ControllerWebhook.
+func (in *ControllerWebhook) DeepCopy() *ControllerWebhook {
+ if in == nil {
+ return nil
+ }
+ out := new(ControllerWebhook)
+ in.DeepCopyInto(out)
+ return out
+}
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/controller/controller.go b/vendor/sigs.k8s.io/controller-runtime/pkg/controller/controller.go
new file mode 100644
index 000000000..88ba78671
--- /dev/null
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/controller/controller.go
@@ -0,0 +1,141 @@
+/*
+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 controller
+
+import (
+ "context"
+ "fmt"
+ "time"
+
+ "github.com/go-logr/logr"
+ "k8s.io/client-go/util/workqueue"
+ "sigs.k8s.io/controller-runtime/pkg/handler"
+ "sigs.k8s.io/controller-runtime/pkg/internal/controller"
+ "sigs.k8s.io/controller-runtime/pkg/manager"
+ "sigs.k8s.io/controller-runtime/pkg/predicate"
+ "sigs.k8s.io/controller-runtime/pkg/ratelimiter"
+ "sigs.k8s.io/controller-runtime/pkg/reconcile"
+ "sigs.k8s.io/controller-runtime/pkg/source"
+)
+
+// Options are the arguments for creating a new Controller.
+type Options struct {
+ // MaxConcurrentReconciles is the maximum number of concurrent Reconciles which can be run. Defaults to 1.
+ MaxConcurrentReconciles int
+
+ // Reconciler reconciles an object
+ Reconciler reconcile.Reconciler
+
+ // RateLimiter is used to limit how frequently requests may be queued.
+ // Defaults to MaxOfRateLimiter which has both overall and per-item rate limiting.
+ // The overall is a token bucket and the per-item is exponential.
+ RateLimiter ratelimiter.RateLimiter
+
+ // Log is the logger used for this controller and passed to each reconciliation
+ // request via the context field.
+ Log 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.
+ RecoverPanic bool
+}
+
+// Controller implements a Kubernetes API. A Controller manages a work queue fed reconcile.Requests
+// from source.Sources. Work is performed through the reconcile.Reconciler for each enqueued item.
+// Work typically is reads and writes Kubernetes objects to make the system state match the state specified
+// in the object Spec.
+type Controller interface {
+ // Reconciler is called to reconcile an object by Namespace/Name
+ reconcile.Reconciler
+
+ // Watch takes events provided by a Source and uses the EventHandler to
+ // enqueue reconcile.Requests in response to the events.
+ //
+ // Watch may be provided one or more Predicates to filter events before
+ // they are given to the EventHandler. Events will be passed to the
+ // EventHandler if all provided Predicates evaluate to true.
+ Watch(src source.Source, eventhandler handler.EventHandler, predicates ...predicate.Predicate) error
+
+ // Start starts the controller. Start blocks until the context is closed or a
+ // controller has an error starting.
+ Start(ctx context.Context) error
+
+ // GetLogger returns this controller logger prefilled with basic information.
+ GetLogger() logr.Logger
+}
+
+// New returns a new Controller registered with the Manager. The Manager will ensure that shared Caches have
+// been synced before the Controller is Started.
+func New(name string, mgr manager.Manager, options Options) (Controller, error) {
+ c, err := NewUnmanaged(name, mgr, options)
+ if err != nil {
+ return nil, err
+ }
+
+ // Add the controller as a Manager components
+ return c, mgr.Add(c)
+}
+
+// NewUnmanaged returns a new controller without adding it to the manager. The
+// caller is responsible for starting the returned controller.
+func NewUnmanaged(name string, mgr manager.Manager, options Options) (Controller, error) {
+ if options.Reconciler == nil {
+ return nil, fmt.Errorf("must specify Reconciler")
+ }
+
+ if len(name) == 0 {
+ return nil, fmt.Errorf("must specify Name for Controller")
+ }
+
+ if options.Log == nil {
+ options.Log = mgr.GetLogger()
+ }
+
+ if options.MaxConcurrentReconciles <= 0 {
+ options.MaxConcurrentReconciles = 1
+ }
+
+ if options.CacheSyncTimeout == 0 {
+ options.CacheSyncTimeout = 2 * time.Minute
+ }
+
+ if options.RateLimiter == nil {
+ options.RateLimiter = workqueue.DefaultControllerRateLimiter()
+ }
+
+ // Inject dependencies into Reconciler
+ if err := mgr.SetFields(options.Reconciler); err != nil {
+ return nil, err
+ }
+
+ // Create controller with dependencies set
+ return &controller.Controller{
+ Do: options.Reconciler,
+ MakeQueue: func() workqueue.RateLimitingInterface {
+ return workqueue.NewNamedRateLimitingQueue(options.RateLimiter, name)
+ },
+ MaxConcurrentReconciles: options.MaxConcurrentReconciles,
+ CacheSyncTimeout: options.CacheSyncTimeout,
+ SetFields: mgr.SetFields,
+ Name: name,
+ Log: options.Log.WithName("controller").WithName(name),
+ RecoverPanic: options.RecoverPanic,
+ }, nil
+}
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/controller/controllerutil/controllerutil.go b/vendor/sigs.k8s.io/controller-runtime/pkg/controller/controllerutil/controllerutil.go
new file mode 100644
index 000000000..13f14a7ed
--- /dev/null
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/controller/controllerutil/controllerutil.go
@@ -0,0 +1,389 @@
+/*
+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 controllerutil
+
+import (
+ "context"
+ "fmt"
+ "reflect"
+
+ "k8s.io/apimachinery/pkg/api/equality"
+ apierrors "k8s.io/apimachinery/pkg/api/errors"
+ 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/utils/pointer"
+ "sigs.k8s.io/controller-runtime/pkg/client"
+ "sigs.k8s.io/controller-runtime/pkg/client/apiutil"
+)
+
+// AlreadyOwnedError is an error returned if the object you are trying to assign
+// a controller reference is already owned by another controller Object is the
+// subject and Owner is the reference for the current owner.
+type AlreadyOwnedError struct {
+ Object metav1.Object
+ Owner metav1.OwnerReference
+}
+
+func (e *AlreadyOwnedError) Error() string {
+ return fmt.Sprintf("Object %s/%s is already owned by another %s controller %s", e.Object.GetNamespace(), e.Object.GetName(), e.Owner.Kind, e.Owner.Name)
+}
+
+func newAlreadyOwnedError(obj metav1.Object, owner metav1.OwnerReference) *AlreadyOwnedError {
+ return &AlreadyOwnedError{
+ Object: obj,
+ Owner: owner,
+ }
+}
+
+// SetControllerReference sets owner as a Controller OwnerReference on controlled.
+// This is used for garbage collection of the controlled object and for
+// reconciling the owner object on changes to controlled (with a Watch + EnqueueRequestForOwner).
+// Since only one OwnerReference can be a controller, it returns an error if
+// there is another OwnerReference with Controller flag set.
+func SetControllerReference(owner, controlled metav1.Object, scheme *runtime.Scheme) error {
+ // Validate the owner.
+ ro, ok := owner.(runtime.Object)
+ if !ok {
+ return fmt.Errorf("%T is not a runtime.Object, cannot call SetControllerReference", owner)
+ }
+ if err := validateOwner(owner, controlled); err != nil {
+ return err
+ }
+
+ // Create a new controller ref.
+ gvk, err := apiutil.GVKForObject(ro, scheme)
+ if err != nil {
+ return err
+ }
+ ref := metav1.OwnerReference{
+ APIVersion: gvk.GroupVersion().String(),
+ Kind: gvk.Kind,
+ Name: owner.GetName(),
+ UID: owner.GetUID(),
+ BlockOwnerDeletion: pointer.BoolPtr(true),
+ Controller: pointer.BoolPtr(true),
+ }
+
+ // Return early with an error if the object is already controlled.
+ if existing := metav1.GetControllerOf(controlled); existing != nil && !referSameObject(*existing, ref) {
+ return newAlreadyOwnedError(controlled, *existing)
+ }
+
+ // Update owner references and return.
+ upsertOwnerRef(ref, controlled)
+ return nil
+}
+
+// SetOwnerReference is a helper method to make sure the given object contains an object reference to the object provided.
+// This allows you to declare that owner has a dependency on the object without specifying it as a controller.
+// If a reference to the same object already exists, it'll be overwritten with the newly provided version.
+func SetOwnerReference(owner, object metav1.Object, scheme *runtime.Scheme) error {
+ // Validate the owner.
+ ro, ok := owner.(runtime.Object)
+ if !ok {
+ return fmt.Errorf("%T is not a runtime.Object, cannot call SetOwnerReference", owner)
+ }
+ if err := validateOwner(owner, object); err != nil {
+ return err
+ }
+
+ // Create a new owner ref.
+ gvk, err := apiutil.GVKForObject(ro, scheme)
+ if err != nil {
+ return err
+ }
+ ref := metav1.OwnerReference{
+ APIVersion: gvk.GroupVersion().String(),
+ Kind: gvk.Kind,
+ UID: owner.GetUID(),
+ Name: owner.GetName(),
+ }
+
+ // Update owner references and return.
+ upsertOwnerRef(ref, object)
+ return nil
+}
+
+func upsertOwnerRef(ref metav1.OwnerReference, object metav1.Object) {
+ owners := object.GetOwnerReferences()
+ if idx := indexOwnerRef(owners, ref); idx == -1 {
+ owners = append(owners, ref)
+ } else {
+ owners[idx] = ref
+ }
+ object.SetOwnerReferences(owners)
+}
+
+// indexOwnerRef returns the index of the owner reference in the slice if found, or -1.
+func indexOwnerRef(ownerReferences []metav1.OwnerReference, ref metav1.OwnerReference) int {
+ for index, r := range ownerReferences {
+ if referSameObject(r, ref) {
+ return index
+ }
+ }
+ return -1
+}
+
+func validateOwner(owner, object metav1.Object) error {
+ ownerNs := owner.GetNamespace()
+ if ownerNs != "" {
+ objNs := object.GetNamespace()
+ if objNs == "" {
+ return fmt.Errorf("cluster-scoped resource must not have a namespace-scoped owner, owner's namespace %s", ownerNs)
+ }
+ if ownerNs != objNs {
+ return fmt.Errorf("cross-namespace owner references are disallowed, owner's namespace %s, obj's namespace %s", owner.GetNamespace(), object.GetNamespace())
+ }
+ }
+ return nil
+}
+
+// Returns true if a and b point to the same object.
+func referSameObject(a, b metav1.OwnerReference) bool {
+ aGV, err := schema.ParseGroupVersion(a.APIVersion)
+ if err != nil {
+ return false
+ }
+
+ bGV, err := schema.ParseGroupVersion(b.APIVersion)
+ if err != nil {
+ return false
+ }
+
+ return aGV.Group == bGV.Group && a.Kind == b.Kind && a.Name == b.Name
+}
+
+// OperationResult is the action result of a CreateOrUpdate call.
+type OperationResult string
+
+const ( // They should complete the sentence "Deployment default/foo has been ..."
+ // OperationResultNone means that the resource has not been changed.
+ OperationResultNone OperationResult = "unchanged"
+ // OperationResultCreated means that a new resource is created.
+ OperationResultCreated OperationResult = "created"
+ // OperationResultUpdated means that an existing resource is updated.
+ OperationResultUpdated OperationResult = "updated"
+ // OperationResultUpdatedStatus means that an existing resource and its status is updated.
+ OperationResultUpdatedStatus OperationResult = "updatedStatus"
+ // OperationResultUpdatedStatusOnly means that only an existing status is updated.
+ OperationResultUpdatedStatusOnly OperationResult = "updatedStatusOnly"
+)
+
+// CreateOrUpdate creates or updates the given object in the Kubernetes
+// cluster. The object's desired state must be reconciled with the existing
+// state inside the passed in callback MutateFn.
+//
+// The MutateFn is called regardless of creating or updating an object.
+//
+// It returns the executed operation and an error.
+func CreateOrUpdate(ctx context.Context, c client.Client, obj client.Object, f MutateFn) (OperationResult, error) {
+ key := client.ObjectKeyFromObject(obj)
+ if err := c.Get(ctx, key, obj); err != nil {
+ if !apierrors.IsNotFound(err) {
+ return OperationResultNone, err
+ }
+ if err := mutate(f, key, obj); err != nil {
+ return OperationResultNone, err
+ }
+ if err := c.Create(ctx, obj); err != nil {
+ return OperationResultNone, err
+ }
+ return OperationResultCreated, nil
+ }
+
+ existing := obj.DeepCopyObject() //nolint
+ if err := mutate(f, key, obj); err != nil {
+ return OperationResultNone, err
+ }
+
+ if equality.Semantic.DeepEqual(existing, obj) {
+ return OperationResultNone, nil
+ }
+
+ if err := c.Update(ctx, obj); err != nil {
+ return OperationResultNone, err
+ }
+ return OperationResultUpdated, nil
+}
+
+// CreateOrPatch creates or patches the given object in the Kubernetes
+// cluster. The object's desired state must be reconciled with the before
+// state inside the passed in callback MutateFn.
+//
+// The MutateFn is called regardless of creating or updating an object.
+//
+// It returns the executed operation and an error.
+func CreateOrPatch(ctx context.Context, c client.Client, obj client.Object, f MutateFn) (OperationResult, error) {
+ key := client.ObjectKeyFromObject(obj)
+ if err := c.Get(ctx, key, obj); err != nil {
+ if !apierrors.IsNotFound(err) {
+ return OperationResultNone, err
+ }
+ if f != nil {
+ if err := mutate(f, key, obj); err != nil {
+ return OperationResultNone, err
+ }
+ }
+ if err := c.Create(ctx, obj); err != nil {
+ return OperationResultNone, err
+ }
+ return OperationResultCreated, nil
+ }
+
+ // Create patches for the object and its possible status.
+ objPatch := client.MergeFrom(obj.DeepCopyObject().(client.Object))
+ statusPatch := client.MergeFrom(obj.DeepCopyObject().(client.Object))
+
+ // Create a copy of the original object as well as converting that copy to
+ // unstructured data.
+ before, err := runtime.DefaultUnstructuredConverter.ToUnstructured(obj.DeepCopyObject())
+ if err != nil {
+ return OperationResultNone, err
+ }
+
+ // Attempt to extract the status from the resource for easier comparison later
+ beforeStatus, hasBeforeStatus, err := unstructured.NestedFieldCopy(before, "status")
+ if err != nil {
+ return OperationResultNone, err
+ }
+
+ // If the resource contains a status then remove it from the unstructured
+ // copy to avoid unnecessary patching later.
+ if hasBeforeStatus {
+ unstructured.RemoveNestedField(before, "status")
+ }
+
+ // Mutate the original object.
+ if f != nil {
+ if err := mutate(f, key, obj); err != nil {
+ return OperationResultNone, err
+ }
+ }
+
+ // Convert the resource to unstructured to compare against our before copy.
+ after, err := runtime.DefaultUnstructuredConverter.ToUnstructured(obj)
+ if err != nil {
+ return OperationResultNone, err
+ }
+
+ // Attempt to extract the status from the resource for easier comparison later
+ afterStatus, hasAfterStatus, err := unstructured.NestedFieldCopy(after, "status")
+ if err != nil {
+ return OperationResultNone, err
+ }
+
+ // If the resource contains a status then remove it from the unstructured
+ // copy to avoid unnecessary patching later.
+ if hasAfterStatus {
+ unstructured.RemoveNestedField(after, "status")
+ }
+
+ result := OperationResultNone
+
+ if !reflect.DeepEqual(before, after) {
+ // Only issue a Patch if the before and after resources (minus status) differ
+ if err := c.Patch(ctx, obj, objPatch); err != nil {
+ return result, err
+ }
+ result = OperationResultUpdated
+ }
+
+ if (hasBeforeStatus || hasAfterStatus) && !reflect.DeepEqual(beforeStatus, afterStatus) {
+ // Only issue a Status Patch if the resource has a status and the beforeStatus
+ // and afterStatus copies differ
+ if result == OperationResultUpdated {
+ // If Status was replaced by Patch before, set it to afterStatus
+ objectAfterPatch, err := runtime.DefaultUnstructuredConverter.ToUnstructured(obj)
+ if err != nil {
+ return result, err
+ }
+ if err = unstructured.SetNestedField(objectAfterPatch, afterStatus, "status"); err != nil {
+ return result, err
+ }
+ // If Status was replaced by Patch before, restore patched structure to the obj
+ if err = runtime.DefaultUnstructuredConverter.FromUnstructured(objectAfterPatch, obj); err != nil {
+ return result, err
+ }
+ }
+ if err := c.Status().Patch(ctx, obj, statusPatch); err != nil {
+ return result, err
+ }
+ if result == OperationResultUpdated {
+ result = OperationResultUpdatedStatus
+ } else {
+ result = OperationResultUpdatedStatusOnly
+ }
+ }
+
+ return result, nil
+}
+
+// mutate wraps a MutateFn and applies validation to its result.
+func mutate(f MutateFn, key client.ObjectKey, obj client.Object) error {
+ if err := f(); err != nil {
+ return err
+ }
+ if newKey := client.ObjectKeyFromObject(obj); key != newKey {
+ return fmt.Errorf("MutateFn cannot mutate object name and/or object namespace")
+ }
+ return nil
+}
+
+// MutateFn is a function which mutates the existing object into it's desired state.
+type MutateFn func() error
+
+// AddFinalizer accepts an Object and adds the provided finalizer if not present.
+func AddFinalizer(o client.Object, finalizer string) {
+ f := o.GetFinalizers()
+ for _, e := range f {
+ if e == finalizer {
+ return
+ }
+ }
+ o.SetFinalizers(append(f, finalizer))
+}
+
+// RemoveFinalizer accepts an Object and removes the provided finalizer if present.
+func RemoveFinalizer(o client.Object, finalizer string) {
+ f := o.GetFinalizers()
+ for i := 0; i < len(f); i++ {
+ if f[i] == finalizer {
+ f = append(f[:i], f[i+1:]...)
+ i--
+ }
+ }
+ o.SetFinalizers(f)
+}
+
+// ContainsFinalizer checks an Object that the provided finalizer is present.
+func ContainsFinalizer(o client.Object, finalizer string) bool {
+ f := o.GetFinalizers()
+ for _, e := range f {
+ if e == finalizer {
+ return true
+ }
+ }
+ return false
+}
+
+// Object allows functions to work indistinctly with any resource that
+// implements both Object interfaces.
+//
+// Deprecated: Use client.Object instead.
+type Object = client.Object
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/controller/controllerutil/doc.go b/vendor/sigs.k8s.io/controller-runtime/pkg/controller/controllerutil/doc.go
new file mode 100644
index 000000000..ab386b29c
--- /dev/null
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/controller/controllerutil/doc.go
@@ -0,0 +1,20 @@
+/*
+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 controllerutil contains utility functions for working with and implementing Controllers.
+*/
+package controllerutil
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/controller/doc.go b/vendor/sigs.k8s.io/controller-runtime/pkg/controller/doc.go
new file mode 100644
index 000000000..667b14fdd
--- /dev/null
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/controller/doc.go
@@ -0,0 +1,25 @@
+/*
+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 controller provides types and functions for building Controllers. Controllers implement Kubernetes APIs.
+
+Creation
+
+To create a new Controller, first create a manager.Manager and pass it to the controller.New function.
+The Controller MUST be started by calling Manager.Start.
+*/
+package controller
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/conversion/conversion.go b/vendor/sigs.k8s.io/controller-runtime/pkg/conversion/conversion.go
new file mode 100644
index 000000000..da32ab48e
--- /dev/null
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/conversion/conversion.go
@@ -0,0 +1,40 @@
+/*
+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 conversion provides interface definitions that an API Type needs to
+implement for it to be supported by the generic conversion webhook handler
+defined under pkg/webhook/conversion.
+*/
+package conversion
+
+import "k8s.io/apimachinery/pkg/runtime"
+
+// Convertible defines capability of a type to convertible i.e. it can be converted to/from a hub type.
+type Convertible interface {
+ runtime.Object
+ ConvertTo(dst Hub) error
+ ConvertFrom(src Hub) error
+}
+
+// Hub marks that a given type is the hub type for conversion. This means that
+// all conversions will first convert to the hub type, then convert from the hub
+// type to the destination type. All types besides the hub type should implement
+// Convertible.
+type Hub interface {
+ runtime.Object
+ Hub()
+}
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/event/doc.go b/vendor/sigs.k8s.io/controller-runtime/pkg/event/doc.go
new file mode 100644
index 000000000..adba3bbc1
--- /dev/null
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/event/doc.go
@@ -0,0 +1,28 @@
+/*
+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 event contains the definitions for the Event types produced by source.Sources and transformed into
+reconcile.Requests by handler.EventHandler.
+
+You should rarely need to work with these directly -- instead, use Controller.Watch with
+source.Sources and handler.EventHandlers.
+
+Events generally contain both a full runtime.Object that caused the event, as well
+as a direct handle to that object's metadata. This saves a lot of typecasting in
+code that works with Events.
+*/
+package event
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/event/event.go b/vendor/sigs.k8s.io/controller-runtime/pkg/event/event.go
new file mode 100644
index 000000000..271b3c00f
--- /dev/null
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/event/event.go
@@ -0,0 +1,55 @@
+/*
+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 event
+
+import "sigs.k8s.io/controller-runtime/pkg/client"
+
+// CreateEvent is an event where a Kubernetes object was created. CreateEvent should be generated
+// by a source.Source and transformed into a reconcile.Request by an handler.EventHandler.
+type CreateEvent struct {
+ // Object is the object from the event
+ Object client.Object
+}
+
+// UpdateEvent is an event where a Kubernetes object was updated. UpdateEvent should be generated
+// by a source.Source and transformed into a reconcile.Request by an handler.EventHandler.
+type UpdateEvent struct {
+ // ObjectOld is the object from the event
+ ObjectOld client.Object
+
+ // ObjectNew is the object from the event
+ ObjectNew client.Object
+}
+
+// DeleteEvent is an event where a Kubernetes object was deleted. DeleteEvent should be generated
+// by a source.Source and transformed into a reconcile.Request by an handler.EventHandler.
+type DeleteEvent struct {
+ // Object is the object from the event
+ Object client.Object
+
+ // DeleteStateUnknown is true if the Delete event was missed but we identified the object
+ // as having been deleted.
+ DeleteStateUnknown bool
+}
+
+// GenericEvent is an event where the operation type is unknown (e.g. polling or event originating outside the cluster).
+// GenericEvent should be generated by a source.Source and transformed into a reconcile.Request by an
+// handler.EventHandler.
+type GenericEvent struct {
+ // Object is the object from the event
+ Object client.Object
+}
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/handler/doc.go b/vendor/sigs.k8s.io/controller-runtime/pkg/handler/doc.go
new file mode 100644
index 000000000..3b5b79048
--- /dev/null
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/handler/doc.go
@@ -0,0 +1,38 @@
+/*
+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 handler defines EventHandlers that enqueue reconcile.Requests in response to Create, Update, Deletion Events
+observed from Watching Kubernetes APIs. Users should provide a source.Source and handler.EventHandler to
+Controller.Watch in order to generate and enqueue reconcile.Request work items.
+
+Generally, following premade event handlers should be sufficient for most use cases:
+
+EventHandlers
+
+EnqueueRequestForObject - Enqueues a reconcile.Request containing the Name and Namespace of the object in the Event. This will
+cause the object that was the source of the Event (e.g. the created / deleted / updated object) to be
+reconciled.
+
+EnqueueRequestForOwner - Enqueues a reconcile.Request containing the Name and Namespace of the Owner of the object in the Event.
+This will cause owner of the object that was the source of the Event (e.g. the owner object that created the object)
+to be reconciled.
+
+EnqueueRequestsFromMapFunc - Enqueues reconcile.Requests resulting from a user provided transformation function run against the
+object in the Event. This will cause an arbitrary collection of objects (defined from a transformation of the
+source object) to be reconciled.
+*/
+package handler
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/handler/enqueue.go b/vendor/sigs.k8s.io/controller-runtime/pkg/handler/enqueue.go
new file mode 100644
index 000000000..e6d3a4eaa
--- /dev/null
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/handler/enqueue.go
@@ -0,0 +1,90 @@
+/*
+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 handler
+
+import (
+ "k8s.io/apimachinery/pkg/types"
+ "k8s.io/client-go/util/workqueue"
+ "sigs.k8s.io/controller-runtime/pkg/event"
+ logf "sigs.k8s.io/controller-runtime/pkg/internal/log"
+ "sigs.k8s.io/controller-runtime/pkg/reconcile"
+)
+
+var enqueueLog = logf.RuntimeLog.WithName("eventhandler").WithName("EnqueueRequestForObject")
+
+type empty struct{}
+
+var _ EventHandler = &EnqueueRequestForObject{}
+
+// EnqueueRequestForObject enqueues a Request containing the Name and Namespace of the object that is the source of the Event.
+// (e.g. the created / deleted / updated objects Name and Namespace). handler.EnqueueRequestForObject is used by almost all
+// Controllers that have associated Resources (e.g. CRDs) to reconcile the associated Resource.
+type EnqueueRequestForObject struct{}
+
+// Create implements EventHandler.
+func (e *EnqueueRequestForObject) Create(evt event.CreateEvent, q workqueue.RateLimitingInterface) {
+ if evt.Object == nil {
+ enqueueLog.Error(nil, "CreateEvent received with no metadata", "event", evt)
+ return
+ }
+ q.Add(reconcile.Request{NamespacedName: types.NamespacedName{
+ Name: evt.Object.GetName(),
+ Namespace: evt.Object.GetNamespace(),
+ }})
+}
+
+// Update implements EventHandler.
+func (e *EnqueueRequestForObject) Update(evt event.UpdateEvent, q workqueue.RateLimitingInterface) {
+ switch {
+ case evt.ObjectNew != nil:
+ q.Add(reconcile.Request{NamespacedName: types.NamespacedName{
+ Name: evt.ObjectNew.GetName(),
+ Namespace: evt.ObjectNew.GetNamespace(),
+ }})
+ case evt.ObjectOld != nil:
+ q.Add(reconcile.Request{NamespacedName: types.NamespacedName{
+ Name: evt.ObjectOld.GetName(),
+ Namespace: evt.ObjectOld.GetNamespace(),
+ }})
+ default:
+ enqueueLog.Error(nil, "UpdateEvent received with no metadata", "event", evt)
+ }
+}
+
+// Delete implements EventHandler.
+func (e *EnqueueRequestForObject) Delete(evt event.DeleteEvent, q workqueue.RateLimitingInterface) {
+ if evt.Object == nil {
+ enqueueLog.Error(nil, "DeleteEvent received with no metadata", "event", evt)
+ return
+ }
+ q.Add(reconcile.Request{NamespacedName: types.NamespacedName{
+ Name: evt.Object.GetName(),
+ Namespace: evt.Object.GetNamespace(),
+ }})
+}
+
+// Generic implements EventHandler.
+func (e *EnqueueRequestForObject) Generic(evt event.GenericEvent, q workqueue.RateLimitingInterface) {
+ if evt.Object == nil {
+ enqueueLog.Error(nil, "GenericEvent received with no metadata", "event", evt)
+ return
+ }
+ q.Add(reconcile.Request{NamespacedName: types.NamespacedName{
+ Name: evt.Object.GetName(),
+ Namespace: evt.Object.GetNamespace(),
+ }})
+}
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/handler/enqueue_mapped.go b/vendor/sigs.k8s.io/controller-runtime/pkg/handler/enqueue_mapped.go
new file mode 100644
index 000000000..17401b1fd
--- /dev/null
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/handler/enqueue_mapped.go
@@ -0,0 +1,97 @@
+/*
+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 handler
+
+import (
+ "k8s.io/client-go/util/workqueue"
+ "sigs.k8s.io/controller-runtime/pkg/client"
+ "sigs.k8s.io/controller-runtime/pkg/event"
+ "sigs.k8s.io/controller-runtime/pkg/reconcile"
+ "sigs.k8s.io/controller-runtime/pkg/runtime/inject"
+)
+
+// MapFunc is the signature required for enqueueing requests from a generic function.
+// This type is usually used with EnqueueRequestsFromMapFunc when registering an event handler.
+type MapFunc func(client.Object) []reconcile.Request
+
+// EnqueueRequestsFromMapFunc enqueues Requests by running a transformation function that outputs a collection
+// of reconcile.Requests on each Event. The reconcile.Requests may be for an arbitrary set of objects
+// defined by some user specified transformation of the source Event. (e.g. trigger Reconciler for a set of objects
+// in response to a cluster resize event caused by adding or deleting a Node)
+//
+// EnqueueRequestsFromMapFunc is frequently used to fan-out updates from one object to one or more other
+// objects of a differing type.
+//
+// For UpdateEvents which contain both a new and old object, the transformation function is run on both
+// objects and both sets of Requests are enqueue.
+func EnqueueRequestsFromMapFunc(fn MapFunc) EventHandler {
+ return &enqueueRequestsFromMapFunc{
+ toRequests: fn,
+ }
+}
+
+var _ EventHandler = &enqueueRequestsFromMapFunc{}
+
+type enqueueRequestsFromMapFunc struct {
+ // Mapper transforms the argument into a slice of keys to be reconciled
+ toRequests MapFunc
+}
+
+// Create implements EventHandler.
+func (e *enqueueRequestsFromMapFunc) Create(evt event.CreateEvent, q workqueue.RateLimitingInterface) {
+ reqs := map[reconcile.Request]empty{}
+ e.mapAndEnqueue(q, evt.Object, reqs)
+}
+
+// Update implements EventHandler.
+func (e *enqueueRequestsFromMapFunc) Update(evt event.UpdateEvent, q workqueue.RateLimitingInterface) {
+ reqs := map[reconcile.Request]empty{}
+ e.mapAndEnqueue(q, evt.ObjectOld, reqs)
+ e.mapAndEnqueue(q, evt.ObjectNew, reqs)
+}
+
+// Delete implements EventHandler.
+func (e *enqueueRequestsFromMapFunc) Delete(evt event.DeleteEvent, q workqueue.RateLimitingInterface) {
+ reqs := map[reconcile.Request]empty{}
+ e.mapAndEnqueue(q, evt.Object, reqs)
+}
+
+// Generic implements EventHandler.
+func (e *enqueueRequestsFromMapFunc) Generic(evt event.GenericEvent, q workqueue.RateLimitingInterface) {
+ reqs := map[reconcile.Request]empty{}
+ e.mapAndEnqueue(q, evt.Object, reqs)
+}
+
+func (e *enqueueRequestsFromMapFunc) mapAndEnqueue(q workqueue.RateLimitingInterface, object client.Object, reqs map[reconcile.Request]empty) {
+ for _, req := range e.toRequests(object) {
+ _, ok := reqs[req]
+ if !ok {
+ q.Add(req)
+ reqs[req] = empty{}
+ }
+ }
+}
+
+// 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)
+}
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/handler/enqueue_owner.go b/vendor/sigs.k8s.io/controller-runtime/pkg/handler/enqueue_owner.go
new file mode 100644
index 000000000..63699893f
--- /dev/null
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/handler/enqueue_owner.go
@@ -0,0 +1,189 @@
+/*
+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 handler
+
+import (
+ "fmt"
+
+ "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/types"
+ "k8s.io/client-go/util/workqueue"
+ "sigs.k8s.io/controller-runtime/pkg/event"
+ logf "sigs.k8s.io/controller-runtime/pkg/internal/log"
+ "sigs.k8s.io/controller-runtime/pkg/reconcile"
+ "sigs.k8s.io/controller-runtime/pkg/runtime/inject"
+)
+
+var _ EventHandler = &EnqueueRequestForOwner{}
+
+var log = logf.RuntimeLog.WithName("eventhandler").WithName("EnqueueRequestForOwner")
+
+// EnqueueRequestForOwner enqueues Requests for the Owners of an object. E.g. the object that created
+// the object that was the source of the Event.
+//
+// If a ReplicaSet creates Pods, users may reconcile the ReplicaSet in response to Pod Events using:
+//
+// - a source.Kind Source with Type of Pod.
+//
+// - a handler.EnqueueRequestForOwner EventHandler with an OwnerType of ReplicaSet and IsController set to 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 schema.GroupKind
+
+ // mapper maps GroupVersionKinds to Resources
+ mapper meta.RESTMapper
+}
+
+// Create implements EventHandler.
+func (e *EnqueueRequestForOwner) Create(evt event.CreateEvent, q workqueue.RateLimitingInterface) {
+ reqs := map[reconcile.Request]empty{}
+ e.getOwnerReconcileRequest(evt.Object, reqs)
+ for req := range reqs {
+ q.Add(req)
+ }
+}
+
+// Update implements EventHandler.
+func (e *EnqueueRequestForOwner) Update(evt event.UpdateEvent, q workqueue.RateLimitingInterface) {
+ reqs := map[reconcile.Request]empty{}
+ e.getOwnerReconcileRequest(evt.ObjectOld, reqs)
+ e.getOwnerReconcileRequest(evt.ObjectNew, reqs)
+ for req := range reqs {
+ q.Add(req)
+ }
+}
+
+// Delete implements EventHandler.
+func (e *EnqueueRequestForOwner) Delete(evt event.DeleteEvent, q workqueue.RateLimitingInterface) {
+ reqs := map[reconcile.Request]empty{}
+ e.getOwnerReconcileRequest(evt.Object, reqs)
+ for req := range reqs {
+ q.Add(req)
+ }
+}
+
+// Generic implements EventHandler.
+func (e *EnqueueRequestForOwner) Generic(evt event.GenericEvent, q workqueue.RateLimitingInterface) {
+ reqs := map[reconcile.Request]empty{}
+ e.getOwnerReconcileRequest(evt.Object, reqs)
+ for req := range reqs {
+ q.Add(req)
+ }
+}
+
+// parseOwnerTypeGroupKind parses the OwnerType into a Group and Kind and caches the result. Returns false
+// if the OwnerType could not be parsed using the scheme.
+func (e *EnqueueRequestForOwner) parseOwnerTypeGroupKind(scheme *runtime.Scheme) error {
+ // Get the kinds of the type
+ kinds, _, err := scheme.ObjectKinds(e.OwnerType)
+ if err != nil {
+ log.Error(err, "Could not get ObjectKinds for OwnerType", "owner type", fmt.Sprintf("%T", e.OwnerType))
+ return err
+ }
+ // Expect only 1 kind. If there is more than one kind this is probably an edge case such as ListOptions.
+ if len(kinds) != 1 {
+ 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)
+ return err
+ }
+ // Cache the Group and Kind for the OwnerType
+ e.groupKind = schema.GroupKind{Group: kinds[0].Group, Kind: kinds[0].Kind}
+ return nil
+}
+
+// getOwnerReconcileRequest looks at object and builds a map of reconcile.Request to reconcile
+// owners of object that match e.OwnerType.
+func (e *EnqueueRequestForOwner) getOwnerReconcileRequest(object metav1.Object, result map[reconcile.Request]empty) {
+ // Iterate through the OwnerReferences looking for a match on Group and Kind against what was requested
+ // by the user
+ for _, ref := range e.getOwnersReferences(object) {
+ // Parse the Group out of the OwnerReference to compare it to what was parsed out of the requested OwnerType
+ refGV, err := schema.ParseGroupVersion(ref.APIVersion)
+ if err != nil {
+ log.Error(err, "Could not parse OwnerReference APIVersion",
+ "api version", ref.APIVersion)
+ return
+ }
+
+ // Compare the OwnerReference Group and Kind against the OwnerType Group and Kind specified by the user.
+ // If the two match, create a Request for the objected referred to by
+ // the OwnerReference. Use the Name from the OwnerReference and the Namespace from the
+ // object in the event.
+ if ref.Kind == e.groupKind.Kind && refGV.Group == e.groupKind.Group {
+ // Match found - add a Request for the object referred to in the OwnerReference
+ request := reconcile.Request{NamespacedName: types.NamespacedName{
+ Name: ref.Name,
+ }}
+
+ // if owner is not namespaced then we should set the namespace to the empty
+ mapping, err := e.mapper.RESTMapping(e.groupKind, refGV.Version)
+ if err != nil {
+ log.Error(err, "Could not retrieve rest mapping", "kind", e.groupKind)
+ return
+ }
+ if mapping.Scope.Name() != meta.RESTScopeNameRoot {
+ request.Namespace = object.GetNamespace()
+ }
+
+ result[request] = empty{}
+ }
+ }
+}
+
+// getOwnersReferences returns the OwnerReferences for an object as specified by the EnqueueRequestForOwner
+// - if IsController is true: only take the Controller OwnerReference (if found)
+// - if IsController is false: take all OwnerReferences.
+func (e *EnqueueRequestForOwner) getOwnersReferences(object metav1.Object) []metav1.OwnerReference {
+ if object == nil {
+ return nil
+ }
+
+ // If not filtered as Controller only, then use all the OwnerReferences
+ if !e.IsController {
+ return object.GetOwnerReferences()
+ }
+ // If filtered to a Controller, only take the Controller OwnerReference
+ if ownerRef := metav1.GetControllerOf(object); ownerRef != nil {
+ return []metav1.OwnerReference{*ownerRef}
+ }
+ // No Controller OwnerReference found
+ 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
+}
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/handler/eventhandler.go b/vendor/sigs.k8s.io/controller-runtime/pkg/handler/eventhandler.go
new file mode 100644
index 000000000..8652d22d7
--- /dev/null
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/handler/eventhandler.go
@@ -0,0 +1,104 @@
+/*
+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 handler
+
+import (
+ "k8s.io/client-go/util/workqueue"
+ "sigs.k8s.io/controller-runtime/pkg/event"
+)
+
+// EventHandler enqueues reconcile.Requests in response to events (e.g. Pod Create). EventHandlers map an Event
+// for one object to trigger Reconciles for either the same object or different objects - e.g. if there is an
+// Event for object with type Foo (using source.KindSource) then reconcile one or more object(s) with type Bar.
+//
+// Identical reconcile.Requests will be batched together through the queuing mechanism before reconcile is called.
+//
+// * Use EnqueueRequestForObject to reconcile the object the event is for
+// - do this for events for the type the Controller Reconciles. (e.g. Deployment for a Deployment Controller)
+//
+// * Use EnqueueRequestForOwner to reconcile the owner of the object the event is for
+// - do this for events for the types the Controller creates. (e.g. ReplicaSets created by a Deployment Controller)
+//
+// * Use EnqueueRequestsFromMapFunc to transform an event for an object to a reconcile of an object
+// of a different type - do this for events for types the Controller may be interested in, but doesn't create.
+// (e.g. If Foo responds to cluster size events, map Node events to Foo objects.)
+//
+// Unless you are implementing your own EventHandler, you can ignore the functions on the EventHandler interface.
+// Most users shouldn't need to implement their own EventHandler.
+type EventHandler interface {
+ // Create is called in response to an create event - e.g. Pod Creation.
+ Create(event.CreateEvent, workqueue.RateLimitingInterface)
+
+ // Update is called in response to an update event - e.g. Pod Updated.
+ Update(event.UpdateEvent, workqueue.RateLimitingInterface)
+
+ // Delete is called in response to a delete event - e.g. Pod Deleted.
+ Delete(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
+ // external trigger request - e.g. reconcile Autoscaling, or a Webhook.
+ Generic(event.GenericEvent, workqueue.RateLimitingInterface)
+}
+
+var _ EventHandler = Funcs{}
+
+// Funcs implements EventHandler.
+type Funcs struct {
+ // Create is called in response to an add event. Defaults to no-op.
+ // RateLimitingInterface is used to enqueue reconcile.Requests.
+ CreateFunc func(event.CreateEvent, workqueue.RateLimitingInterface)
+
+ // Update is called in response to an update event. Defaults to no-op.
+ // RateLimitingInterface is used to enqueue reconcile.Requests.
+ UpdateFunc func(event.UpdateEvent, workqueue.RateLimitingInterface)
+
+ // Delete is called in response to a delete event. Defaults to no-op.
+ // RateLimitingInterface is used to enqueue reconcile.Requests.
+ DeleteFunc func(event.DeleteEvent, workqueue.RateLimitingInterface)
+
+ // GenericFunc is called in response to a generic event. Defaults to no-op.
+ // RateLimitingInterface is used to enqueue reconcile.Requests.
+ GenericFunc func(event.GenericEvent, workqueue.RateLimitingInterface)
+}
+
+// Create implements EventHandler.
+func (h Funcs) Create(e event.CreateEvent, q workqueue.RateLimitingInterface) {
+ if h.CreateFunc != nil {
+ h.CreateFunc(e, q)
+ }
+}
+
+// Delete implements EventHandler.
+func (h Funcs) Delete(e event.DeleteEvent, q workqueue.RateLimitingInterface) {
+ if h.DeleteFunc != nil {
+ h.DeleteFunc(e, q)
+ }
+}
+
+// Update implements EventHandler.
+func (h Funcs) Update(e event.UpdateEvent, q workqueue.RateLimitingInterface) {
+ if h.UpdateFunc != nil {
+ h.UpdateFunc(e, q)
+ }
+}
+
+// Generic implements EventHandler.
+func (h Funcs) Generic(e event.GenericEvent, q workqueue.RateLimitingInterface) {
+ if h.GenericFunc != nil {
+ h.GenericFunc(e, q)
+ }
+}
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/healthz/doc.go b/vendor/sigs.k8s.io/controller-runtime/pkg/healthz/doc.go
new file mode 100644
index 000000000..9827eeafe
--- /dev/null
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/healthz/doc.go
@@ -0,0 +1,32 @@
+/*
+Copyright 2014 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 healthz contains helpers from supporting liveness and readiness endpoints.
+// (often referred to as healthz and readyz, respectively).
+//
+// This package draws heavily from the apiserver's healthz package
+// ( https://github.com/kubernetes/apiserver/tree/master/pkg/server/healthz )
+// but has some changes to bring it in line with controller-runtime's style.
+//
+// The main entrypoint is the Handler -- this serves both aggregated health status
+// and individual health check endpoints.
+package healthz
+
+import (
+ logf "sigs.k8s.io/controller-runtime/pkg/internal/log"
+)
+
+var log = logf.RuntimeLog.WithName("healthz")
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/healthz/healthz.go b/vendor/sigs.k8s.io/controller-runtime/pkg/healthz/healthz.go
new file mode 100644
index 000000000..bd1cc151a
--- /dev/null
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/healthz/healthz.go
@@ -0,0 +1,206 @@
+/*
+Copyright 2014 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 healthz
+
+import (
+ "fmt"
+ "net/http"
+ "path"
+ "sort"
+ "strings"
+
+ "k8s.io/apimachinery/pkg/util/sets"
+)
+
+// Handler is an http.Handler that aggregates the results of the given
+// checkers to the root path, and supports calling individual checkers on
+// subpaths of the name of the checker.
+//
+// Adding checks on the fly is *not* threadsafe -- use a wrapper.
+type Handler struct {
+ Checks map[string]Checker
+}
+
+// checkStatus holds the output of a particular check.
+type checkStatus struct {
+ name string
+ healthy bool
+ excluded bool
+}
+
+func (h *Handler) serveAggregated(resp http.ResponseWriter, req *http.Request) {
+ failed := false
+ excluded := getExcludedChecks(req)
+
+ parts := make([]checkStatus, 0, len(h.Checks))
+
+ // calculate the results...
+ for checkName, check := range h.Checks {
+ // no-op the check if we've specified we want to exclude the check
+ if excluded.Has(checkName) {
+ excluded.Delete(checkName)
+ parts = append(parts, checkStatus{name: checkName, healthy: true, excluded: true})
+ continue
+ }
+ if err := check(req); err != nil {
+ log.V(1).Info("healthz check failed", "checker", checkName, "error", err)
+ parts = append(parts, checkStatus{name: checkName, healthy: false})
+ failed = true
+ } else {
+ parts = append(parts, checkStatus{name: checkName, healthy: true})
+ }
+ }
+
+ // ...default a check if none is present...
+ if len(h.Checks) == 0 {
+ parts = append(parts, checkStatus{name: "ping", healthy: true})
+ }
+
+ for _, c := range excluded.List() {
+ log.V(1).Info("cannot exclude health check, no matches for it", "checker", c)
+ }
+
+ // ...sort to be consistent...
+ sort.Slice(parts, func(i, j int) bool { return parts[i].name < parts[j].name })
+
+ // ...and write out the result
+ // TODO(directxman12): this should also accept a request for JSON content (via a accept header)
+ _, forceVerbose := req.URL.Query()["verbose"]
+ writeStatusesAsText(resp, parts, excluded, failed, forceVerbose)
+}
+
+// writeStatusAsText writes out the given check statuses in some semi-arbitrary
+// bespoke text format that we copied from Kubernetes. unknownExcludes lists
+// any checks that the user requested to have excluded, but weren't actually
+// known checks. writeStatusAsText is always verbose on failure, and can be
+// forced to be verbose on success using the given argument.
+func writeStatusesAsText(resp http.ResponseWriter, parts []checkStatus, unknownExcludes sets.String, failed, forceVerbose bool) {
+ resp.Header().Set("Content-Type", "text/plain; charset=utf-8")
+ resp.Header().Set("X-Content-Type-Options", "nosniff")
+
+ // always write status code first
+ if failed {
+ resp.WriteHeader(http.StatusInternalServerError)
+ } else {
+ resp.WriteHeader(http.StatusOK)
+ }
+
+ // shortcut for easy non-verbose success
+ if !failed && !forceVerbose {
+ fmt.Fprint(resp, "ok")
+ return
+ }
+
+ // we're always verbose on failure, so from this point on we're guaranteed to be verbose
+
+ for _, checkOut := range parts {
+ switch {
+ case checkOut.excluded:
+ fmt.Fprintf(resp, "[+]%s excluded: ok\n", checkOut.name)
+ case checkOut.healthy:
+ fmt.Fprintf(resp, "[+]%s ok\n", checkOut.name)
+ default:
+ // don't include the error since this endpoint is public. If someone wants more detail
+ // they should have explicit permission to the detailed checks.
+ fmt.Fprintf(resp, "[-]%s failed: reason withheld\n", checkOut.name)
+ }
+ }
+
+ if unknownExcludes.Len() > 0 {
+ fmt.Fprintf(resp, "warn: some health checks cannot be excluded: no matches for %s\n", formatQuoted(unknownExcludes.List()...))
+ }
+
+ if failed {
+ log.Info("healthz check failed", "statuses", parts)
+ fmt.Fprintf(resp, "healthz check failed\n")
+ } else {
+ fmt.Fprint(resp, "healthz check passed\n")
+ }
+}
+
+func (h *Handler) ServeHTTP(resp http.ResponseWriter, req *http.Request) {
+ // clean up the request (duplicating the internal logic of http.ServeMux a bit)
+ // clean up the path a bit
+ reqPath := req.URL.Path
+ if reqPath == "" || reqPath[0] != '/' {
+ reqPath = "/" + reqPath
+ }
+ // path.Clean removes the trailing slash except for root for us
+ // (which is fine, since we're only serving one layer of sub-paths)
+ reqPath = path.Clean(reqPath)
+
+ // either serve the root endpoint...
+ if reqPath == "/" {
+ h.serveAggregated(resp, req)
+ return
+ }
+
+ // ...the default check (if nothing else is present)...
+ if len(h.Checks) == 0 && reqPath[1:] == "ping" {
+ CheckHandler{Checker: Ping}.ServeHTTP(resp, req)
+ return
+ }
+
+ // ...or an individual checker
+ checkName := reqPath[1:] // ignore the leading slash
+ checker, known := h.Checks[checkName]
+ if !known {
+ http.NotFoundHandler().ServeHTTP(resp, req)
+ return
+ }
+
+ CheckHandler{Checker: checker}.ServeHTTP(resp, req)
+}
+
+// CheckHandler is an http.Handler that serves a health check endpoint at the root path,
+// based on its checker.
+type CheckHandler struct {
+ Checker
+}
+
+func (h CheckHandler) ServeHTTP(resp http.ResponseWriter, req *http.Request) {
+ if err := h.Checker(req); err != nil {
+ http.Error(resp, fmt.Sprintf("internal server error: %v", err), http.StatusInternalServerError)
+ } else {
+ fmt.Fprint(resp, "ok")
+ }
+}
+
+// Checker knows how to perform a health check.
+type Checker func(req *http.Request) error
+
+// Ping returns true automatically when checked.
+var Ping Checker = func(_ *http.Request) error { return nil }
+
+// getExcludedChecks extracts the health check names to be excluded from the query param.
+func getExcludedChecks(r *http.Request) sets.String {
+ checks, found := r.URL.Query()["exclude"]
+ if found {
+ return sets.NewString(checks...)
+ }
+ return sets.NewString()
+}
+
+// formatQuoted returns a formatted string of the health check names,
+// preserving the order passed in.
+func formatQuoted(names ...string) string {
+ quoted := make([]string, 0, len(names))
+ for _, name := range names {
+ quoted = append(quoted, fmt.Sprintf("%q", name))
+ }
+ return strings.Join(quoted, ",")
+}
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/internal/controller/controller.go b/vendor/sigs.k8s.io/controller-runtime/pkg/internal/controller/controller.go
new file mode 100644
index 000000000..1f4712d8b
--- /dev/null
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/internal/controller/controller.go
@@ -0,0 +1,351 @@
+/*
+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 controller
+
+import (
+ "context"
+ "errors"
+ "fmt"
+ "sync"
+ "time"
+
+ "github.com/go-logr/logr"
+ utilruntime "k8s.io/apimachinery/pkg/util/runtime"
+ "k8s.io/client-go/util/workqueue"
+ "sigs.k8s.io/controller-runtime/pkg/handler"
+ ctrlmetrics "sigs.k8s.io/controller-runtime/pkg/internal/controller/metrics"
+ logf "sigs.k8s.io/controller-runtime/pkg/log"
+ "sigs.k8s.io/controller-runtime/pkg/predicate"
+ "sigs.k8s.io/controller-runtime/pkg/reconcile"
+ "sigs.k8s.io/controller-runtime/pkg/runtime/inject"
+ "sigs.k8s.io/controller-runtime/pkg/source"
+)
+
+var _ inject.Injector = &Controller{}
+
+// Controller implements controller.Controller.
+type Controller struct {
+ // Name is used to uniquely identify a Controller in tracing, logging and monitoring. Name is required.
+ Name string
+
+ // MaxConcurrentReconciles is the maximum number of concurrent Reconciles which can be run. Defaults to 1.
+ MaxConcurrentReconciles int
+
+ // Reconciler is a function that can be called at any time with the Name / Namespace of an object and
+ // ensures that the state of the system matches the state specified in the object.
+ // Defaults to the DefaultReconcileFunc.
+ Do reconcile.Reconciler
+
+ // MakeQueue constructs the queue for this controller once the controller is ready to start.
+ // This exists because the standard Kubernetes workqueues start themselves immediately, which
+ // leads to goroutine leaks if something calls controller.New repeatedly.
+ MakeQueue func() workqueue.RateLimitingInterface
+
+ // Queue is an listeningQueue that listens for events from Informers and adds object keys to
+ // the Queue for processing
+ 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 sync.Mutex
+
+ // Started is true if the Controller has been Started
+ Started bool
+
+ // ctx is the context that was passed to Start() and used when starting watches.
+ //
+ // According to the docs, contexts should not be stored in a struct: https://golang.org/pkg/context,
+ // while we usually always strive to follow best practices, we consider this a legacy case and it should
+ // undergo a major refactoring and redesign to allow for context to not be stored in a struct.
+ ctx context.Context
+
+ // CacheSyncTimeout refers to the time limit set on waiting for cache to sync
+ // Defaults to 2 minutes if not set.
+ CacheSyncTimeout time.Duration
+
+ // startWatches maintains a list of sources, handlers, and predicates to start when the controller is started.
+ startWatches []watchDescription
+
+ // Log is used to log messages to users during reconciliation, or for example when a watch is started.
+ Log logr.Logger
+
+ // RecoverPanic indicates whether the panic caused by reconcile should be recovered.
+ RecoverPanic bool
+}
+
+// watchDescription contains all the information necessary to start a watch.
+type watchDescription struct {
+ src source.Source
+ handler handler.EventHandler
+ predicates []predicate.Predicate
+}
+
+// Reconcile implements reconcile.Reconciler.
+func (c *Controller) Reconcile(ctx context.Context, req reconcile.Request) (_ reconcile.Result, err error) {
+ if c.RecoverPanic {
+ defer func() {
+ if r := recover(); r != nil {
+ for _, fn := range utilruntime.PanicHandlers {
+ fn(r)
+ }
+ err = fmt.Errorf("panic: %v [recovered]", r)
+ }
+ }()
+ }
+ log := c.Log.WithValues("name", req.Name, "namespace", req.Namespace)
+ ctx = logf.IntoContext(ctx, log)
+ return c.Do.Reconcile(ctx, req)
+}
+
+// Watch implements controller.Controller.
+func (c *Controller) Watch(src source.Source, evthdler handler.EventHandler, prct ...predicate.Predicate) error {
+ c.mu.Lock()
+ 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.
+ //
+ // These watches are going to be held on the controller struct until the manager or user calls Start(...).
+ if !c.Started {
+ c.startWatches = append(c.startWatches, watchDescription{src: src, handler: evthdler, predicates: prct})
+ return nil
+ }
+
+ c.Log.Info("Starting EventSource", "source", src)
+ return src.Start(c.ctx, evthdler, c.Queue, prct...)
+}
+
+// Start implements controller.Controller.
+func (c *Controller) Start(ctx context.Context) error {
+ // use an IIFE to get proper lock handling
+ // but lock outside to get proper handling of the queue shutdown
+ c.mu.Lock()
+ if c.Started {
+ return errors.New("controller was started more than once. This is likely to be caused by being added to a manager multiple times")
+ }
+
+ c.initMetrics()
+
+ // Set the internal context.
+ c.ctx = ctx
+
+ c.Queue = c.MakeQueue()
+ go func() {
+ <-ctx.Done()
+ c.Queue.ShutDown()
+ }()
+
+ wg := &sync.WaitGroup{}
+ err := func() error {
+ defer c.mu.Unlock()
+
+ // TODO(pwittrock): Reconsider HandleCrash
+ defer utilruntime.HandleCrash()
+
+ // NB(directxman12): launch the sources *before* trying to wait for the
+ // caches to sync so that they have a chance to register their intendeded
+ // caches.
+ for _, watch := range c.startWatches {
+ c.Log.Info("Starting EventSource", "source", fmt.Sprintf("%s", watch.src))
+
+ if err := watch.src.Start(ctx, watch.handler, c.Queue, watch.predicates...); err != nil {
+ return err
+ }
+ }
+
+ // Start the SharedIndexInformer factories to begin populating the SharedIndexInformer caches
+ c.Log.Info("Starting Controller")
+
+ for _, watch := range c.startWatches {
+ syncingSource, ok := watch.src.(source.SyncingSource)
+ if !ok {
+ continue
+ }
+
+ if err := func() error {
+ // use a context with timeout for launching sources and syncing caches.
+ sourceStartCtx, cancel := context.WithTimeout(ctx, c.CacheSyncTimeout)
+ defer cancel()
+
+ // WaitForSync waits for a definitive timeout, and returns if there
+ // is an error or a timeout
+ if err := syncingSource.WaitForSync(sourceStartCtx); err != nil {
+ err := fmt.Errorf("failed to wait for %s caches to sync: %w", c.Name, err)
+ c.Log.Error(err, "Could not wait for Cache to sync")
+ return err
+ }
+
+ return nil
+ }(); err != nil {
+ return err
+ }
+ }
+
+ // All the watches have been started, we can reset the local slice.
+ //
+ // We should never hold watches more than necessary, each watch source can hold a backing cache,
+ // which won't be garbage collected if we hold a reference to it.
+ c.startWatches = nil
+
+ // Launch workers to process resources
+ c.Log.Info("Starting workers", "worker count", c.MaxConcurrentReconciles)
+ wg.Add(c.MaxConcurrentReconciles)
+ for i := 0; i < c.MaxConcurrentReconciles; i++ {
+ go func() {
+ defer wg.Done()
+ // Run a worker thread that just dequeues items, processes them, and marks them done.
+ // It enforces that the reconcileHandler is never invoked concurrently with the same object.
+ for c.processNextWorkItem(ctx) {
+ }
+ }()
+ }
+
+ c.Started = true
+ return nil
+ }()
+ if err != nil {
+ return err
+ }
+
+ <-ctx.Done()
+ c.Log.Info("Shutdown signal received, waiting for all workers to finish")
+ wg.Wait()
+ c.Log.Info("All workers finished")
+ return nil
+}
+
+// processNextWorkItem will read a single work item off the workqueue and
+// attempt to process it, by calling the reconcileHandler.
+func (c *Controller) processNextWorkItem(ctx context.Context) bool {
+ obj, shutdown := c.Queue.Get()
+ if shutdown {
+ // Stop working
+ return false
+ }
+
+ // We call Done here so the workqueue knows we have finished
+ // processing this item. We also must remember to call Forget if we
+ // do not want this work item being re-queued. For example, we do
+ // not call Forget if a transient error occurs, instead the item is
+ // put back on the workqueue and attempted again after a back-off
+ // period.
+ defer c.Queue.Done(obj)
+
+ ctrlmetrics.ActiveWorkers.WithLabelValues(c.Name).Add(1)
+ defer ctrlmetrics.ActiveWorkers.WithLabelValues(c.Name).Add(-1)
+
+ c.reconcileHandler(ctx, obj)
+ return true
+}
+
+const (
+ labelError = "error"
+ labelRequeueAfter = "requeue_after"
+ labelRequeue = "requeue"
+ labelSuccess = "success"
+)
+
+func (c *Controller) initMetrics() {
+ ctrlmetrics.ActiveWorkers.WithLabelValues(c.Name).Set(0)
+ ctrlmetrics.ReconcileErrors.WithLabelValues(c.Name).Add(0)
+ ctrlmetrics.ReconcileTotal.WithLabelValues(c.Name, labelError).Add(0)
+ ctrlmetrics.ReconcileTotal.WithLabelValues(c.Name, labelRequeueAfter).Add(0)
+ ctrlmetrics.ReconcileTotal.WithLabelValues(c.Name, labelRequeue).Add(0)
+ ctrlmetrics.ReconcileTotal.WithLabelValues(c.Name, labelSuccess).Add(0)
+ ctrlmetrics.WorkerCount.WithLabelValues(c.Name).Set(float64(c.MaxConcurrentReconciles))
+}
+
+func (c *Controller) reconcileHandler(ctx context.Context, obj interface{}) {
+ // Update metrics after processing each item
+ reconcileStartTS := time.Now()
+ defer func() {
+ c.updateMetrics(time.Since(reconcileStartTS))
+ }()
+
+ // Make sure that the the object is a valid request.
+ req, ok := obj.(reconcile.Request)
+ if !ok {
+ // As the item in the workqueue is actually invalid, we call
+ // Forget here else we'd go into a loop of attempting to
+ // process a work item that is invalid.
+ c.Queue.Forget(obj)
+ c.Log.Error(nil, "Queue item was not a Request", "type", fmt.Sprintf("%T", obj), "value", obj)
+ // Return true, don't take a break
+ return
+ }
+
+ log := c.Log.WithValues("name", req.Name, "namespace", req.Namespace)
+ ctx = logf.IntoContext(ctx, log)
+
+ // RunInformersAndControllers the syncHandler, passing it the Namespace/Name string of the
+ // resource to be synced.
+ result, err := c.Reconcile(ctx, req)
+ switch {
+ case err != nil:
+ c.Queue.AddRateLimited(req)
+ ctrlmetrics.ReconcileErrors.WithLabelValues(c.Name).Inc()
+ ctrlmetrics.ReconcileTotal.WithLabelValues(c.Name, labelError).Inc()
+ log.Error(err, "Reconciler error")
+ case result.RequeueAfter > 0:
+ // The result.RequeueAfter request will be lost, if it is returned
+ // along with a non-nil error. But this is intended as
+ // We need to drive to stable reconcile loops before queuing due
+ // to result.RequestAfter
+ c.Queue.Forget(obj)
+ c.Queue.AddAfter(req, result.RequeueAfter)
+ ctrlmetrics.ReconcileTotal.WithLabelValues(c.Name, labelRequeueAfter).Inc()
+ case result.Requeue:
+ c.Queue.AddRateLimited(req)
+ ctrlmetrics.ReconcileTotal.WithLabelValues(c.Name, labelRequeue).Inc()
+ default:
+ // Finally, if no error occurs we Forget this item so it does not
+ // get queued again until another change happens.
+ c.Queue.Forget(obj)
+ ctrlmetrics.ReconcileTotal.WithLabelValues(c.Name, labelSuccess).Inc()
+ }
+}
+
+// GetLogger returns this controller's logger.
+func (c *Controller) GetLogger() logr.Logger {
+ return c.Log
+}
+
+// InjectFunc implement SetFields.Injector.
+func (c *Controller) InjectFunc(f inject.Func) error {
+ c.SetFields = f
+ return nil
+}
+
+// updateMetrics updates prometheus metrics within the controller.
+func (c *Controller) updateMetrics(reconcileTime time.Duration) {
+ ctrlmetrics.ReconcileTime.WithLabelValues(c.Name).Observe(reconcileTime.Seconds())
+}
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/internal/controller/metrics/metrics.go b/vendor/sigs.k8s.io/controller-runtime/pkg/internal/controller/metrics/metrics.go
new file mode 100644
index 000000000..baec66927
--- /dev/null
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/internal/controller/metrics/metrics.go
@@ -0,0 +1,78 @@
+/*
+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 metrics
+
+import (
+ "github.com/prometheus/client_golang/prometheus"
+ "github.com/prometheus/client_golang/prometheus/collectors"
+ "sigs.k8s.io/controller-runtime/pkg/metrics"
+)
+
+var (
+ // ReconcileTotal is a prometheus counter metrics which holds the total
+ // number of reconciliations per controller. It has two labels. controller label refers
+ // to the controller name and result label refers to the reconcile result i.e
+ // success, error, requeue, requeue_after.
+ ReconcileTotal = prometheus.NewCounterVec(prometheus.CounterOpts{
+ Name: "controller_runtime_reconcile_total",
+ Help: "Total number of reconciliations per controller",
+ }, []string{"controller", "result"})
+
+ // ReconcileErrors is a prometheus counter metrics which holds the total
+ // number of errors from the Reconciler.
+ ReconcileErrors = prometheus.NewCounterVec(prometheus.CounterOpts{
+ Name: "controller_runtime_reconcile_errors_total",
+ Help: "Total number of reconciliation errors per controller",
+ }, []string{"controller"})
+
+ // ReconcileTime is a prometheus metric which keeps track of the duration
+ // of reconciliations.
+ ReconcileTime = prometheus.NewHistogramVec(prometheus.HistogramOpts{
+ Name: "controller_runtime_reconcile_time_seconds",
+ Help: "Length of time per reconciliation per controller",
+ Buckets: []float64{0.005, 0.01, 0.025, 0.05, 0.1, 0.15, 0.2, 0.25, 0.3, 0.35, 0.4, 0.45, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0,
+ 1.25, 1.5, 1.75, 2.0, 2.5, 3.0, 3.5, 4.0, 4.5, 5, 6, 7, 8, 9, 10, 15, 20, 25, 30, 40, 50, 60},
+ }, []string{"controller"})
+
+ // WorkerCount is a prometheus metric which holds the number of
+ // concurrent reconciles per controller.
+ WorkerCount = prometheus.NewGaugeVec(prometheus.GaugeOpts{
+ Name: "controller_runtime_max_concurrent_reconciles",
+ Help: "Maximum number of concurrent reconciles per controller",
+ }, []string{"controller"})
+
+ // ActiveWorkers is a prometheus metric which holds the number
+ // of active workers per controller.
+ ActiveWorkers = prometheus.NewGaugeVec(prometheus.GaugeOpts{
+ Name: "controller_runtime_active_workers",
+ Help: "Number of currently used workers per controller",
+ }, []string{"controller"})
+)
+
+func init() {
+ metrics.Registry.MustRegister(
+ ReconcileTotal,
+ ReconcileErrors,
+ ReconcileTime,
+ WorkerCount,
+ ActiveWorkers,
+ // expose process metrics like CPU, Memory, file descriptor usage etc.
+ collectors.NewProcessCollector(collectors.ProcessCollectorOpts{}),
+ // expose Go runtime metrics like GC stats, memory stats etc.
+ collectors.NewGoCollector(),
+ )
+}
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/internal/log/log.go b/vendor/sigs.k8s.io/controller-runtime/pkg/internal/log/log.go
new file mode 100644
index 000000000..d91a0ca50
--- /dev/null
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/internal/log/log.go
@@ -0,0 +1,32 @@
+/*
+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 log
+
+import (
+ "github.com/go-logr/logr"
+
+ "sigs.k8s.io/controller-runtime/pkg/log"
+)
+
+var (
+ // RuntimeLog is a base parent logger for use inside controller-runtime.
+ RuntimeLog logr.Logger
+)
+
+func init() {
+ RuntimeLog = log.Log.WithName("controller-runtime")
+}
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/internal/objectutil/objectutil.go b/vendor/sigs.k8s.io/controller-runtime/pkg/internal/objectutil/objectutil.go
new file mode 100644
index 000000000..7057f3dbe
--- /dev/null
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/internal/objectutil/objectutil.go
@@ -0,0 +1,78 @@
+/*
+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
+}
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/internal/recorder/recorder.go b/vendor/sigs.k8s.io/controller-runtime/pkg/internal/recorder/recorder.go
new file mode 100644
index 000000000..46cc1714b
--- /dev/null
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/internal/recorder/recorder.go
@@ -0,0 +1,176 @@
+/*
+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 recorder
+
+import (
+ "context"
+ "fmt"
+ "sync"
+
+ "github.com/go-logr/logr"
+ corev1 "k8s.io/api/core/v1"
+ "k8s.io/apimachinery/pkg/runtime"
+ corev1client "k8s.io/client-go/kubernetes/typed/core/v1"
+ "k8s.io/client-go/rest"
+ "k8s.io/client-go/tools/record"
+)
+
+// EventBroadcasterProducer makes an event broadcaster, returning
+// whether or not the broadcaster should be stopped with the Provider,
+// or not (e.g. if it's shared, it shouldn't be stopped with the Provider).
+type EventBroadcasterProducer func() (caster record.EventBroadcaster, stopWithProvider bool)
+
+// Provider is a recorder.Provider that records events to the k8s API server
+// and to a logr Logger.
+type Provider struct {
+ lock sync.RWMutex
+ stopped bool
+
+ // scheme to specify when creating a recorder
+ scheme *runtime.Scheme
+ // logger is the logger to use when logging diagnostic event info
+ logger logr.Logger
+ evtClient corev1client.EventInterface
+ makeBroadcaster EventBroadcasterProducer
+
+ broadcasterOnce sync.Once
+ broadcaster record.EventBroadcaster
+ stopBroadcaster bool
+}
+
+// NB(directxman12): this manually implements Stop instead of Being a runnable because we need to
+// stop it *after* everything else shuts down, otherwise we'll cause panics as the leader election
+// code finishes up and tries to continue emitting events.
+
+// Stop attempts to stop this provider, stopping the underlying broadcaster
+// if the broadcaster asked to be stopped. It kinda tries to honor the given
+// context, but the underlying broadcaster has an indefinite wait that doesn't
+// return until all queued events are flushed, so this may end up just returning
+// before the underlying wait has finished instead of cancelling the wait.
+// This is Very Frustrating™.
+func (p *Provider) Stop(shutdownCtx context.Context) {
+ doneCh := make(chan struct{})
+
+ go func() {
+ // technically, this could start the broadcaster, but practically, it's
+ // almost certainly already been started (e.g. by leader election). We
+ // need to invoke this to ensure that we don't inadvertently race with
+ // an invocation of getBroadcaster.
+ broadcaster := p.getBroadcaster()
+ if p.stopBroadcaster {
+ p.lock.Lock()
+ broadcaster.Shutdown()
+ p.stopped = true
+ p.lock.Unlock()
+ }
+ close(doneCh)
+ }()
+
+ select {
+ case <-shutdownCtx.Done():
+ case <-doneCh:
+ }
+}
+
+// getBroadcaster ensures that a broadcaster is started for this
+// provider, and returns it. It's threadsafe.
+func (p *Provider) getBroadcaster() record.EventBroadcaster {
+ // NB(directxman12): this can technically still leak if something calls
+ // "getBroadcaster" (i.e. Emits an Event) but never calls Start, but if we
+ // create the broadcaster in start, we could race with other things that
+ // are started at the same time & want to emit events. The alternative is
+ // silently swallowing events and more locking, but that seems suboptimal.
+
+ p.broadcasterOnce.Do(func() {
+ broadcaster, stop := p.makeBroadcaster()
+ broadcaster.StartRecordingToSink(&corev1client.EventSinkImpl{Interface: p.evtClient})
+ broadcaster.StartEventWatcher(
+ func(e *corev1.Event) {
+ p.logger.V(1).Info(e.Type, "object", e.InvolvedObject, "reason", e.Reason, "message", e.Message)
+ })
+ p.broadcaster = broadcaster
+ p.stopBroadcaster = stop
+ })
+
+ return p.broadcaster
+}
+
+// NewProvider create a new Provider instance.
+func NewProvider(config *rest.Config, scheme *runtime.Scheme, logger logr.Logger, makeBroadcaster EventBroadcasterProducer) (*Provider, error) {
+ corev1Client, err := corev1client.NewForConfig(config)
+ if err != nil {
+ return nil, fmt.Errorf("failed to init client: %w", err)
+ }
+
+ p := &Provider{scheme: scheme, logger: logger, makeBroadcaster: makeBroadcaster, evtClient: corev1Client.Events("")}
+ return p, nil
+}
+
+// GetEventRecorderFor returns an event recorder that broadcasts to this provider's
+// broadcaster. All events will be associated with a component of the given name.
+func (p *Provider) GetEventRecorderFor(name string) record.EventRecorder {
+ return &lazyRecorder{
+ prov: p,
+ name: name,
+ }
+}
+
+// lazyRecorder is a recorder that doesn't actually instantiate any underlying
+// recorder until the first event is emitted.
+type lazyRecorder struct {
+ prov *Provider
+ name string
+
+ recOnce sync.Once
+ rec record.EventRecorder
+}
+
+// ensureRecording ensures that a concrete recorder is populated for this recorder.
+func (l *lazyRecorder) ensureRecording() {
+ l.recOnce.Do(func() {
+ broadcaster := l.prov.getBroadcaster()
+ l.rec = broadcaster.NewRecorder(l.prov.scheme, corev1.EventSource{Component: l.name})
+ })
+}
+
+func (l *lazyRecorder) Event(object runtime.Object, eventtype, reason, message string) {
+ l.ensureRecording()
+
+ l.prov.lock.RLock()
+ if !l.prov.stopped {
+ l.rec.Event(object, eventtype, reason, message)
+ }
+ l.prov.lock.RUnlock()
+}
+func (l *lazyRecorder) Eventf(object runtime.Object, eventtype, reason, messageFmt string, args ...interface{}) {
+ l.ensureRecording()
+
+ l.prov.lock.RLock()
+ if !l.prov.stopped {
+ l.rec.Eventf(object, eventtype, reason, messageFmt, args...)
+ }
+ l.prov.lock.RUnlock()
+}
+func (l *lazyRecorder) AnnotatedEventf(object runtime.Object, annotations map[string]string, eventtype, reason, messageFmt string, args ...interface{}) {
+ l.ensureRecording()
+
+ l.prov.lock.RLock()
+ if !l.prov.stopped {
+ l.rec.AnnotatedEventf(object, annotations, eventtype, reason, messageFmt, args...)
+ }
+ l.prov.lock.RUnlock()
+}
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/leaderelection/doc.go b/vendor/sigs.k8s.io/controller-runtime/pkg/leaderelection/doc.go
new file mode 100644
index 000000000..37a9aefab
--- /dev/null
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/leaderelection/doc.go
@@ -0,0 +1,24 @@
+/*
+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 leaderelection contains a constructor for a leader election resource lock.
+This is used to ensure that multiple copies of a controller manager can be run with
+only one active set of controllers, for active-passive HA.
+
+It uses built-in Kubernetes leader election APIs.
+*/
+package leaderelection
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/leaderelection/leader_election.go b/vendor/sigs.k8s.io/controller-runtime/pkg/leaderelection/leader_election.go
new file mode 100644
index 000000000..3dedd462f
--- /dev/null
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/leaderelection/leader_election.go
@@ -0,0 +1,126 @@
+/*
+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 leaderelection
+
+import (
+ "errors"
+ "fmt"
+ "io/ioutil"
+ "os"
+
+ "k8s.io/apimachinery/pkg/util/uuid"
+ coordinationv1client "k8s.io/client-go/kubernetes/typed/coordination/v1"
+ corev1client "k8s.io/client-go/kubernetes/typed/core/v1"
+ "k8s.io/client-go/rest"
+ "k8s.io/client-go/tools/leaderelection/resourcelock"
+ "sigs.k8s.io/controller-runtime/pkg/recorder"
+)
+
+const inClusterNamespacePath = "/var/run/secrets/kubernetes.io/serviceaccount/namespace"
+
+// Options provides the required configuration to create a new resource lock.
+type Options struct {
+ // LeaderElection determines whether or not to use leader election when
+ // starting the manager.
+ LeaderElection bool
+
+ // LeaderElectionResourceLock determines which resource lock to use for leader election,
+ // defaults to "configmapsleases".
+ LeaderElectionResourceLock string
+
+ // LeaderElectionNamespace determines the namespace in which the leader
+ // election resource will be created.
+ LeaderElectionNamespace string
+
+ // LeaderElectionID determines the name of the resource that leader election
+ // will use for holding the leader lock.
+ LeaderElectionID string
+}
+
+// NewResourceLock creates a new resource lock for use in a leader election loop.
+func NewResourceLock(config *rest.Config, recorderProvider recorder.Provider, options Options) (resourcelock.Interface, error) {
+ if !options.LeaderElection {
+ return nil, nil
+ }
+
+ // Default resource lock to "configmapsleases". We must keep this default until we are sure all controller-runtime
+ // users have upgraded from the original default ConfigMap lock to a controller-runtime version that has this new
+ // default. Many users of controller-runtime skip versions, so we should be extremely conservative here.
+ if options.LeaderElectionResourceLock == "" {
+ options.LeaderElectionResourceLock = resourcelock.ConfigMapsLeasesResourceLock
+ }
+
+ // LeaderElectionID must be provided to prevent clashes
+ if options.LeaderElectionID == "" {
+ return nil, errors.New("LeaderElectionID must be configured")
+ }
+
+ // Default the namespace (if running in cluster)
+ if options.LeaderElectionNamespace == "" {
+ var err error
+ options.LeaderElectionNamespace, err = getInClusterNamespace()
+ if err != nil {
+ return nil, fmt.Errorf("unable to find leader election namespace: %w", err)
+ }
+ }
+
+ // Leader id, needs to be unique
+ id, err := os.Hostname()
+ if err != nil {
+ return nil, err
+ }
+ id = id + "_" + string(uuid.NewUUID())
+
+ // Construct clients for leader election
+ rest.AddUserAgent(config, "leader-election")
+ corev1Client, err := corev1client.NewForConfig(config)
+ if err != nil {
+ return nil, err
+ }
+
+ coordinationClient, err := coordinationv1client.NewForConfig(config)
+ if err != nil {
+ return nil, err
+ }
+
+ return resourcelock.New(options.LeaderElectionResourceLock,
+ options.LeaderElectionNamespace,
+ options.LeaderElectionID,
+ corev1Client,
+ coordinationClient,
+ resourcelock.ResourceLockConfig{
+ Identity: id,
+ EventRecorder: recorderProvider.GetEventRecorderFor(id),
+ })
+}
+
+func getInClusterNamespace() (string, error) {
+ // Check whether the namespace file exists.
+ // If not, we are not running in cluster so can't guess the namespace.
+ if _, err := os.Stat(inClusterNamespacePath); os.IsNotExist(err) {
+ return "", fmt.Errorf("not running in-cluster, please specify LeaderElectionNamespace")
+ } else if err != nil {
+ return "", fmt.Errorf("error checking namespace file: %w", err)
+ }
+
+ // Load the namespace file and return its content
+ namespace, err := ioutil.ReadFile(inClusterNamespacePath)
+ if err != nil {
+ return "", fmt.Errorf("error reading namespace file: %w", err)
+ }
+ return string(namespace), nil
+}
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/log/deleg.go b/vendor/sigs.k8s.io/controller-runtime/pkg/log/deleg.go
new file mode 100644
index 000000000..9d73947da
--- /dev/null
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/log/deleg.go
@@ -0,0 +1,216 @@
+/*
+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 log
+
+import (
+ "sync"
+
+ "github.com/go-logr/logr"
+)
+
+// loggerPromise knows how to populate a concrete logr.Logger
+// with options, given an actual base logger later on down the line.
+type loggerPromise struct {
+ logger *DelegatingLogger
+ childPromises []*loggerPromise
+ promisesLock sync.Mutex
+
+ name *string
+ tags []interface{}
+ level int
+}
+
+func (p *loggerPromise) WithName(l *DelegatingLogger, name string) *loggerPromise {
+ res := &loggerPromise{
+ logger: l,
+ name: &name,
+ promisesLock: sync.Mutex{},
+ }
+
+ p.promisesLock.Lock()
+ defer p.promisesLock.Unlock()
+ p.childPromises = append(p.childPromises, res)
+ return res
+}
+
+// WithValues provides a new Logger with the tags appended.
+func (p *loggerPromise) WithValues(l *DelegatingLogger, tags ...interface{}) *loggerPromise {
+ res := &loggerPromise{
+ logger: l,
+ tags: tags,
+ promisesLock: sync.Mutex{},
+ }
+
+ p.promisesLock.Lock()
+ defer p.promisesLock.Unlock()
+ p.childPromises = append(p.childPromises, res)
+ return res
+}
+
+func (p *loggerPromise) V(l *DelegatingLogger, level int) *loggerPromise {
+ res := &loggerPromise{
+ logger: l,
+ level: level,
+ promisesLock: sync.Mutex{},
+ }
+
+ p.promisesLock.Lock()
+ defer p.promisesLock.Unlock()
+ p.childPromises = append(p.childPromises, res)
+ return res
+}
+
+// Fulfill instantiates the Logger with the provided logger.
+func (p *loggerPromise) Fulfill(parentLogger logr.Logger) {
+ logger := logr.WithCallDepth(parentLogger, 1)
+ if p.name != nil {
+ logger = logger.WithName(*p.name)
+ }
+
+ if p.tags != nil {
+ logger = logger.WithValues(p.tags...)
+ }
+ if p.level != 0 {
+ logger = logger.V(p.level)
+ }
+
+ p.logger.lock.Lock()
+ p.logger.logger = logger
+ p.logger.promise = nil
+ p.logger.lock.Unlock()
+
+ for _, childPromise := range p.childPromises {
+ childPromise.Fulfill(logger)
+ }
+}
+
+// DelegatingLogger is a logr.Logger that delegates to another logr.Logger.
+// 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
+// logger. It expects to have *some* logr.Logger set at all times (generally
+// a no-op logger before the promises are fulfilled).
+type DelegatingLogger struct {
+ lock sync.RWMutex
+ logger logr.Logger
+ promise *loggerPromise
+}
+
+// Enabled tests whether this Logger is enabled. For example, commandline
+// flags might be used to set the logging verbosity and disable some info
+// logs.
+func (l *DelegatingLogger) Enabled() bool {
+ l.lock.RLock()
+ defer l.lock.RUnlock()
+ return l.logger.Enabled()
+}
+
+// Info logs a non-error message with the given key/value pairs as context.
+//
+// The msg argument should be used to add some constant description to
+// the log line. The key/value pairs can then be used to add additional
+// variable information. The key/value pairs should alternate string
+// keys and arbitrary values.
+func (l *DelegatingLogger) Info(msg string, keysAndValues ...interface{}) {
+ l.lock.RLock()
+ defer l.lock.RUnlock()
+ l.logger.Info(msg, keysAndValues...)
+}
+
+// Error logs an error, with the given message and key/value pairs as context.
+// It functions similarly to calling Info with the "error" named value, but may
+// have unique behavior, and should be preferred for logging errors (see the
+// package documentations for more information).
+//
+// 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
+// triggered this log line, if present.
+func (l *DelegatingLogger) Error(err error, msg string, keysAndValues ...interface{}) {
+ l.lock.RLock()
+ defer l.lock.RUnlock()
+ l.logger.Error(err, msg, keysAndValues...)
+}
+
+// V returns an Logger value for a specific verbosity level, relative to
+// this Logger. In other words, V values are additive. V higher verbosity
+// level means a log message is less important. It's illegal to pass a log
+// level less than zero.
+func (l *DelegatingLogger) V(level int) logr.Logger {
+ l.lock.RLock()
+ defer l.lock.RUnlock()
+
+ if l.promise == nil {
+ return l.logger.V(level)
+ }
+
+ res := &DelegatingLogger{logger: l.logger}
+ promise := l.promise.V(res, level)
+ res.promise = promise
+
+ return res
+}
+
+// WithName provides a new Logger with the name appended.
+func (l *DelegatingLogger) WithName(name string) logr.Logger {
+ l.lock.RLock()
+ defer l.lock.RUnlock()
+
+ if l.promise == nil {
+ return l.logger.WithName(name)
+ }
+
+ res := &DelegatingLogger{logger: l.logger}
+ promise := l.promise.WithName(res, name)
+ res.promise = promise
+
+ return res
+}
+
+// WithValues provides a new Logger with the tags appended.
+func (l *DelegatingLogger) WithValues(tags ...interface{}) logr.Logger {
+ l.lock.RLock()
+ defer l.lock.RUnlock()
+
+ if l.promise == nil {
+ return l.logger.WithValues(tags...)
+ }
+
+ res := &DelegatingLogger{logger: l.logger}
+ promise := l.promise.WithValues(res, tags...)
+ res.promise = promise
+
+ return res
+}
+
+// Fulfill switches the logger over to use the actual logger
+// provided, instead of the temporary initial one, if this method
+// has not been previously called.
+func (l *DelegatingLogger) Fulfill(actual logr.Logger) {
+ if l.promise != nil {
+ l.promise.Fulfill(actual)
+ }
+}
+
+// NewDelegatingLogger constructs a new DelegatingLogger which uses
+// the given logger before it's promise is fulfilled.
+func NewDelegatingLogger(initial logr.Logger) *DelegatingLogger {
+ l := &DelegatingLogger{
+ logger: initial,
+ promise: &loggerPromise{promisesLock: sync.Mutex{}},
+ }
+ l.promise.logger = l
+ return l
+}
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/log/log.go b/vendor/sigs.k8s.io/controller-runtime/pkg/log/log.go
new file mode 100644
index 000000000..229ac7ec3
--- /dev/null
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/log/log.go
@@ -0,0 +1,99 @@
+/*
+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 log contains utilities for fetching a new logger
+// when one is not already available.
+//
+// The Log Handle
+//
+// This package contains a root logr.Logger Log. It may be used to
+// get a handle to whatever the root logging implementation is. By
+// default, no implementation exists, and the handle returns "promises"
+// to loggers. When the implementation is set using SetLogger, these
+// "promises" will be converted over to real loggers.
+//
+// Logr
+//
+// All logging in controller-runtime is structured, using a set of interfaces
+// defined by a package called logr
+// (https://godoc.org/github.com/go-logr/logr). The sub-package zap provides
+// helpers for setting up logr backed by Zap (go.uber.org/zap).
+package log
+
+import (
+ "context"
+ "sync"
+ "time"
+
+ "github.com/go-logr/logr"
+)
+
+// SetLogger sets a concrete logging implementation for all deferred Loggers.
+func SetLogger(l logr.Logger) {
+ loggerWasSetLock.Lock()
+ defer loggerWasSetLock.Unlock()
+
+ loggerWasSet = true
+ Log.Fulfill(l)
+}
+
+// It is safe to assume that if this wasn't set within the first 30 seconds of a binaries
+// lifetime, it will never get set. The DelegatingLogger causes a high number of memory
+// allocations when not given an actual Logger, so we set a NullLogger to avoid that.
+//
+// We need to keep the DelegatingLogger because we have various inits() that get a logger from
+// here. They will always get executed before any code that imports controller-runtime
+// has a chance to run and hence to set an actual logger.
+func init() {
+ // Init is blocking, so start a new goroutine
+ go func() {
+ time.Sleep(30 * time.Second)
+ loggerWasSetLock.Lock()
+ defer loggerWasSetLock.Unlock()
+ if !loggerWasSet {
+ Log.Fulfill(NullLogger{})
+ }
+ }()
+}
+
+var (
+ loggerWasSetLock sync.Mutex
+ loggerWasSet bool
+)
+
+// Log is the base logger used by kubebuilder. It delegates
+// to another logr.Logger. You *must* call SetLogger to
+// get any actual logging. If SetLogger is not called within
+// the first 30 seconds of a binaries lifetime, it will get
+// set to a NullLogger.
+var Log = NewDelegatingLogger(NullLogger{})
+
+// FromContext returns a logger with predefined values from a context.Context.
+func FromContext(ctx context.Context, keysAndValues ...interface{}) logr.Logger {
+ var log logr.Logger = Log
+ if ctx != nil {
+ if logger := logr.FromContext(ctx); logger != nil {
+ log = logger
+ }
+ }
+ return log.WithValues(keysAndValues...)
+}
+
+// IntoContext takes a context and sets the logger as one of its values.
+// Use FromContext function to retrieve the logger.
+func IntoContext(ctx context.Context, log logr.Logger) context.Context {
+ return logr.NewContext(ctx, log)
+}
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/log/null.go b/vendor/sigs.k8s.io/controller-runtime/pkg/log/null.go
new file mode 100644
index 000000000..09a5a02eb
--- /dev/null
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/log/null.go
@@ -0,0 +1,60 @@
+/*
+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 log
+
+import (
+ "github.com/go-logr/logr"
+)
+
+// NB: this is the same as the null logger logr/testing,
+// but avoids accidentally adding the testing flags to
+// all binaries.
+
+// NullLogger is a logr.Logger that does nothing.
+type NullLogger struct{}
+
+var _ logr.Logger = NullLogger{}
+
+// Info implements logr.InfoLogger.
+func (NullLogger) Info(_ string, _ ...interface{}) {
+ // Do nothing.
+}
+
+// Enabled implements logr.InfoLogger.
+func (NullLogger) Enabled() bool {
+ return false
+}
+
+// Error implements logr.Logger.
+func (NullLogger) Error(_ error, _ string, _ ...interface{}) {
+ // Do nothing.
+}
+
+// V implements logr.Logger.
+func (log NullLogger) V(_ int) logr.Logger {
+ return log
+}
+
+// WithName implements logr.Logger.
+func (log NullLogger) WithName(_ string) logr.Logger {
+ return log
+}
+
+// WithValues implements logr.Logger.
+func (log NullLogger) WithValues(_ ...interface{}) logr.Logger {
+ return log
+}
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/log/warning_handler.go b/vendor/sigs.k8s.io/controller-runtime/pkg/log/warning_handler.go
new file mode 100644
index 000000000..3012fdd41
--- /dev/null
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/log/warning_handler.go
@@ -0,0 +1,76 @@
+/*
+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 log
+
+import (
+ "sync"
+
+ "github.com/go-logr/logr"
+)
+
+// KubeAPIWarningLoggerOptions controls the behavior
+// of a rest.WarningHandler constructed using NewKubeAPIWarningLogger().
+type KubeAPIWarningLoggerOptions struct {
+ // Deduplicate indicates a given warning message should only be written once.
+ // Setting this to true in a long-running process handling many warnings can
+ // result in increased memory use.
+ Deduplicate bool
+}
+
+// KubeAPIWarningLogger is a wrapper around
+// a provided logr.Logger that implements the
+// rest.WarningHandler interface.
+type KubeAPIWarningLogger struct {
+ // logger is used to log responses with the warning header
+ logger logr.Logger
+ // opts contain options controlling warning output
+ opts KubeAPIWarningLoggerOptions
+ // writtenLock gurads written
+ writtenLock sync.Mutex
+ // used to keep track of already logged messages
+ // and help in de-duplication.
+ written map[string]struct{}
+}
+
+// HandleWarningHeader handles logging for responses from API server that are
+// warnings with code being 299 and uses a logr.Logger for it's logging purposes.
+func (l *KubeAPIWarningLogger) HandleWarningHeader(code int, agent string, message string) {
+ if code != 299 || len(message) == 0 {
+ return
+ }
+
+ if l.opts.Deduplicate {
+ l.writtenLock.Lock()
+ defer l.writtenLock.Unlock()
+
+ if _, alreadyLogged := l.written[message]; alreadyLogged {
+ return
+ }
+ l.written[message] = struct{}{}
+ }
+ l.logger.Info(message)
+}
+
+// NewKubeAPIWarningLogger returns an implementation of rest.WarningHandler that logs warnings
+// with code = 299 to the provided logr.Logger.
+func NewKubeAPIWarningLogger(l logr.Logger, opts KubeAPIWarningLoggerOptions) *KubeAPIWarningLogger {
+ h := &KubeAPIWarningLogger{logger: l, opts: opts}
+ if opts.Deduplicate {
+ h.written = map[string]struct{}{}
+ }
+ return h
+}
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/manager/doc.go b/vendor/sigs.k8s.io/controller-runtime/pkg/manager/doc.go
new file mode 100644
index 000000000..f2976c7f7
--- /dev/null
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/manager/doc.go
@@ -0,0 +1,21 @@
+/*
+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 manager is required to create Controllers and provides shared dependencies such as clients, caches, schemes,
+etc. Controllers must be started by calling Manager.Start.
+*/
+package manager
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/manager/internal.go b/vendor/sigs.k8s.io/controller-runtime/pkg/manager/internal.go
new file mode 100644
index 000000000..59794d962
--- /dev/null
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/manager/internal.go
@@ -0,0 +1,709 @@
+/*
+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 manager
+
+import (
+ "context"
+ "errors"
+ "fmt"
+ "net"
+ "net/http"
+ "sync"
+ "time"
+
+ "github.com/go-logr/logr"
+ "github.com/prometheus/client_golang/prometheus/promhttp"
+ "k8s.io/apimachinery/pkg/api/meta"
+ "k8s.io/apimachinery/pkg/runtime"
+ kerrors "k8s.io/apimachinery/pkg/util/errors"
+ "k8s.io/client-go/rest"
+ "k8s.io/client-go/tools/leaderelection"
+ "k8s.io/client-go/tools/leaderelection/resourcelock"
+ "k8s.io/client-go/tools/record"
+
+ "sigs.k8s.io/controller-runtime/pkg/cache"
+ "sigs.k8s.io/controller-runtime/pkg/client"
+ "sigs.k8s.io/controller-runtime/pkg/cluster"
+ "sigs.k8s.io/controller-runtime/pkg/config/v1alpha1"
+ "sigs.k8s.io/controller-runtime/pkg/healthz"
+ intrec "sigs.k8s.io/controller-runtime/pkg/internal/recorder"
+ "sigs.k8s.io/controller-runtime/pkg/metrics"
+ "sigs.k8s.io/controller-runtime/pkg/runtime/inject"
+ "sigs.k8s.io/controller-runtime/pkg/webhook"
+)
+
+const (
+ // Values taken from: https://github.com/kubernetes/component-base/blob/master/config/v1alpha1/defaults.go
+ defaultLeaseDuration = 15 * time.Second
+ defaultRenewDeadline = 10 * time.Second
+ defaultRetryPeriod = 2 * time.Second
+ defaultGracefulShutdownPeriod = 30 * time.Second
+
+ defaultReadinessEndpoint = "/readyz"
+ defaultLivenessEndpoint = "/healthz"
+ defaultMetricsEndpoint = "/metrics"
+)
+
+var _ Runnable = &controllerManager{}
+
+type controllerManager struct {
+ // cluster holds a variety of methods to interact with a cluster. Required.
+ cluster cluster.Cluster
+
+ // leaderElectionRunnables is the set of Controllers that the controllerManager injects deps into and Starts.
+ // These Runnables are managed by lead election.
+ leaderElectionRunnables []Runnable
+
+ // nonLeaderElectionRunnables is the set of webhook servers that the controllerManager injects deps into and Starts.
+ // These Runnables will not be blocked by lead election.
+ nonLeaderElectionRunnables []Runnable
+
+ // recorderProvider is used to generate event recorders that will be injected into Controllers
+ // (and EventHandlers, Sources and Predicates).
+ recorderProvider *intrec.Provider
+
+ // resourceLock forms the basis for leader election
+ resourceLock resourcelock.Interface
+
+ // leaderElectionReleaseOnCancel defines if the manager should step back from the leader lease
+ // on shutdown
+ leaderElectionReleaseOnCancel bool
+
+ // metricsListener is used to serve prometheus metrics
+ metricsListener net.Listener
+
+ // metricsExtraHandlers contains extra handlers to register on http server that serves metrics.
+ metricsExtraHandlers map[string]http.Handler
+
+ // healthProbeListener is used to serve liveness probe
+ healthProbeListener net.Listener
+
+ // Readiness probe endpoint name
+ readinessEndpointName string
+
+ // Liveness probe endpoint name
+ livenessEndpointName string
+
+ // Readyz probe handler
+ readyzHandler *healthz.Handler
+
+ // Healthz probe handler
+ healthzHandler *healthz.Handler
+
+ mu sync.Mutex
+ started bool
+ startedLeader bool
+ healthzStarted bool
+ errChan chan error
+
+ // controllerOptions are the global controller options.
+ controllerOptions v1alpha1.ControllerConfigurationSpec
+
+ // Logger is the logger that should be used by this manager.
+ // If none is set, it defaults to log.Log global logger.
+ logger logr.Logger
+
+ // leaderElectionCancel is used to cancel the leader election. It is distinct from internalStopper,
+ // because for safety reasons we need to os.Exit() when we lose the leader election, meaning that
+ // it must be deferred until after gracefulShutdown is done.
+ leaderElectionCancel context.CancelFunc
+
+ // leaderElectionStopped is an internal channel used to signal the stopping procedure that the
+ // LeaderElection.Run(...) function has returned and the shutdown can proceed.
+ leaderElectionStopped chan struct{}
+
+ // stop procedure engaged. In other words, we should not add anything else to the manager
+ stopProcedureEngaged bool
+
+ // elected is closed when this manager becomes the leader of a group of
+ // managers, either because it won a leader election or because no leader
+ // election was configured.
+ elected chan struct{}
+
+ caches []hasCache
+
+ // port is the port that the webhook server serves at.
+ 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
+
+ webhookServer *webhook.Server
+ // webhookServerOnce will be called in GetWebhookServer() to optionally initialize
+ // webhookServer if unset, and Add() it to controllerManager.
+ webhookServerOnce sync.Once
+
+ // leaseDuration is the duration that non-leader candidates will
+ // wait to force acquire leadership.
+ leaseDuration time.Duration
+ // renewDeadline is the duration that the acting controlplane will retry
+ // refreshing leadership before giving up.
+ renewDeadline time.Duration
+ // retryPeriod is the duration the LeaderElector clients should wait
+ // between tries of actions.
+ retryPeriod time.Duration
+
+ // waitForRunnable is holding the number of runnables currently running so that
+ // we can wait for them to exit before quitting the manager
+ waitForRunnable sync.WaitGroup
+
+ // gracefulShutdownTimeout is the duration given to runnable to stop
+ // before the manager actually returns on stop.
+ gracefulShutdownTimeout time.Duration
+
+ // onStoppedLeading is callled when the leader election lease is lost.
+ // It can be overridden for tests.
+ onStoppedLeading func()
+
+ // shutdownCtx is the context that can be used during shutdown. It will be cancelled
+ // after the gracefulShutdownTimeout ended. It must not be accessed before internalStop
+ // is closed because it will be nil.
+ shutdownCtx context.Context
+
+ internalCtx context.Context
+ internalCancel context.CancelFunc
+
+ // internalProceduresStop channel is used internally to the manager when coordinating
+ // the proper shutdown of servers. This channel is also used for dependency injection.
+ internalProceduresStop chan struct{}
+}
+
+type hasCache interface {
+ Runnable
+ GetCache() cache.Cache
+}
+
+// Add sets dependencies on i, and adds it to the list of Runnables to start.
+func (cm *controllerManager) Add(r Runnable) error {
+ cm.mu.Lock()
+ defer cm.mu.Unlock()
+ if cm.stopProcedureEngaged {
+ return errors.New("can't accept new runnable as stop procedure is already engaged")
+ }
+
+ // Set dependencies on the object
+ if err := cm.SetFields(r); err != nil {
+ return err
+ }
+
+ var shouldStart bool
+
+ // Add the runnable to the leader election or the non-leaderelection list
+ if leRunnable, ok := r.(LeaderElectionRunnable); ok && !leRunnable.NeedLeaderElection() {
+ shouldStart = cm.started
+ cm.nonLeaderElectionRunnables = append(cm.nonLeaderElectionRunnables, r)
+ } else if hasCache, ok := r.(hasCache); ok {
+ cm.caches = append(cm.caches, hasCache)
+ } else {
+ shouldStart = cm.startedLeader
+ cm.leaderElectionRunnables = append(cm.leaderElectionRunnables, r)
+ }
+
+ if shouldStart {
+ // If already started, start the controller
+ cm.startRunnable(r)
+ }
+
+ return nil
+}
+
+// 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.
+func (cm *controllerManager) AddMetricsExtraHandler(path string, handler http.Handler) error {
+ if path == defaultMetricsEndpoint {
+ return fmt.Errorf("overriding builtin %s endpoint is not allowed", defaultMetricsEndpoint)
+ }
+
+ cm.mu.Lock()
+ defer cm.mu.Unlock()
+
+ if _, found := cm.metricsExtraHandlers[path]; found {
+ return fmt.Errorf("can't register extra handler by duplicate path %q on metrics http server", path)
+ }
+
+ cm.metricsExtraHandlers[path] = handler
+ cm.logger.V(2).Info("Registering metrics http server extra handler", "path", path)
+ return nil
+}
+
+// AddHealthzCheck allows you to add Healthz checker.
+func (cm *controllerManager) AddHealthzCheck(name string, check healthz.Checker) error {
+ cm.mu.Lock()
+ defer cm.mu.Unlock()
+
+ if cm.stopProcedureEngaged {
+ return errors.New("can't accept new healthCheck as stop procedure is already engaged")
+ }
+
+ if cm.healthzStarted {
+ return fmt.Errorf("unable to add new checker because healthz endpoint has already been created")
+ }
+
+ if cm.healthzHandler == nil {
+ cm.healthzHandler = &healthz.Handler{Checks: map[string]healthz.Checker{}}
+ }
+
+ cm.healthzHandler.Checks[name] = check
+ return nil
+}
+
+// AddReadyzCheck allows you to add Readyz checker.
+func (cm *controllerManager) AddReadyzCheck(name string, check healthz.Checker) error {
+ cm.mu.Lock()
+ defer cm.mu.Unlock()
+
+ if cm.stopProcedureEngaged {
+ return errors.New("can't accept new ready check as stop procedure is already engaged")
+ }
+
+ if cm.healthzStarted {
+ return fmt.Errorf("unable to add new checker because readyz endpoint has already been created")
+ }
+
+ if cm.readyzHandler == nil {
+ cm.readyzHandler = &healthz.Handler{Checks: map[string]healthz.Checker{}}
+ }
+
+ cm.readyzHandler.Checks[name] = check
+ return nil
+}
+
+func (cm *controllerManager) GetConfig() *rest.Config {
+ return cm.cluster.GetConfig()
+}
+
+func (cm *controllerManager) GetClient() client.Client {
+ return cm.cluster.GetClient()
+}
+
+func (cm *controllerManager) GetScheme() *runtime.Scheme {
+ return cm.cluster.GetScheme()
+}
+
+func (cm *controllerManager) GetFieldIndexer() client.FieldIndexer {
+ return cm.cluster.GetFieldIndexer()
+}
+
+func (cm *controllerManager) GetCache() cache.Cache {
+ return cm.cluster.GetCache()
+}
+
+func (cm *controllerManager) GetEventRecorderFor(name string) record.EventRecorder {
+ return cm.cluster.GetEventRecorderFor(name)
+}
+
+func (cm *controllerManager) GetRESTMapper() meta.RESTMapper {
+ return cm.cluster.GetRESTMapper()
+}
+
+func (cm *controllerManager) GetAPIReader() client.Reader {
+ return cm.cluster.GetAPIReader()
+}
+
+func (cm *controllerManager) GetWebhookServer() *webhook.Server {
+ cm.webhookServerOnce.Do(func() {
+ if cm.webhookServer == nil {
+ cm.webhookServer = &webhook.Server{
+ Port: cm.port,
+ Host: cm.host,
+ CertDir: cm.certDir,
+ }
+ }
+ if err := cm.Add(cm.webhookServer); err != nil {
+ panic("unable to add webhook server to the controller manager")
+ }
+ })
+ return cm.webhookServer
+}
+
+func (cm *controllerManager) GetLogger() logr.Logger {
+ return cm.logger
+}
+
+func (cm *controllerManager) GetControllerOptions() v1alpha1.ControllerConfigurationSpec {
+ return cm.controllerOptions
+}
+
+func (cm *controllerManager) serveMetrics() {
+ handler := promhttp.HandlerFor(metrics.Registry, promhttp.HandlerOpts{
+ ErrorHandling: promhttp.HTTPErrorOnError,
+ })
+ // TODO(JoelSpeed): Use existing Kubernetes machinery for serving metrics
+ mux := http.NewServeMux()
+ mux.Handle(defaultMetricsEndpoint, handler)
+
+ func() {
+ cm.mu.Lock()
+ defer cm.mu.Unlock()
+
+ for path, extraHandler := range cm.metricsExtraHandlers {
+ mux.Handle(path, extraHandler)
+ }
+ }()
+
+ server := http.Server{
+ Handler: mux,
+ }
+ // Run the server
+ cm.startRunnable(RunnableFunc(func(_ context.Context) error {
+ cm.logger.Info("Starting metrics server", "path", defaultMetricsEndpoint)
+ if err := server.Serve(cm.metricsListener); err != nil && err != http.ErrServerClosed {
+ return err
+ }
+ return nil
+ }))
+
+ // Shutdown the server when stop is closed
+ <-cm.internalProceduresStop
+ if err := server.Shutdown(cm.shutdownCtx); err != nil {
+ cm.errChan <- err
+ }
+}
+
+func (cm *controllerManager) serveHealthProbes() {
+ mux := http.NewServeMux()
+ server := http.Server{
+ Handler: mux,
+ }
+
+ func() {
+ cm.mu.Lock()
+ defer cm.mu.Unlock()
+
+ if cm.readyzHandler != nil {
+ mux.Handle(cm.readinessEndpointName, http.StripPrefix(cm.readinessEndpointName, cm.readyzHandler))
+ // Append '/' suffix to handle subpaths
+ mux.Handle(cm.readinessEndpointName+"/", http.StripPrefix(cm.readinessEndpointName, cm.readyzHandler))
+ }
+ if cm.healthzHandler != nil {
+ mux.Handle(cm.livenessEndpointName, http.StripPrefix(cm.livenessEndpointName, cm.healthzHandler))
+ // Append '/' suffix to handle subpaths
+ mux.Handle(cm.livenessEndpointName+"/", http.StripPrefix(cm.livenessEndpointName, cm.healthzHandler))
+ }
+
+ // Run server
+ cm.startRunnable(RunnableFunc(func(_ context.Context) error {
+ if err := server.Serve(cm.healthProbeListener); err != nil && err != http.ErrServerClosed {
+ return err
+ }
+ return nil
+ }))
+ cm.healthzStarted = true
+ }()
+
+ go func() {
+ // Shutdown the server when stop is closed
+ <-cm.internalProceduresStop
+ if err := server.Shutdown(cm.shutdownCtx); err != nil {
+ cm.errChan <- err
+ }
+ }()
+}
+
+func (cm *controllerManager) Start(ctx context.Context) (err error) {
+ if err := cm.Add(cm.cluster); err != nil {
+ return fmt.Errorf("failed to add cluster to runnables: %w", err)
+ }
+ cm.internalCtx, cm.internalCancel = context.WithCancel(ctx)
+
+ // This chan indicates that stop is complete, in other words all runnables have returned or timeout on stop request
+ stopComplete := make(chan struct{})
+ defer close(stopComplete)
+ // This must be deferred after closing stopComplete, otherwise we deadlock.
+ defer func() {
+ // https://hips.hearstapps.com/hmg-prod.s3.amazonaws.com/images/gettyimages-459889618-1533579787.jpg
+ stopErr := cm.engageStopProcedure(stopComplete)
+ if stopErr != nil {
+ if err != nil {
+ // Utilerrors.Aggregate allows to use errors.Is for all contained errors
+ // whereas fmt.Errorf allows wrapping at most one error which means the
+ // other one can not be found anymore.
+ err = kerrors.NewAggregate([]error{err, stopErr})
+ } else {
+ err = stopErr
+ }
+ }
+ }()
+
+ // initialize this here so that we reset the signal channel state on every start
+ // Everything that might write into this channel must be started in a new goroutine,
+ // because otherwise we might block this routine trying to write into the full channel
+ // and will not be able to enter the deferred cm.engageStopProcedure() which drains
+ // it.
+ cm.errChan = make(chan error)
+
+ // Metrics should be served whether the controller is leader or not.
+ // (If we don't serve metrics for non-leaders, prometheus will still scrape
+ // the pod but will get a connection refused)
+ if cm.metricsListener != nil {
+ go cm.serveMetrics()
+ }
+
+ // Serve health probes
+ if cm.healthProbeListener != nil {
+ cm.serveHealthProbes()
+ }
+
+ // Webhooks MUST start before any cache is populated, otherwise there is a race condition
+ // between conversion webhooks and the cache sync (usually initial list) which causes the webhooks
+ // to never start because no cache can be populated.
+ cm.startWebhookRunnables()
+
+ go cm.startNonLeaderElectionRunnables()
+
+ go func() {
+ if cm.resourceLock != nil {
+ err := cm.startLeaderElection()
+ if err != nil {
+ cm.errChan <- err
+ }
+ } else {
+ // Treat not having leader election enabled the same as being elected.
+ cm.startLeaderElectionRunnables()
+ close(cm.elected)
+ }
+ }()
+
+ select {
+ case <-ctx.Done():
+ // We are done
+ return nil
+ case err := <-cm.errChan:
+ // Error starting or running a runnable
+ return err
+ }
+}
+
+// engageStopProcedure signals all runnables to stop, reads potential errors
+// from the errChan and waits for them to end. It must not be called more than once.
+func (cm *controllerManager) engageStopProcedure(stopComplete <-chan struct{}) error {
+ // Populate the shutdown context.
+ var shutdownCancel context.CancelFunc
+ if cm.gracefulShutdownTimeout > 0 {
+ cm.shutdownCtx, shutdownCancel = context.WithTimeout(context.Background(), cm.gracefulShutdownTimeout)
+ } else {
+ cm.shutdownCtx, shutdownCancel = context.WithCancel(context.Background())
+ }
+ defer shutdownCancel()
+
+ // Cancel the internal stop channel and wait for the procedures to stop and complete.
+ close(cm.internalProceduresStop)
+ cm.internalCancel()
+
+ // Start draining the errors before acquiring the lock to make sure we don't deadlock
+ // if something that has the lock is blocked on trying to write into the unbuffered
+ // channel after something else already wrote into it.
+ go func() {
+ for {
+ select {
+ case err, ok := <-cm.errChan:
+ if ok {
+ cm.logger.Error(err, "error received after stop sequence was engaged")
+ }
+ case <-stopComplete:
+ return
+ }
+ }
+ }()
+ if cm.gracefulShutdownTimeout == 0 {
+ return nil
+ }
+ cm.mu.Lock()
+ defer cm.mu.Unlock()
+ cm.stopProcedureEngaged = true
+
+ // we want to close this after the other runnables stop, because we don't
+ // want things like leader election to try and emit events on a closed
+ // channel
+ defer cm.recorderProvider.Stop(cm.shutdownCtx)
+ return cm.waitForRunnableToEnd(shutdownCancel)
+}
+
+// waitForRunnableToEnd blocks until all runnables ended or the
+// tearDownTimeout was reached. In the latter case, an error is returned.
+func (cm *controllerManager) waitForRunnableToEnd(shutdownCancel context.CancelFunc) (retErr error) {
+ // Cancel leader election only after we waited. It will os.Exit() the app for safety.
+ defer func() {
+ if retErr == nil && cm.leaderElectionCancel != nil {
+ // After asking the context to be cancelled, make sure
+ // we wait for the leader stopped channel to be closed, otherwise
+ // we might encounter race conditions between this code
+ // and the event recorder, which is used within leader election code.
+ cm.leaderElectionCancel()
+ <-cm.leaderElectionStopped
+ }
+ }()
+
+ go func() {
+ cm.waitForRunnable.Wait()
+ shutdownCancel()
+ }()
+
+ <-cm.shutdownCtx.Done()
+ if err := cm.shutdownCtx.Err(); err != nil && err != context.Canceled {
+ return fmt.Errorf("failed waiting for all runnables to end within grace period of %s: %w", cm.gracefulShutdownTimeout, err)
+ }
+ return nil
+}
+
+func (cm *controllerManager) startWebhookRunnables() {
+ cm.mu.Lock()
+ defer cm.mu.Unlock()
+
+ // WARNING: Webhooks MUST start before any cache is populated, otherwise there is a race condition
+ // between conversion webhooks and the cache sync (usually initial list) which causes the webhooks
+ // to never start because no cache can be populated.
+ for _, c := range cm.nonLeaderElectionRunnables {
+ if _, ok := c.(*webhook.Server); ok {
+ cm.startRunnable(c)
+ }
+ }
+}
+
+func (cm *controllerManager) startNonLeaderElectionRunnables() {
+ cm.mu.Lock()
+ defer cm.mu.Unlock()
+
+ // Start and wait for caches.
+ cm.waitForCache(cm.internalCtx)
+
+ // Start the non-leaderelection Runnables after the cache has synced
+ for _, c := range cm.nonLeaderElectionRunnables {
+ if _, ok := c.(*webhook.Server); ok {
+ continue
+ }
+
+ // Controllers block, but we want to return an error if any have an error starting.
+ // Write any Start errors to a channel so we can return them
+ cm.startRunnable(c)
+ }
+}
+
+func (cm *controllerManager) startLeaderElectionRunnables() {
+ cm.mu.Lock()
+ defer cm.mu.Unlock()
+
+ cm.waitForCache(cm.internalCtx)
+
+ // Start the leader election Runnables after the cache has synced
+ for _, c := range cm.leaderElectionRunnables {
+ // Controllers block, but we want to return an error if any have an error starting.
+ // Write any Start errors to a channel so we can return them
+ cm.startRunnable(c)
+ }
+
+ cm.startedLeader = true
+}
+
+func (cm *controllerManager) waitForCache(ctx context.Context) {
+ if cm.started {
+ return
+ }
+
+ for _, cache := range cm.caches {
+ cm.startRunnable(cache)
+ }
+
+ // Wait for the caches to sync.
+ // TODO(community): Check the return value and write a test
+ for _, cache := range cm.caches {
+ cache.GetCache().WaitForCacheSync(ctx)
+ }
+ // TODO: This should be the return value of cm.cache.WaitForCacheSync but we abuse
+ // cm.started as check if we already started the cache so it must always become true.
+ // Making sure that the cache doesn't get started twice is needed to not get a "close
+ // of closed channel" panic
+ cm.started = true
+}
+
+func (cm *controllerManager) startLeaderElection() (err error) {
+ ctx, cancel := context.WithCancel(context.Background())
+ cm.mu.Lock()
+ cm.leaderElectionCancel = cancel
+ cm.mu.Unlock()
+
+ if cm.onStoppedLeading == nil {
+ cm.onStoppedLeading = func() {
+ // Make sure graceful shutdown is skipped if we lost the leader lock without
+ // intending to.
+ cm.gracefulShutdownTimeout = time.Duration(0)
+ // Most implementations of leader election log.Fatal() here.
+ // Since Start is wrapped in log.Fatal when called, we can just return
+ // an error here which will cause the program to exit.
+ cm.errChan <- errors.New("leader election lost")
+ }
+ }
+ l, err := leaderelection.NewLeaderElector(leaderelection.LeaderElectionConfig{
+ Lock: cm.resourceLock,
+ LeaseDuration: cm.leaseDuration,
+ RenewDeadline: cm.renewDeadline,
+ RetryPeriod: cm.retryPeriod,
+ Callbacks: leaderelection.LeaderCallbacks{
+ OnStartedLeading: func(_ context.Context) {
+ cm.startLeaderElectionRunnables()
+ close(cm.elected)
+ },
+ OnStoppedLeading: cm.onStoppedLeading,
+ },
+ ReleaseOnCancel: cm.leaderElectionReleaseOnCancel,
+ })
+ if err != nil {
+ return err
+ }
+
+ // Start the leader elector process
+ go func() {
+ l.Run(ctx)
+ <-ctx.Done()
+ close(cm.leaderElectionStopped)
+ }()
+ return nil
+}
+
+func (cm *controllerManager) Elected() <-chan struct{} {
+ return cm.elected
+}
+
+func (cm *controllerManager) startRunnable(r Runnable) {
+ cm.waitForRunnable.Add(1)
+ go func() {
+ defer cm.waitForRunnable.Done()
+ if err := r.Start(cm.internalCtx); err != nil {
+ cm.errChan <- err
+ }
+ }()
+}
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/manager/manager.go b/vendor/sigs.k8s.io/controller-runtime/pkg/manager/manager.go
new file mode 100644
index 000000000..2d2733f0a
--- /dev/null
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/manager/manager.go
@@ -0,0 +1,579 @@
+/*
+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 manager
+
+import (
+ "context"
+ "fmt"
+ "net"
+ "net/http"
+ "reflect"
+ "time"
+
+ "github.com/go-logr/logr"
+ "k8s.io/apimachinery/pkg/api/meta"
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ "k8s.io/apimachinery/pkg/runtime"
+ "k8s.io/client-go/rest"
+ "k8s.io/client-go/tools/leaderelection/resourcelock"
+ "k8s.io/client-go/tools/record"
+ "sigs.k8s.io/controller-runtime/pkg/cache"
+ "sigs.k8s.io/controller-runtime/pkg/client"
+ "sigs.k8s.io/controller-runtime/pkg/cluster"
+ "sigs.k8s.io/controller-runtime/pkg/config"
+ "sigs.k8s.io/controller-runtime/pkg/config/v1alpha1"
+ "sigs.k8s.io/controller-runtime/pkg/healthz"
+ intrec "sigs.k8s.io/controller-runtime/pkg/internal/recorder"
+ "sigs.k8s.io/controller-runtime/pkg/leaderelection"
+ "sigs.k8s.io/controller-runtime/pkg/log"
+ "sigs.k8s.io/controller-runtime/pkg/metrics"
+ "sigs.k8s.io/controller-runtime/pkg/recorder"
+ "sigs.k8s.io/controller-runtime/pkg/runtime/inject"
+ "sigs.k8s.io/controller-runtime/pkg/webhook"
+)
+
+// Manager initializes shared dependencies such as Caches and Clients, and provides them to Runnables.
+// A Manager is required to create Controllers.
+type Manager interface {
+ // Cluster holds a variety of methods to interact with a cluster.
+ cluster.Cluster
+
+ // 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
+ // implements the inject interface - e.g. inject.Client.
+ // 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).
+ Add(Runnable) error
+
+ // Elected is closed when this manager is elected leader of a group of
+ // managers, either because it won a leader election or because no leader
+ // election was configured.
+ Elected() <-chan struct{}
+
+ // AddMetricsExtraHandler adds an extra handler served on path to the http server that serves metrics.
+ // Might be useful to register some diagnostic endpoints e.g. pprof. Note that these endpoints meant to be
+ // sensitive and shouldn't be exposed publicly.
+ // If the simple path -> handler mapping offered here is not enough, a new http server/listener should be added as
+ // Runnable to the manager via Add method.
+ AddMetricsExtraHandler(path string, handler http.Handler) error
+
+ // AddHealthzCheck allows you to add Healthz checker
+ AddHealthzCheck(name string, check healthz.Checker) error
+
+ // AddReadyzCheck allows you to add Readyz checker
+ AddReadyzCheck(name string, check healthz.Checker) error
+
+ // Start starts all registered Controllers and blocks until the context is cancelled.
+ // Returns an error if there is an error starting any controller.
+ //
+ // If LeaderElection is used, the binary must be exited immediately after this returns,
+ // otherwise components that need leader election might continue to run after the leader
+ // lock was lost.
+ Start(ctx context.Context) error
+
+ // GetWebhookServer returns a webhook.Server
+ GetWebhookServer() *webhook.Server
+
+ // GetLogger returns this manager's logger.
+ GetLogger() logr.Logger
+
+ // GetControllerOptions returns controller global configuration options.
+ GetControllerOptions() v1alpha1.ControllerConfigurationSpec
+}
+
+// Options are the arguments for creating a new Manager.
+type Options 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
+
+ // MapperProvider provides the rest mapper used to map go types to Kubernetes APIs
+ MapperProvider func(c *rest.Config) (meta.RESTMapper, error)
+
+ // SyncPeriod determines the minimum frequency at which watched resources are
+ // reconciled. A lower period will correct entropy more quickly, but reduce
+ // responsiveness to change if there are many watched resources. Change this
+ // value only if you know what you are doing. Defaults to 10 hours if unset.
+ // there will a 10 percent jitter between the SyncPeriod of all controllers
+ // so that all controllers will not send list requests simultaneously.
+ //
+ // 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
+
+ // Logger is the logger that should be used by this manager.
+ // If none is set, it defaults to log.Log global logger.
+ Logger logr.Logger
+
+ // LeaderElection determines whether or not to use leader election when
+ // starting the manager.
+ LeaderElection bool
+
+ // LeaderElectionResourceLock determines which resource lock to use for leader election,
+ // defaults to "configmapsleases". Change this value only if you know what you are doing.
+ // Otherwise, users of your controller might end up with multiple running instances that
+ // each acquired leadership through different resource locks during upgrades and thus
+ // act on the same resources concurrently.
+ // If you want to migrate to the "leases" resource lock, you might do so by migrating to the
+ // respective multilock first ("configmapsleases" or "endpointsleases"), which will acquire a
+ // leader lock on both resources. After all your users have migrated to the multilock, you can
+ // go ahead and migrate to "leases". Please also keep in mind, that users might skip versions
+ // of your controller.
+ //
+ // Note: before controller-runtime version v0.7, the resource lock was set to "configmaps".
+ // Please keep this in mind, when planning a proper migration path for your controller.
+ LeaderElectionResourceLock string
+
+ // LeaderElectionNamespace determines the namespace in which the leader
+ // election resource will be created.
+ LeaderElectionNamespace string
+
+ // LeaderElectionID determines the name of the resource that leader election
+ // will use for holding the leader lock.
+ LeaderElectionID string
+
+ // LeaderElectionConfig can be specified to override the default configuration
+ // that is used to build the leader election client.
+ LeaderElectionConfig *rest.Config
+
+ // LeaderElectionReleaseOnCancel defines if the leader should step down voluntarily
+ // when the Manager ends. This requires the binary to immediately end when the
+ // Manager is stopped, otherwise this setting is unsafe. Setting this significantly
+ // speeds up voluntary leader transitions as the new leader doesn't have to wait
+ // LeaseDuration time first.
+ LeaderElectionReleaseOnCancel bool
+
+ // LeaseDuration is the duration that non-leader candidates will
+ // wait to force acquire leadership. This is measured against time of
+ // last observed ack. Default is 15 seconds.
+ LeaseDuration *time.Duration
+ // RenewDeadline is the duration that the acting controlplane will retry
+ // refreshing leadership before giving up. Default is 10 seconds.
+ RenewDeadline *time.Duration
+ // RetryPeriod is the duration the LeaderElector clients should wait
+ // between tries of actions. Default is 2 seconds.
+ RetryPeriod *time.Duration
+
+ // Namespace if specified restricts the manager's cache to watch objects in
+ // the desired namespace Defaults to all namespaces
+ //
+ // Note: If a namespace is specified, controllers can still Watch for a
+ // cluster-scoped resource (e.g Node). For namespaced resources the cache
+ // will only hold objects from the desired namespace.
+ Namespace string
+
+ // MetricsBindAddress is the TCP address that the controller should bind to
+ // for serving prometheus metrics.
+ // It can be set to "0" to disable the metrics serving.
+ MetricsBindAddress string
+
+ // HealthProbeBindAddress is the TCP address that the controller should bind to
+ // for serving health probes
+ HealthProbeBindAddress string
+
+ // Readiness probe endpoint name, defaults to "readyz"
+ ReadinessEndpointName string
+
+ // Liveness probe endpoint name, defaults to "healthz"
+ LivenessEndpointName string
+
+ // Port is the port that the webhook server serves at.
+ // It is used to set webhook.Server.Port if WebhookServer is not set.
+ Port int
+ // Host is the hostname that the webhook server binds to.
+ // It is used to set webhook.Server.Host if WebhookServer is not set.
+ 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. The server key and certificate
+ // must be named tls.key and tls.crt, respectively.
+ // It is used to set webhook.Server.CertDir if WebhookServer is not set.
+ CertDir string
+
+ // WebhookServer is an externally configured webhook.Server. By default,
+ // a Manager will create a default server using Port, Host, and CertDir;
+ // if this is set, the Manager will use this server instead.
+ WebhookServer *webhook.Server
+
+ // Functions to all for a user to customize the 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
+
+ // ClientDisableCacheFor tells the client that, if any cache is used, to bypass it
+ // for the given objects.
+ ClientDisableCacheFor []client.Object
+
+ // DryRunClient specifies whether the client should be configured to enforce
+ // dryRun mode.
+ DryRunClient bool
+
+ // EventBroadcaster records Events emitted by the manager and sends them to the Kubernetes API
+ // Use this to customize the event correlator and spam filter
+ //
+ // Deprecated: using this may cause goroutine leaks if the lifetime of your manager or controllers
+ // is shorter than the lifetime of your process.
+ EventBroadcaster record.EventBroadcaster
+
+ // GracefulShutdownTimeout is the duration given to runnable to stop before the manager actually returns on stop.
+ // To disable graceful shutdown, set to time.Duration(0)
+ // To use graceful shutdown without timeout, set to a negative duration, e.G. time.Duration(-1)
+ // The graceful shutdown is skipped for safety reasons in case the leader election lease is lost.
+ GracefulShutdownTimeout *time.Duration
+
+ // Controller contains global configuration options for controllers
+ // registered within this manager.
+ // +optional
+ Controller v1alpha1.ControllerConfigurationSpec
+
+ // makeBroadcaster allows deferring the creation of the broadcaster to
+ // avoid leaking goroutines if we never call Start on this manager. It also
+ // returns whether or not this is a "owned" broadcaster, and as such should be
+ // stopped with the manager.
+ makeBroadcaster intrec.EventBroadcasterProducer
+
+ // Dependency injection for testing
+ newRecorderProvider func(config *rest.Config, 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)
+ newMetricsListener func(addr string) (net.Listener, error)
+ newHealthProbeListener func(addr string) (net.Listener, error)
+}
+
+// Runnable allows a component to be started.
+// It's very important that Start blocks until
+// it's done running.
+type Runnable interface {
+ // Start starts running the component. The component will stop running
+ // when the context is closed. Start blocks until the context is closed or
+ // an error occurs.
+ Start(context.Context) error
+}
+
+// RunnableFunc implements Runnable using a function.
+// It's very important that the given function block
+// until it's done running.
+type RunnableFunc func(context.Context) error
+
+// Start implements Runnable.
+func (r RunnableFunc) Start(ctx context.Context) error {
+ return r(ctx)
+}
+
+// LeaderElectionRunnable knows if a Runnable needs to be run in the leader election mode.
+type LeaderElectionRunnable interface {
+ // NeedLeaderElection returns true if the Runnable needs to be run in the leader election mode.
+ // e.g. controllers need to be run in leader election mode, while webhook server doesn't.
+ NeedLeaderElection() bool
+}
+
+// New returns a new Manager for creating Controllers.
+func New(config *rest.Config, options Options) (Manager, error) {
+ // Set default values for options fields
+ options = setOptionsDefaults(options)
+
+ cluster, err := cluster.New(config, func(clusterOptions *cluster.Options) {
+ clusterOptions.Scheme = options.Scheme
+ clusterOptions.MapperProvider = options.MapperProvider
+ clusterOptions.Logger = options.Logger
+ clusterOptions.SyncPeriod = options.SyncPeriod
+ clusterOptions.Namespace = options.Namespace
+ clusterOptions.NewCache = options.NewCache
+ clusterOptions.NewClient = options.NewClient
+ clusterOptions.ClientDisableCacheFor = options.ClientDisableCacheFor
+ clusterOptions.DryRunClient = options.DryRunClient
+ clusterOptions.EventBroadcaster = options.EventBroadcaster //nolint:staticcheck
+ })
+ if err != nil {
+ return nil, err
+ }
+
+ // 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
+ // 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)
+ if err != nil {
+ return nil, err
+ }
+
+ // Create the resource lock to enable leader election)
+ leaderConfig := options.LeaderElectionConfig
+ if leaderConfig == nil {
+ leaderConfig = rest.CopyConfig(config)
+ }
+ resourceLock, err := options.newResourceLock(leaderConfig, recorderProvider, leaderelection.Options{
+ LeaderElection: options.LeaderElection,
+ LeaderElectionResourceLock: options.LeaderElectionResourceLock,
+ LeaderElectionID: options.LeaderElectionID,
+ LeaderElectionNamespace: options.LeaderElectionNamespace,
+ })
+ if err != nil {
+ return nil, err
+ }
+
+ // Create the metrics listener. This will throw an error if the metrics bind
+ // address is invalid or already in use.
+ metricsListener, err := options.newMetricsListener(options.MetricsBindAddress)
+ if err != nil {
+ return nil, err
+ }
+
+ // By default we have no extra endpoints to expose on metrics http server.
+ metricsExtraHandlers := make(map[string]http.Handler)
+
+ // Create health probes listener. This will throw an error if the bind
+ // address is invalid or already in use.
+ healthProbeListener, err := options.newHealthProbeListener(options.HealthProbeBindAddress)
+ if err != nil {
+ return nil, err
+ }
+
+ return &controllerManager{
+ cluster: cluster,
+ recorderProvider: recorderProvider,
+ resourceLock: resourceLock,
+ metricsListener: metricsListener,
+ metricsExtraHandlers: metricsExtraHandlers,
+ controllerOptions: options.Controller,
+ logger: options.Logger,
+ elected: make(chan struct{}),
+ port: options.Port,
+ host: options.Host,
+ certDir: options.CertDir,
+ webhookServer: options.WebhookServer,
+ leaseDuration: *options.LeaseDuration,
+ renewDeadline: *options.RenewDeadline,
+ retryPeriod: *options.RetryPeriod,
+ healthProbeListener: healthProbeListener,
+ readinessEndpointName: options.ReadinessEndpointName,
+ livenessEndpointName: options.LivenessEndpointName,
+ gracefulShutdownTimeout: *options.GracefulShutdownTimeout,
+ internalProceduresStop: make(chan struct{}),
+ leaderElectionStopped: make(chan struct{}),
+ leaderElectionReleaseOnCancel: options.LeaderElectionReleaseOnCancel,
+ }, nil
+}
+
+// AndFrom will use a supplied type and convert to Options
+// any options already set on Options will be ignored, this is used to allow
+// cli flags to override anything specified in the config file.
+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()
+ if err != nil {
+ return o, err
+ }
+
+ o = o.setLeaderElectionConfig(newObj)
+
+ if o.SyncPeriod == nil && newObj.SyncPeriod != nil {
+ o.SyncPeriod = &newObj.SyncPeriod.Duration
+ }
+
+ if o.Namespace == "" && newObj.CacheNamespace != "" {
+ o.Namespace = newObj.CacheNamespace
+ }
+
+ if o.MetricsBindAddress == "" && newObj.Metrics.BindAddress != "" {
+ o.MetricsBindAddress = newObj.Metrics.BindAddress
+ }
+
+ if o.HealthProbeBindAddress == "" && newObj.Health.HealthProbeBindAddress != "" {
+ o.HealthProbeBindAddress = newObj.Health.HealthProbeBindAddress
+ }
+
+ if o.ReadinessEndpointName == "" && newObj.Health.ReadinessEndpointName != "" {
+ o.ReadinessEndpointName = newObj.Health.ReadinessEndpointName
+ }
+
+ if o.LivenessEndpointName == "" && newObj.Health.LivenessEndpointName != "" {
+ o.LivenessEndpointName = newObj.Health.LivenessEndpointName
+ }
+
+ if o.Port == 0 && newObj.Webhook.Port != nil {
+ o.Port = *newObj.Webhook.Port
+ }
+
+ if o.Host == "" && newObj.Webhook.Host != "" {
+ o.Host = newObj.Webhook.Host
+ }
+
+ if o.CertDir == "" && newObj.Webhook.CertDir != "" {
+ o.CertDir = newObj.Webhook.CertDir
+ }
+
+ if newObj.Controller != nil {
+ if o.Controller.CacheSyncTimeout == nil && newObj.Controller.CacheSyncTimeout != nil {
+ o.Controller.CacheSyncTimeout = newObj.Controller.CacheSyncTimeout
+ }
+
+ if len(o.Controller.GroupKindConcurrency) == 0 && len(newObj.Controller.GroupKindConcurrency) > 0 {
+ o.Controller.GroupKindConcurrency = newObj.Controller.GroupKindConcurrency
+ }
+ }
+
+ return o, nil
+}
+
+// AndFromOrDie will use options.AndFrom() and will panic if there are errors.
+func (o Options) AndFromOrDie(loader config.ControllerManagerConfiguration) Options {
+ o, err := o.AndFrom(loader)
+ if err != nil {
+ panic(fmt.Sprintf("could not parse config file: %v", err))
+ }
+ return o
+}
+
+func (o Options) setLeaderElectionConfig(obj v1alpha1.ControllerManagerConfigurationSpec) Options {
+ if !o.LeaderElection && obj.LeaderElection.LeaderElect != nil {
+ o.LeaderElection = *obj.LeaderElection.LeaderElect
+ }
+
+ if o.LeaderElectionResourceLock == "" && obj.LeaderElection.ResourceLock != "" {
+ o.LeaderElectionResourceLock = obj.LeaderElection.ResourceLock
+ }
+
+ if o.LeaderElectionNamespace == "" && obj.LeaderElection.ResourceNamespace != "" {
+ o.LeaderElectionNamespace = obj.LeaderElection.ResourceNamespace
+ }
+
+ if o.LeaderElectionID == "" && obj.LeaderElection.ResourceName != "" {
+ o.LeaderElectionID = obj.LeaderElection.ResourceName
+ }
+
+ if o.LeaseDuration == nil && !reflect.DeepEqual(obj.LeaderElection.LeaseDuration, metav1.Duration{}) {
+ o.LeaseDuration = &obj.LeaderElection.LeaseDuration.Duration
+ }
+
+ if o.RenewDeadline == nil && !reflect.DeepEqual(obj.LeaderElection.RenewDeadline, metav1.Duration{}) {
+ o.RenewDeadline = &obj.LeaderElection.RenewDeadline.Duration
+ }
+
+ if o.RetryPeriod == nil && !reflect.DeepEqual(obj.LeaderElection.RetryPeriod, metav1.Duration{}) {
+ o.RetryPeriod = &obj.LeaderElection.RetryPeriod.Duration
+ }
+
+ return o
+}
+
+// defaultHealthProbeListener creates the default health probes listener bound to the given address.
+func defaultHealthProbeListener(addr string) (net.Listener, error) {
+ if addr == "" || addr == "0" {
+ return nil, nil
+ }
+
+ ln, err := net.Listen("tcp", addr)
+ if err != nil {
+ return nil, fmt.Errorf("error listening on %s: %v", addr, err)
+ }
+ return ln, nil
+}
+
+// setOptionsDefaults set default values for Options fields.
+func setOptionsDefaults(options Options) Options {
+ // Allow newResourceLock to be mocked
+ if options.newResourceLock == nil {
+ options.newResourceLock = leaderelection.NewResourceLock
+ }
+
+ // Allow newRecorderProvider to be mocked
+ if options.newRecorderProvider == nil {
+ options.newRecorderProvider = intrec.NewProvider
+ }
+
+ // This is duplicated with pkg/cluster, we need it here
+ // for the leader election and there to provide the user with
+ // an EventBroadcaster
+ if options.EventBroadcaster == nil {
+ // defer initialization to avoid leaking by default
+ options.makeBroadcaster = func() (record.EventBroadcaster, bool) {
+ return record.NewBroadcaster(), true
+ }
+ } else {
+ options.makeBroadcaster = func() (record.EventBroadcaster, bool) {
+ return options.EventBroadcaster, false
+ }
+ }
+
+ if options.newMetricsListener == nil {
+ options.newMetricsListener = metrics.NewListener
+ }
+ leaseDuration, renewDeadline, retryPeriod := defaultLeaseDuration, defaultRenewDeadline, defaultRetryPeriod
+ if options.LeaseDuration == nil {
+ options.LeaseDuration = &leaseDuration
+ }
+
+ if options.RenewDeadline == nil {
+ options.RenewDeadline = &renewDeadline
+ }
+
+ if options.RetryPeriod == nil {
+ options.RetryPeriod = &retryPeriod
+ }
+
+ if options.ReadinessEndpointName == "" {
+ options.ReadinessEndpointName = defaultReadinessEndpoint
+ }
+
+ if options.LivenessEndpointName == "" {
+ options.LivenessEndpointName = defaultLivenessEndpoint
+ }
+
+ if options.newHealthProbeListener == nil {
+ options.newHealthProbeListener = defaultHealthProbeListener
+ }
+
+ if options.GracefulShutdownTimeout == nil {
+ gracefulShutdownTimeout := defaultGracefulShutdownPeriod
+ options.GracefulShutdownTimeout = &gracefulShutdownTimeout
+ }
+
+ if options.Logger == nil {
+ options.Logger = log.Log
+ }
+
+ return options
+}
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/manager/signals/doc.go b/vendor/sigs.k8s.io/controller-runtime/pkg/manager/signals/doc.go
new file mode 100644
index 000000000..737cc7eff
--- /dev/null
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/manager/signals/doc.go
@@ -0,0 +1,20 @@
+/*
+Copyright 2017 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 signals contains libraries for handling signals to gracefully
+// shutdown the manager in combination with Kubernetes pod graceful termination
+// policy.
+package signals
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/manager/signals/signal.go b/vendor/sigs.k8s.io/controller-runtime/pkg/manager/signals/signal.go
new file mode 100644
index 000000000..9a85558f8
--- /dev/null
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/manager/signals/signal.go
@@ -0,0 +1,45 @@
+/*
+Copyright 2017 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 signals
+
+import (
+ "context"
+ "os"
+ "os/signal"
+)
+
+var onlyOneSignalHandler = make(chan struct{})
+
+// SetupSignalHandler registers for SIGTERM and SIGINT. A stop channel is returned
+// which is closed on one of these signals. If a second signal is caught, the program
+// is terminated with exit code 1.
+func SetupSignalHandler() context.Context {
+ close(onlyOneSignalHandler) // panics when called twice
+
+ ctx, cancel := context.WithCancel(context.Background())
+
+ c := make(chan os.Signal, 2)
+ signal.Notify(c, shutdownSignals...)
+ go func() {
+ <-c
+ cancel()
+ <-c
+ os.Exit(1) // second signal. Exit directly.
+ }()
+
+ return ctx
+}
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/manager/signals/signal_posix.go b/vendor/sigs.k8s.io/controller-runtime/pkg/manager/signals/signal_posix.go
new file mode 100644
index 000000000..9bdb4e741
--- /dev/null
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/manager/signals/signal_posix.go
@@ -0,0 +1,26 @@
+// +build !windows
+
+/*
+Copyright 2017 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 signals
+
+import (
+ "os"
+ "syscall"
+)
+
+var shutdownSignals = []os.Signal{os.Interrupt, syscall.SIGTERM}
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/manager/signals/signal_windows.go b/vendor/sigs.k8s.io/controller-runtime/pkg/manager/signals/signal_windows.go
new file mode 100644
index 000000000..4907d573f
--- /dev/null
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/manager/signals/signal_windows.go
@@ -0,0 +1,23 @@
+/*
+Copyright 2017 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 signals
+
+import (
+ "os"
+)
+
+var shutdownSignals = []os.Signal{os.Interrupt}
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/metrics/client_go_adapter.go b/vendor/sigs.k8s.io/controller-runtime/pkg/metrics/client_go_adapter.go
new file mode 100644
index 000000000..d32ce2534
--- /dev/null
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/metrics/client_go_adapter.go
@@ -0,0 +1,231 @@
+/*
+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 metrics
+
+import (
+ "context"
+ "net/url"
+ "time"
+
+ "github.com/prometheus/client_golang/prometheus"
+ reflectormetrics "k8s.io/client-go/tools/cache"
+ clientmetrics "k8s.io/client-go/tools/metrics"
+)
+
+// this file contains setup logic to initialize the myriad of places
+// that client-go registers metrics. We copy the names and formats
+// 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"
+)
+
+// Metrics subsystem and all keys used by the reflectors.
+const (
+ ReflectorSubsystem = "reflector"
+ ListsTotalKey = "lists_total"
+ ListsDurationKey = "list_duration_seconds"
+ ItemsPerListKey = "items_per_list"
+ WatchesTotalKey = "watches_total"
+ ShortWatchesTotalKey = "short_watches_total"
+ WatchDurationKey = "watch_duration_seconds"
+ ItemsPerWatchKey = "items_per_watch"
+ LastResourceVersionKey = "last_resource_version"
+)
+
+var (
+ // 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"})
+
+ requestResult = prometheus.NewCounterVec(prometheus.CounterOpts{
+ Subsystem: RestClientSubsystem,
+ Name: ResultKey,
+ Help: "Number of HTTP requests, partitioned by status code, method, and host.",
+ }, []string{"code", "method", "host"})
+
+ // reflector metrics.
+
+ // TODO(directxman12): update these to be histograms once the metrics overhaul KEP
+ // PRs start landing.
+
+ listsTotal = prometheus.NewCounterVec(prometheus.CounterOpts{
+ Subsystem: ReflectorSubsystem,
+ Name: ListsTotalKey,
+ Help: "Total number of API lists done by the reflectors",
+ }, []string{"name"})
+
+ listsDuration = prometheus.NewSummaryVec(prometheus.SummaryOpts{
+ Subsystem: ReflectorSubsystem,
+ Name: ListsDurationKey,
+ Help: "How long an API list takes to return and decode for the reflectors",
+ }, []string{"name"})
+
+ itemsPerList = prometheus.NewSummaryVec(prometheus.SummaryOpts{
+ Subsystem: ReflectorSubsystem,
+ Name: ItemsPerListKey,
+ Help: "How many items an API list returns to the reflectors",
+ }, []string{"name"})
+
+ watchesTotal = prometheus.NewCounterVec(prometheus.CounterOpts{
+ Subsystem: ReflectorSubsystem,
+ Name: WatchesTotalKey,
+ Help: "Total number of API watches done by the reflectors",
+ }, []string{"name"})
+
+ shortWatchesTotal = prometheus.NewCounterVec(prometheus.CounterOpts{
+ Subsystem: ReflectorSubsystem,
+ Name: ShortWatchesTotalKey,
+ Help: "Total number of short API watches done by the reflectors",
+ }, []string{"name"})
+
+ watchDuration = prometheus.NewSummaryVec(prometheus.SummaryOpts{
+ Subsystem: ReflectorSubsystem,
+ Name: WatchDurationKey,
+ Help: "How long an API watch takes to return and decode for the reflectors",
+ }, []string{"name"})
+
+ itemsPerWatch = prometheus.NewSummaryVec(prometheus.SummaryOpts{
+ Subsystem: ReflectorSubsystem,
+ Name: ItemsPerWatchKey,
+ Help: "How many items an API watch returns to the reflectors",
+ }, []string{"name"})
+
+ lastResourceVersion = prometheus.NewGaugeVec(prometheus.GaugeOpts{
+ Subsystem: ReflectorSubsystem,
+ Name: LastResourceVersionKey,
+ Help: "Last resource version seen for the reflectors",
+ }, []string{"name"})
+)
+
+func init() {
+ registerClientMetrics()
+ registerReflectorMetrics()
+}
+
+// registerClientMetrics sets up the client latency metrics from client-go.
+func registerClientMetrics() {
+ // register the metrics with our registry
+ Registry.MustRegister(requestResult)
+
+ // register the metrics with client-go
+ clientmetrics.Register(clientmetrics.RegisterOpts{
+ RequestResult: &resultAdapter{metric: requestResult},
+ })
+}
+
+// registerReflectorMetrics sets up reflector (reconcile) loop metrics.
+func registerReflectorMetrics() {
+ Registry.MustRegister(listsTotal)
+ Registry.MustRegister(listsDuration)
+ Registry.MustRegister(itemsPerList)
+ Registry.MustRegister(watchesTotal)
+ Registry.MustRegister(shortWatchesTotal)
+ Registry.MustRegister(watchDuration)
+ Registry.MustRegister(itemsPerWatch)
+ Registry.MustRegister(lastResourceVersion)
+
+ reflectormetrics.SetReflectorMetricsProvider(reflectorMetricsProvider{})
+}
+
+// this section contains adapters, implementations, and other sundry organic, artisanally
+// hand-crafted syntax trees required to convince client-go that it actually wants to let
+// someone use its metrics.
+
+// Client metrics adapters (method #1 for client-go metrics),
+// copied (more-or-less directly) from k8s.io/kubernetes setup code
+// (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 resultAdapter struct {
+ metric *prometheus.CounterVec
+}
+
+func (r *resultAdapter) Increment(_ context.Context, code, method, host string) {
+ r.metric.WithLabelValues(code, method, host).Inc()
+}
+
+// Reflector metrics provider (method #2 for client-go metrics),
+// copied (more-or-less directly) from k8s.io/kubernetes setup code
+// (which isn't anywhere in an easily-importable place).
+
+type reflectorMetricsProvider struct{}
+
+func (reflectorMetricsProvider) NewListsMetric(name string) reflectormetrics.CounterMetric {
+ return listsTotal.WithLabelValues(name)
+}
+
+func (reflectorMetricsProvider) NewListDurationMetric(name string) reflectormetrics.SummaryMetric {
+ return listsDuration.WithLabelValues(name)
+}
+
+func (reflectorMetricsProvider) NewItemsInListMetric(name string) reflectormetrics.SummaryMetric {
+ return itemsPerList.WithLabelValues(name)
+}
+
+func (reflectorMetricsProvider) NewWatchesMetric(name string) reflectormetrics.CounterMetric {
+ return watchesTotal.WithLabelValues(name)
+}
+
+func (reflectorMetricsProvider) NewShortWatchesMetric(name string) reflectormetrics.CounterMetric {
+ return shortWatchesTotal.WithLabelValues(name)
+}
+
+func (reflectorMetricsProvider) NewWatchDurationMetric(name string) reflectormetrics.SummaryMetric {
+ return watchDuration.WithLabelValues(name)
+}
+
+func (reflectorMetricsProvider) NewItemsInWatchMetric(name string) reflectormetrics.SummaryMetric {
+ return itemsPerWatch.WithLabelValues(name)
+}
+
+func (reflectorMetricsProvider) NewLastResourceVersionMetric(name string) reflectormetrics.GaugeMetric {
+ return lastResourceVersion.WithLabelValues(name)
+}
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/metrics/doc.go b/vendor/sigs.k8s.io/controller-runtime/pkg/metrics/doc.go
new file mode 100644
index 000000000..6ed9df951
--- /dev/null
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/metrics/doc.go
@@ -0,0 +1,20 @@
+/*
+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 metrics contains controller related metrics utilities
+*/
+package metrics
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/metrics/listener.go b/vendor/sigs.k8s.io/controller-runtime/pkg/metrics/listener.go
new file mode 100644
index 000000000..123d8c15f
--- /dev/null
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/metrics/listener.go
@@ -0,0 +1,52 @@
+/*
+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 metrics
+
+import (
+ "fmt"
+ "net"
+
+ logf "sigs.k8s.io/controller-runtime/pkg/internal/log"
+)
+
+var log = logf.RuntimeLog.WithName("metrics")
+
+// DefaultBindAddress sets the default bind address for the metrics listener
+// The metrics is on by default.
+var DefaultBindAddress = ":8080"
+
+// NewListener creates a new TCP listener bound to the given address.
+func NewListener(addr string) (net.Listener, error) {
+ if addr == "" {
+ // If the metrics bind address is empty, default to ":8080"
+ addr = DefaultBindAddress
+ }
+
+ // Add a case to disable metrics altogether
+ if addr == "0" {
+ return nil, nil
+ }
+
+ log.Info("Metrics server is starting to listen", "addr", addr)
+ ln, err := net.Listen("tcp", addr)
+ if err != nil {
+ er := fmt.Errorf("error listening on %s: %w", addr, err)
+ log.Error(er, "metrics server failed to listen. You may want to disable the metrics server or use another port if it is due to conflicts")
+ return nil, er
+ }
+ return ln, nil
+}
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/metrics/registry.go b/vendor/sigs.k8s.io/controller-runtime/pkg/metrics/registry.go
new file mode 100644
index 000000000..ce17124d5
--- /dev/null
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/metrics/registry.go
@@ -0,0 +1,30 @@
+/*
+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 metrics
+
+import "github.com/prometheus/client_golang/prometheus"
+
+// RegistererGatherer combines both parts of the API of a Prometheus
+// registry, both the Registerer and the Gatherer interfaces.
+type RegistererGatherer interface {
+ prometheus.Registerer
+ prometheus.Gatherer
+}
+
+// Registry is a prometheus registry for storing metrics within the
+// controller-runtime.
+var Registry RegistererGatherer = prometheus.NewRegistry()
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/metrics/workqueue.go b/vendor/sigs.k8s.io/controller-runtime/pkg/metrics/workqueue.go
new file mode 100644
index 000000000..8ca47235d
--- /dev/null
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/metrics/workqueue.go
@@ -0,0 +1,130 @@
+/*
+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 metrics
+
+import (
+ "github.com/prometheus/client_golang/prometheus"
+ "k8s.io/client-go/util/workqueue"
+)
+
+// This file is copied and adapted from k8s.io/kubernetes/pkg/util/workqueue/prometheus
+// which registers metrics to the default prometheus Registry. We require very
+// similar functionality, but must register metrics to a different Registry.
+
+// Metrics subsystem and all keys used by the workqueue.
+const (
+ WorkQueueSubsystem = "workqueue"
+ DepthKey = "depth"
+ AddsKey = "adds_total"
+ QueueLatencyKey = "queue_duration_seconds"
+ WorkDurationKey = "work_duration_seconds"
+ UnfinishedWorkKey = "unfinished_work_seconds"
+ LongestRunningProcessorKey = "longest_running_processor_seconds"
+ RetriesKey = "retries_total"
+)
+
+var (
+ depth = prometheus.NewGaugeVec(prometheus.GaugeOpts{
+ Subsystem: WorkQueueSubsystem,
+ Name: DepthKey,
+ Help: "Current depth of workqueue",
+ }, []string{"name"})
+
+ adds = prometheus.NewCounterVec(prometheus.CounterOpts{
+ Subsystem: WorkQueueSubsystem,
+ Name: AddsKey,
+ Help: "Total number of adds handled by workqueue",
+ }, []string{"name"})
+
+ latency = prometheus.NewHistogramVec(prometheus.HistogramOpts{
+ Subsystem: WorkQueueSubsystem,
+ Name: QueueLatencyKey,
+ Help: "How long in seconds an item stays in workqueue before being requested",
+ Buckets: prometheus.ExponentialBuckets(10e-9, 10, 10),
+ }, []string{"name"})
+
+ workDuration = prometheus.NewHistogramVec(prometheus.HistogramOpts{
+ Subsystem: WorkQueueSubsystem,
+ Name: WorkDurationKey,
+ Help: "How long in seconds processing an item from workqueue takes.",
+ Buckets: prometheus.ExponentialBuckets(10e-9, 10, 10),
+ }, []string{"name"})
+
+ unfinished = prometheus.NewGaugeVec(prometheus.GaugeOpts{
+ Subsystem: WorkQueueSubsystem,
+ Name: UnfinishedWorkKey,
+ Help: "How many seconds of work has been done that " +
+ "is in progress and hasn't been observed by work_duration. Large " +
+ "values indicate stuck threads. One can deduce the number of stuck " +
+ "threads by observing the rate at which this increases.",
+ }, []string{"name"})
+
+ longestRunningProcessor = prometheus.NewGaugeVec(prometheus.GaugeOpts{
+ Subsystem: WorkQueueSubsystem,
+ Name: LongestRunningProcessorKey,
+ Help: "How many seconds has the longest running " +
+ "processor for workqueue been running.",
+ }, []string{"name"})
+
+ retries = prometheus.NewCounterVec(prometheus.CounterOpts{
+ Subsystem: WorkQueueSubsystem,
+ Name: RetriesKey,
+ Help: "Total number of retries handled by workqueue",
+ }, []string{"name"})
+)
+
+func init() {
+ Registry.MustRegister(depth)
+ Registry.MustRegister(adds)
+ Registry.MustRegister(latency)
+ Registry.MustRegister(workDuration)
+ Registry.MustRegister(unfinished)
+ Registry.MustRegister(longestRunningProcessor)
+ Registry.MustRegister(retries)
+
+ workqueue.SetProvider(workqueueMetricsProvider{})
+}
+
+type workqueueMetricsProvider struct{}
+
+func (workqueueMetricsProvider) NewDepthMetric(name string) workqueue.GaugeMetric {
+ return depth.WithLabelValues(name)
+}
+
+func (workqueueMetricsProvider) NewAddsMetric(name string) workqueue.CounterMetric {
+ return adds.WithLabelValues(name)
+}
+
+func (workqueueMetricsProvider) NewLatencyMetric(name string) workqueue.HistogramMetric {
+ return latency.WithLabelValues(name)
+}
+
+func (workqueueMetricsProvider) NewWorkDurationMetric(name string) workqueue.HistogramMetric {
+ return workDuration.WithLabelValues(name)
+}
+
+func (workqueueMetricsProvider) NewUnfinishedWorkSecondsMetric(name string) workqueue.SettableGaugeMetric {
+ return unfinished.WithLabelValues(name)
+}
+
+func (workqueueMetricsProvider) NewLongestRunningProcessorSecondsMetric(name string) workqueue.SettableGaugeMetric {
+ return longestRunningProcessor.WithLabelValues(name)
+}
+
+func (workqueueMetricsProvider) NewRetriesMetric(name string) workqueue.CounterMetric {
+ return retries.WithLabelValues(name)
+}
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/predicate/doc.go b/vendor/sigs.k8s.io/controller-runtime/pkg/predicate/doc.go
new file mode 100644
index 000000000..e498107ef
--- /dev/null
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/predicate/doc.go
@@ -0,0 +1,20 @@
+/*
+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 predicate defines Predicates used by Controllers to filter Events before they are provided to EventHandlers.
+*/
+package predicate
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/predicate/predicate.go b/vendor/sigs.k8s.io/controller-runtime/pkg/predicate/predicate.go
new file mode 100644
index 000000000..fc59d89ba
--- /dev/null
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/predicate/predicate.go
@@ -0,0 +1,333 @@
+/*
+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 predicate
+
+import (
+ "reflect"
+
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ "k8s.io/apimachinery/pkg/labels"
+ "sigs.k8s.io/controller-runtime/pkg/client"
+ "sigs.k8s.io/controller-runtime/pkg/event"
+ logf "sigs.k8s.io/controller-runtime/pkg/internal/log"
+)
+
+var log = logf.RuntimeLog.WithName("predicate").WithName("eventFilters")
+
+// Predicate filters events before enqueuing the keys.
+type Predicate interface {
+ // Create returns true if the Create event should be processed
+ Create(event.CreateEvent) bool
+
+ // Delete returns true if the Delete event should be processed
+ Delete(event.DeleteEvent) bool
+
+ // Update returns true if the Update event should be processed
+ Update(event.UpdateEvent) bool
+
+ // Generic returns true if the Generic event should be processed
+ Generic(event.GenericEvent) bool
+}
+
+var _ Predicate = Funcs{}
+var _ Predicate = ResourceVersionChangedPredicate{}
+var _ Predicate = GenerationChangedPredicate{}
+var _ Predicate = AnnotationChangedPredicate{}
+var _ Predicate = or{}
+var _ Predicate = and{}
+
+// Funcs is a function that implements Predicate.
+type Funcs struct {
+ // Create returns true if the Create event should be processed
+ CreateFunc func(event.CreateEvent) bool
+
+ // Delete returns true if the Delete event should be processed
+ DeleteFunc func(event.DeleteEvent) bool
+
+ // Update returns true if the Update event should be processed
+ UpdateFunc func(event.UpdateEvent) bool
+
+ // Generic returns true if the Generic event should be processed
+ GenericFunc func(event.GenericEvent) bool
+}
+
+// Create implements Predicate.
+func (p Funcs) Create(e event.CreateEvent) bool {
+ if p.CreateFunc != nil {
+ return p.CreateFunc(e)
+ }
+ return true
+}
+
+// Delete implements Predicate.
+func (p Funcs) Delete(e event.DeleteEvent) bool {
+ if p.DeleteFunc != nil {
+ return p.DeleteFunc(e)
+ }
+ return true
+}
+
+// Update implements Predicate.
+func (p Funcs) Update(e event.UpdateEvent) bool {
+ if p.UpdateFunc != nil {
+ return p.UpdateFunc(e)
+ }
+ return true
+}
+
+// Generic implements Predicate.
+func (p Funcs) Generic(e event.GenericEvent) bool {
+ if p.GenericFunc != nil {
+ return p.GenericFunc(e)
+ }
+ return true
+}
+
+// NewPredicateFuncs returns a predicate funcs that applies the given filter function
+// on CREATE, UPDATE, DELETE and GENERIC events. For UPDATE events, the filter is applied
+// to the new object.
+func NewPredicateFuncs(filter func(object client.Object) bool) Funcs {
+ return Funcs{
+ CreateFunc: func(e event.CreateEvent) bool {
+ return filter(e.Object)
+ },
+ UpdateFunc: func(e event.UpdateEvent) bool {
+ return filter(e.ObjectNew)
+ },
+ DeleteFunc: func(e event.DeleteEvent) bool {
+ return filter(e.Object)
+ },
+ GenericFunc: func(e event.GenericEvent) bool {
+ return filter(e.Object)
+ },
+ }
+}
+
+// ResourceVersionChangedPredicate implements a default update predicate function on resource version change.
+type ResourceVersionChangedPredicate struct {
+ Funcs
+}
+
+// Update implements default UpdateEvent filter for validating resource version change.
+func (ResourceVersionChangedPredicate) Update(e event.UpdateEvent) bool {
+ if e.ObjectOld == nil {
+ log.Error(nil, "Update event has no old object to update", "event", e)
+ return false
+ }
+ if e.ObjectNew == nil {
+ log.Error(nil, "Update event has no new object to update", "event", e)
+ return false
+ }
+
+ return e.ObjectNew.GetResourceVersion() != e.ObjectOld.GetResourceVersion()
+}
+
+// GenerationChangedPredicate implements a default update predicate function on Generation change.
+//
+// This predicate will skip update events that have no change in the object's metadata.generation field.
+// The metadata.generation field of an object is incremented by the API server when writes are made to the spec field of an object.
+// This allows a controller to ignore update events where the spec is unchanged, and only the metadata and/or status fields are changed.
+//
+// For CustomResource objects the Generation is only incremented when the status subresource is enabled.
+//
+// Caveats:
+//
+// * The assumption that the Generation is incremented only on writing to the spec does not hold for all APIs.
+// E.g For Deployment objects the Generation is also incremented on writes to the metadata.annotations field.
+// For object types other than CustomResources be sure to verify which fields will trigger a Generation increment when they are written to.
+//
+// * With this predicate, any update events with writes only to the status field will not be reconciled.
+// So in the event that the status block is overwritten or wiped by someone else the controller will not self-correct to restore the correct status.
+type GenerationChangedPredicate struct {
+ Funcs
+}
+
+// Update implements default UpdateEvent filter for validating generation change.
+func (GenerationChangedPredicate) Update(e event.UpdateEvent) bool {
+ if e.ObjectOld == nil {
+ log.Error(nil, "Update event has no old object to update", "event", e)
+ return false
+ }
+ if e.ObjectNew == nil {
+ log.Error(nil, "Update event has no new object for update", "event", e)
+ return false
+ }
+
+ return e.ObjectNew.GetGeneration() != e.ObjectOld.GetGeneration()
+}
+
+// AnnotationChangedPredicate implements a default update predicate function on annotation change.
+//
+// This predicate will skip update events that have no change in the object's annotation.
+// It is intended to be used in conjunction with the GenerationChangedPredicate, as in the following example:
+//
+// Controller.Watch(
+// &source.Kind{Type: v1.MyCustomKind},
+// &handler.EnqueueRequestForObject{},
+// predicate.Or(predicate.GenerationChangedPredicate{}, predicate.AnnotationChangedPredicate{}))
+//
+// This is mostly useful for controllers that needs to trigger both when the resource's generation is incremented
+// (i.e., when the resource' .spec changes), or an annotation changes (e.g., for a staging/alpha API).
+type AnnotationChangedPredicate struct {
+ Funcs
+}
+
+// Update implements default UpdateEvent filter for validating annotation change.
+func (AnnotationChangedPredicate) Update(e event.UpdateEvent) bool {
+ if e.ObjectOld == nil {
+ log.Error(nil, "Update event has no old object to update", "event", e)
+ return false
+ }
+ if e.ObjectNew == nil {
+ log.Error(nil, "Update event has no new object for update", "event", e)
+ return false
+ }
+
+ return !reflect.DeepEqual(e.ObjectNew.GetAnnotations(), e.ObjectOld.GetAnnotations())
+}
+
+// LabelChangedPredicate implements a default update predicate function on label change.
+//
+// This predicate will skip update events that have no change in the object's label.
+// It is intended to be used in conjunction with the GenerationChangedPredicate, as in the following example:
+//
+// Controller.Watch(
+// &source.Kind{Type: v1.MyCustomKind},
+// &handler.EnqueueRequestForObject{},
+// predicate.Or(predicate.GenerationChangedPredicate{}, predicate.LabelChangedPredicate{}))
+//
+// This will be helpful when object's labels is carrying some extra specification information beyond object's spec,
+// and the controller will be triggered if any valid spec change (not only in spec, but also in labels) happens.
+type LabelChangedPredicate struct {
+ Funcs
+}
+
+// Update implements default UpdateEvent filter for checking label change.
+func (LabelChangedPredicate) Update(e event.UpdateEvent) bool {
+ if e.ObjectOld == nil {
+ log.Error(nil, "Update event has no old object to update", "event", e)
+ return false
+ }
+ if e.ObjectNew == nil {
+ log.Error(nil, "Update event has no new object for update", "event", e)
+ return false
+ }
+
+ return !reflect.DeepEqual(e.ObjectNew.GetLabels(), e.ObjectOld.GetLabels())
+}
+
+// And returns a composite predicate that implements a logical AND of the predicates passed to it.
+func And(predicates ...Predicate) Predicate {
+ return and{predicates}
+}
+
+type and struct {
+ predicates []Predicate
+}
+
+func (a and) Create(e event.CreateEvent) bool {
+ for _, p := range a.predicates {
+ if !p.Create(e) {
+ return false
+ }
+ }
+ return true
+}
+
+func (a and) Update(e event.UpdateEvent) bool {
+ for _, p := range a.predicates {
+ if !p.Update(e) {
+ return false
+ }
+ }
+ return true
+}
+
+func (a and) Delete(e event.DeleteEvent) bool {
+ for _, p := range a.predicates {
+ if !p.Delete(e) {
+ return false
+ }
+ }
+ return true
+}
+
+func (a and) Generic(e event.GenericEvent) bool {
+ for _, p := range a.predicates {
+ if !p.Generic(e) {
+ return false
+ }
+ }
+ return true
+}
+
+// Or returns a composite predicate that implements a logical OR of the predicates passed to it.
+func Or(predicates ...Predicate) Predicate {
+ return or{predicates}
+}
+
+type or struct {
+ predicates []Predicate
+}
+
+func (o or) Create(e event.CreateEvent) bool {
+ for _, p := range o.predicates {
+ if p.Create(e) {
+ return true
+ }
+ }
+ return false
+}
+
+func (o or) Update(e event.UpdateEvent) bool {
+ for _, p := range o.predicates {
+ if p.Update(e) {
+ return true
+ }
+ }
+ return false
+}
+
+func (o or) Delete(e event.DeleteEvent) bool {
+ for _, p := range o.predicates {
+ if p.Delete(e) {
+ return true
+ }
+ }
+ return false
+}
+
+func (o or) Generic(e event.GenericEvent) bool {
+ for _, p := range o.predicates {
+ if p.Generic(e) {
+ return true
+ }
+ }
+ return false
+}
+
+// LabelSelectorPredicate constructs a Predicate from a LabelSelector.
+// Only objects matching the LabelSelector will be admitted.
+func LabelSelectorPredicate(s metav1.LabelSelector) (Predicate, error) {
+ selector, err := metav1.LabelSelectorAsSelector(&s)
+ if err != nil {
+ return Funcs{}, err
+ }
+ return NewPredicateFuncs(func(o client.Object) bool {
+ return selector.Matches(labels.Set(o.GetLabels()))
+ }), nil
+}
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/ratelimiter/doc.go b/vendor/sigs.k8s.io/controller-runtime/pkg/ratelimiter/doc.go
new file mode 100644
index 000000000..a01d603fe
--- /dev/null
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/ratelimiter/doc.go
@@ -0,0 +1,22 @@
+/*
+Copyright 2020 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+/*
+Package ratelimiter defines rate limiters used by Controllers to limit how frequently requests may be queued.
+
+Typical rate limiters that can be used are implemented in client-go's workqueue package.
+*/
+package ratelimiter
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/ratelimiter/ratelimiter.go b/vendor/sigs.k8s.io/controller-runtime/pkg/ratelimiter/ratelimiter.go
new file mode 100644
index 000000000..565a3a227
--- /dev/null
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/ratelimiter/ratelimiter.go
@@ -0,0 +1,30 @@
+/*
+Copyright 2020 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package ratelimiter
+
+import "time"
+
+// RateLimiter is an identical interface of client-go workqueue RateLimiter.
+type RateLimiter interface {
+ // When gets an item and gets to decide how long that item should wait
+ When(item interface{}) time.Duration
+ // Forget indicates that an item is finished being retried. Doesn't matter whether its for perm failing
+ // or for success, we'll stop tracking it
+ Forget(item interface{})
+ // NumRequeues returns back how many failures the item has had
+ NumRequeues(item interface{}) int
+}
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/reconcile/doc.go b/vendor/sigs.k8s.io/controller-runtime/pkg/reconcile/doc.go
new file mode 100644
index 000000000..d221dd7b3
--- /dev/null
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/reconcile/doc.go
@@ -0,0 +1,21 @@
+/*
+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 reconcile defines the Reconciler interface to implement Kubernetes APIs. Reconciler is provided
+to Controllers at creation time as the API implementation.
+*/
+package reconcile
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/reconcile/reconcile.go b/vendor/sigs.k8s.io/controller-runtime/pkg/reconcile/reconcile.go
new file mode 100644
index 000000000..b2159c531
--- /dev/null
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/reconcile/reconcile.go
@@ -0,0 +1,102 @@
+/*
+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 reconcile
+
+import (
+ "context"
+ "time"
+
+ "k8s.io/apimachinery/pkg/types"
+)
+
+// Result contains the result of a Reconciler invocation.
+type Result struct {
+ // Requeue tells the Controller to requeue the reconcile key. Defaults to false.
+ Requeue bool
+
+ // RequeueAfter if greater than 0, tells the Controller to requeue the reconcile key after the Duration.
+ // Implies that Requeue is true, there is no need to set Requeue to true at the same time as RequeueAfter.
+ RequeueAfter time.Duration
+}
+
+// IsZero returns true if this result is empty.
+func (r *Result) IsZero() bool {
+ if r == nil {
+ return true
+ }
+ return *r == Result{}
+}
+
+// Request contains the information necessary to reconcile a Kubernetes object. This includes the
+// information to uniquely identify the object - its Name and Namespace. It does NOT contain information about
+// any specific Event or the object contents itself.
+type Request struct {
+ // NamespacedName is the name and namespace of the object to reconcile.
+ types.NamespacedName
+}
+
+/*
+Reconciler implements a Kubernetes API for a specific Resource by Creating, Updating or Deleting Kubernetes
+objects, or by making changes to systems external to the cluster (e.g. cloudproviders, github, etc).
+
+reconcile implementations compare the state specified in an object by a user against the actual cluster state,
+and then perform operations to make the actual cluster state reflect the state specified by the user.
+
+Typically, reconcile is triggered by a Controller in response to cluster Events (e.g. Creating, Updating,
+Deleting Kubernetes objects) or external Events (GitHub Webhooks, polling external sources, etc).
+
+Example reconcile Logic:
+
+ * Read an object and all the Pods it owns.
+ * Observe that the object spec specifies 5 replicas but actual cluster contains only 1 Pod replica.
+ * Create 4 Pods and set their OwnerReferences to the object.
+
+reconcile may be implemented as either a type:
+
+ type reconcile struct {}
+
+ func (reconcile) reconcile(controller.Request) (controller.Result, error) {
+ // Implement business logic of reading and writing objects here
+ return controller.Result{}, nil
+ }
+
+Or as a function:
+
+ controller.Func(func(o controller.Request) (controller.Result, error) {
+ // Implement business logic of reading and writing objects here
+ return controller.Result{}, nil
+ })
+
+Reconciliation is level-based, meaning action isn't driven off changes in individual Events, but instead is
+driven by actual cluster state read from the apiserver or a local cache.
+For example if responding to a Pod Delete Event, the Request won't contain that a Pod was deleted,
+instead the reconcile function observes this when reading the cluster state and seeing the Pod as missing.
+*/
+type Reconciler interface {
+ // Reconciler performs a full reconciliation for the object referred to by the Request.
+ // The Controller will requeue the Request to be processed again if an error is non-nil or
+ // Result.Requeue is true, otherwise upon completion it will remove the work from the queue.
+ Reconcile(context.Context, Request) (Result, error)
+}
+
+// Func is a function that implements the reconcile interface.
+type Func func(context.Context, Request) (Result, error)
+
+var _ Reconciler = Func(nil)
+
+// Reconcile implements Reconciler.
+func (r Func) Reconcile(ctx context.Context, o Request) (Result, error) { return r(ctx, o) }
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/recorder/recorder.go b/vendor/sigs.k8s.io/controller-runtime/pkg/recorder/recorder.go
new file mode 100644
index 000000000..f093f0a72
--- /dev/null
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/recorder/recorder.go
@@ -0,0 +1,31 @@
+/*
+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 recorder defines interfaces for working with Kubernetes event recorders.
+//
+// You can use these to emit Kubernetes events associated with a particular Kubernetes
+// object.
+package recorder
+
+import (
+ "k8s.io/client-go/tools/record"
+)
+
+// Provider knows how to generate new event recorders with given name.
+type Provider interface {
+ // NewRecorder returns an EventRecorder with given name.
+ GetEventRecorderFor(name string) record.EventRecorder
+}
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/runtime/inject/doc.go b/vendor/sigs.k8s.io/controller-runtime/pkg/runtime/inject/doc.go
new file mode 100644
index 000000000..17c60895f
--- /dev/null
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/runtime/inject/doc.go
@@ -0,0 +1,22 @@
+/*
+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
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/runtime/inject/inject.go b/vendor/sigs.k8s.io/controller-runtime/pkg/runtime/inject/inject.go
new file mode 100644
index 000000000..c8c56ba81
--- /dev/null
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/runtime/inject/inject.go
@@ -0,0 +1,164 @@
+/*
+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
+}
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/scheme/scheme.go b/vendor/sigs.k8s.io/controller-runtime/pkg/scheme/scheme.go
new file mode 100644
index 000000000..9dc93a9b2
--- /dev/null
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/scheme/scheme.go
@@ -0,0 +1,94 @@
+/*
+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 scheme contains utilities for gradually building Schemes,
+// which contain information associating Go types with Kubernetes
+// groups, versions, and kinds.
+//
+// Each API group should define a utility function
+// called AddToScheme for adding its types to a Scheme:
+//
+// // in package myapigroupv1...
+// var (
+// SchemeGroupVersion = schema.GroupVersion{Group: "my.api.group", Version: "v1"}
+// SchemeBuilder = &scheme.Builder{GroupVersion: SchemeGroupVersion}
+// AddToScheme = SchemeBuilder.AddToScheme
+// )
+//
+// func init() {
+// SchemeBuilder.Register(&MyType{}, &MyTypeList)
+// }
+// var (
+// scheme *runtime.Scheme = runtime.NewScheme()
+// )
+//
+// This also true of the built-in Kubernetes types. Then, in the entrypoint for
+// your manager, assemble the scheme containing exactly the types you need,
+// panicing if scheme registration failed. For instance, if our controller needs
+// types from the core/v1 API group (e.g. Pod), plus types from my.api.group/v1:
+//
+// func init() {
+// utilruntime.Must(myapigroupv1.AddToScheme(scheme))
+// utilruntime.Must(kubernetesscheme.AddToScheme(scheme))
+// }
+//
+// func main() {
+// mgr := controllers.NewManager(context.Background(), controllers.GetConfigOrDie(), manager.Options{
+// Scheme: scheme,
+// })
+// // ...
+// }
+//
+package scheme
+
+import (
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ "k8s.io/apimachinery/pkg/runtime"
+ "k8s.io/apimachinery/pkg/runtime/schema"
+)
+
+// Builder builds a new Scheme for mapping go types to Kubernetes GroupVersionKinds.
+type Builder struct {
+ GroupVersion schema.GroupVersion
+ runtime.SchemeBuilder
+}
+
+// Register adds one or more objects to the SchemeBuilder so they can be added to a Scheme. Register mutates bld.
+func (bld *Builder) Register(object ...runtime.Object) *Builder {
+ bld.SchemeBuilder.Register(func(scheme *runtime.Scheme) error {
+ scheme.AddKnownTypes(bld.GroupVersion, object...)
+ metav1.AddToGroupVersion(scheme, bld.GroupVersion)
+ return nil
+ })
+ return bld
+}
+
+// RegisterAll registers all types from the Builder argument. RegisterAll mutates bld.
+func (bld *Builder) RegisterAll(b *Builder) *Builder {
+ bld.SchemeBuilder = append(bld.SchemeBuilder, b.SchemeBuilder...)
+ return bld
+}
+
+// AddToScheme adds all registered types to s.
+func (bld *Builder) AddToScheme(s *runtime.Scheme) error {
+ return bld.SchemeBuilder.AddToScheme(s)
+}
+
+// Build returns a new Scheme containing the registered types.
+func (bld *Builder) Build() (*runtime.Scheme, error) {
+ s := runtime.NewScheme()
+ return s, bld.AddToScheme(s)
+}
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/source/doc.go b/vendor/sigs.k8s.io/controller-runtime/pkg/source/doc.go
new file mode 100644
index 000000000..31935c83c
--- /dev/null
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/source/doc.go
@@ -0,0 +1,22 @@
+/*
+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 source provides event streams to hook up to Controllers with Controller.Watch. Events are
+used with handler.EventHandlers to enqueue reconcile.Requests and trigger Reconciles for Kubernetes
+objects.
+*/
+package source
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/source/internal/eventsource.go b/vendor/sigs.k8s.io/controller-runtime/pkg/source/internal/eventsource.go
new file mode 100644
index 000000000..f0cfe212e
--- /dev/null
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/source/internal/eventsource.go
@@ -0,0 +1,138 @@
+/*
+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 (
+ "fmt"
+
+ "k8s.io/client-go/tools/cache"
+ "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/handler"
+ logf "sigs.k8s.io/controller-runtime/pkg/internal/log"
+
+ "sigs.k8s.io/controller-runtime/pkg/predicate"
+)
+
+var log = logf.RuntimeLog.WithName("source").WithName("EventHandler")
+
+var _ cache.ResourceEventHandler = EventHandler{}
+
+// EventHandler adapts a handler.EventHandler interface to a cache.ResourceEventHandler interface.
+type EventHandler struct {
+ EventHandler handler.EventHandler
+ Queue workqueue.RateLimitingInterface
+ Predicates []predicate.Predicate
+}
+
+// OnAdd creates CreateEvent and calls Create on EventHandler.
+func (e EventHandler) OnAdd(obj interface{}) {
+ c := event.CreateEvent{}
+
+ // Pull Object out of the object
+ if o, ok := obj.(client.Object); ok {
+ c.Object = o
+ } else {
+ log.Error(nil, "OnAdd missing Object",
+ "object", obj, "type", fmt.Sprintf("%T", obj))
+ return
+ }
+
+ for _, p := range e.Predicates {
+ if !p.Create(c) {
+ return
+ }
+ }
+
+ // Invoke create handler
+ e.EventHandler.Create(c, e.Queue)
+}
+
+// OnUpdate creates UpdateEvent and calls Update on EventHandler.
+func (e EventHandler) OnUpdate(oldObj, newObj interface{}) {
+ u := event.UpdateEvent{}
+
+ if o, ok := oldObj.(client.Object); ok {
+ u.ObjectOld = o
+ } else {
+ log.Error(nil, "OnUpdate missing ObjectOld",
+ "object", oldObj, "type", fmt.Sprintf("%T", oldObj))
+ return
+ }
+
+ // Pull Object out of the object
+ if o, ok := newObj.(client.Object); ok {
+ u.ObjectNew = o
+ } else {
+ log.Error(nil, "OnUpdate missing ObjectNew",
+ "object", newObj, "type", fmt.Sprintf("%T", newObj))
+ return
+ }
+
+ for _, p := range e.Predicates {
+ if !p.Update(u) {
+ return
+ }
+ }
+
+ // Invoke update handler
+ e.EventHandler.Update(u, e.Queue)
+}
+
+// OnDelete creates DeleteEvent and calls Delete on EventHandler.
+func (e EventHandler) OnDelete(obj interface{}) {
+ d := event.DeleteEvent{}
+
+ // Deal with tombstone events by pulling the object out. Tombstone events wrap the object in a
+ // DeleteFinalStateUnknown struct, so the object needs to be pulled out.
+ // Copied from sample-controller
+ // This should never happen if we aren't missing events, which we have concluded that we are not
+ // and made decisions off of this belief. Maybe this shouldn't be here?
+ var ok bool
+ if _, ok = obj.(client.Object); !ok {
+ // If the object doesn't have Metadata, assume it is a tombstone object of type DeletedFinalStateUnknown
+ tombstone, ok := obj.(cache.DeletedFinalStateUnknown)
+ if !ok {
+ log.Error(nil, "Error decoding objects. Expected cache.DeletedFinalStateUnknown",
+ "type", fmt.Sprintf("%T", obj),
+ "object", obj)
+ return
+ }
+
+ // Set obj to the tombstone obj
+ obj = tombstone.Obj
+ }
+
+ // Pull Object out of the object
+ if o, ok := obj.(client.Object); ok {
+ d.Object = o
+ } else {
+ log.Error(nil, "OnDelete missing Object",
+ "object", obj, "type", fmt.Sprintf("%T", obj))
+ return
+ }
+
+ for _, p := range e.Predicates {
+ if !p.Delete(d) {
+ return
+ }
+ }
+
+ // Invoke delete handler
+ e.EventHandler.Delete(d, e.Queue)
+}
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/source/source.go b/vendor/sigs.k8s.io/controller-runtime/pkg/source/source.go
new file mode 100644
index 000000000..8f649eaac
--- /dev/null
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/source/source.go
@@ -0,0 +1,366 @@
+/*
+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 source
+
+import (
+ "context"
+ "errors"
+ "fmt"
+ "sync"
+ "time"
+
+ "k8s.io/apimachinery/pkg/api/meta"
+ "k8s.io/apimachinery/pkg/util/wait"
+ "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/handler"
+ logf "sigs.k8s.io/controller-runtime/pkg/internal/log"
+ "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/predicate"
+)
+
+var log = logf.RuntimeLog.WithName("source")
+
+const (
+ // defaultBufferSize is the default number of event notifications that can be buffered.
+ defaultBufferSize = 1024
+)
+
+// Source is a source of events (eh.g. Create, Update, Delete operations on Kubernetes Objects, Webhook callbacks, etc)
+// which should be processed by event.EventHandlers to enqueue reconcile.Requests.
+//
+// * Use Kind for events originating in the cluster (e.g. Pod Create, Pod Update, Deployment Update).
+//
+// * Use Channel for events originating outside the cluster (eh.g. GitHub Webhook callback, Polling external urls).
+//
+// Users may build their own Source implementations. If their implementations implement any of the inject package
+// interfaces, the dependencies will be injected by the Controller when Watch is called.
+type Source interface {
+ // Start is internal and should be called only by the Controller to register an EventHandler with the Informer
+ // to enqueue reconcile.Requests.
+ Start(context.Context, handler.EventHandler, workqueue.RateLimitingInterface, ...predicate.Predicate) error
+}
+
+// SyncingSource is a source that needs syncing prior to being usable. The controller
+// will call its WaitForSync prior to starting workers.
+type SyncingSource interface {
+ Source
+ WaitForSync(ctx context.Context) error
+}
+
+// NewKindWithCache creates a Source without InjectCache, so that it is assured that the given cache is used
+// and not overwritten. It can be used to watch objects in a different cluster by passing the cache
+// from that other cluster.
+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) 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{}
+ if errors.As(lastErr, &kindMatchErr) {
+ log.Error(lastErr, "if kind is a CRD, it should be installed before calling Start",
+ "kind", kindMatchErr.GroupKind)
+ }
+ 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
+ }
+
+ i.AddEventHandler(internal.EventHandler{Queue: queue, EventHandler: handler, Predicates: prct})
+ 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()
+ 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{}
+
+// Channel is used to provide a source of events originating outside the cluster
+// (e.g. GitHub Webhook callback). Channel requires the user to wire the external
+// source (eh.g. http handler) to write GenericEvents to the underlying channel.
+type Channel struct {
+ // once ensures the event distribution goroutine will be performed only once
+ once sync.Once
+
+ // Source is the source channel to fetch GenericEvents
+ Source <-chan event.GenericEvent
+
+ // stop is to end ongoing goroutine, and close the channels
+ stop <-chan struct{}
+
+ // dest is the destination channels of the added event handlers
+ dest []chan event.GenericEvent
+
+ // DestBufferSize is the specified buffer size of dest channels.
+ // Default to 1024 if not specified.
+ DestBufferSize int
+
+ // destLock is to ensure the destination channels are safely added/removed
+ destLock sync.Mutex
+}
+
+func (cs *Channel) String() string {
+ 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.
+func (cs *Channel) Start(
+ ctx context.Context,
+ handler handler.EventHandler,
+ queue workqueue.RateLimitingInterface,
+ prct ...predicate.Predicate) error {
+ // Source should have been specified by the user.
+ if cs.Source == nil {
+ 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
+ if cs.DestBufferSize == 0 {
+ cs.DestBufferSize = defaultBufferSize
+ }
+
+ dst := make(chan event.GenericEvent, cs.DestBufferSize)
+
+ cs.destLock.Lock()
+ cs.dest = append(cs.dest, dst)
+ cs.destLock.Unlock()
+
+ cs.once.Do(func() {
+ // Distribute GenericEvents to all EventHandler / Queue pairs Watching this source
+ go cs.syncLoop(ctx)
+ })
+
+ go func() {
+ for evt := range dst {
+ shouldHandle := true
+ for _, p := range prct {
+ if !p.Generic(evt) {
+ shouldHandle = false
+ break
+ }
+ }
+
+ if shouldHandle {
+ handler.Generic(evt, queue)
+ }
+ }
+ }()
+
+ return nil
+}
+
+func (cs *Channel) doStop() {
+ cs.destLock.Lock()
+ defer cs.destLock.Unlock()
+
+ for _, dst := range cs.dest {
+ close(dst)
+ }
+}
+
+func (cs *Channel) distribute(evt event.GenericEvent) {
+ cs.destLock.Lock()
+ defer cs.destLock.Unlock()
+
+ for _, dst := range cs.dest {
+ // We cannot make it under goroutine here, or we'll meet the
+ // race condition of writing message to closed channels.
+ // To avoid blocking, the dest channels are expected to be of
+ // proper buffer size. If we still see it blocked, then
+ // the controller is thought to be in an abnormal state.
+ dst <- evt
+ }
+}
+
+func (cs *Channel) syncLoop(ctx context.Context) {
+ for {
+ select {
+ case <-ctx.Done():
+ // Close destination channels
+ cs.doStop()
+ return
+ case evt, stillOpen := <-cs.Source:
+ if !stillOpen {
+ // if the source channel is closed, we're never gonna get
+ // anything more on it, so stop & bail
+ cs.doStop()
+ return
+ }
+ cs.distribute(evt)
+ }
+ }
+}
+
+// Informer is used to provide a source of events originating inside the cluster from Watches (e.g. Pod Create).
+type Informer struct {
+ // Informer is the controller-runtime Informer
+ Informer cache.Informer
+}
+
+var _ Source = &Informer{}
+
+// Start is internal and should be called only by the Controller to register an EventHandler with the Informer
+// to enqueue reconcile.Requests.
+func (is *Informer) Start(ctx context.Context, handler handler.EventHandler, queue workqueue.RateLimitingInterface,
+ prct ...predicate.Predicate) error {
+ // Informer should have been specified by the user.
+ if is.Informer == nil {
+ return fmt.Errorf("must specify Informer.Informer")
+ }
+
+ is.Informer.AddEventHandler(internal.EventHandler{Queue: queue, EventHandler: handler, Predicates: prct})
+ return nil
+}
+
+func (is *Informer) String() string {
+ return fmt.Sprintf("informer source: %p", is.Informer)
+}
+
+var _ Source = Func(nil)
+
+// Func is a function that implements Source.
+type Func func(context.Context, handler.EventHandler, workqueue.RateLimitingInterface, ...predicate.Predicate) error
+
+// Start implements Source.
+func (f Func) Start(ctx context.Context, evt handler.EventHandler, queue workqueue.RateLimitingInterface,
+ pr ...predicate.Predicate) error {
+ return f(ctx, evt, queue, pr...)
+}
+
+func (f Func) String() string {
+ return fmt.Sprintf("func source: %p", f)
+}
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/decode.go b/vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/decode.go
new file mode 100644
index 000000000..c7cb71b75
--- /dev/null
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/decode.go
@@ -0,0 +1,72 @@
+/*
+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 admission
+
+import (
+ "fmt"
+
+ "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
+ "k8s.io/apimachinery/pkg/runtime"
+ "k8s.io/apimachinery/pkg/runtime/serializer"
+ "k8s.io/apimachinery/pkg/util/json"
+)
+
+// Decoder knows how to decode the contents of an admission
+// request into a concrete object.
+type Decoder struct {
+ codecs serializer.CodecFactory
+}
+
+// NewDecoder creates a Decoder given the runtime.Scheme.
+func NewDecoder(scheme *runtime.Scheme) (*Decoder, error) {
+ return &Decoder{codecs: serializer.NewCodecFactory(scheme)}, nil
+}
+
+// Decode decodes the inlined object in the AdmissionRequest into the passed-in runtime.Object.
+// If you want decode the OldObject in the AdmissionRequest, use DecodeRaw.
+// It errors out if req.Object.Raw is empty i.e. containing 0 raw bytes.
+func (d *Decoder) Decode(req Request, into runtime.Object) error {
+ // we error out if rawObj is an empty object.
+ if len(req.Object.Raw) == 0 {
+ return fmt.Errorf("there is no content to decode")
+ }
+ return d.DecodeRaw(req.Object, into)
+}
+
+// DecodeRaw decodes a RawExtension object into the passed-in runtime.Object.
+// It errors out if rawObj is empty i.e. containing 0 raw bytes.
+func (d *Decoder) DecodeRaw(rawObj runtime.RawExtension, into runtime.Object) error {
+ // NB(directxman12): there's a bug/weird interaction between decoders and
+ // the API server where the API server doesn't send a GVK on the embedded
+ // objects, which means the unstructured decoder refuses to decode. It
+ // also means we can't pass the unstructured directly in, since it'll try
+ // and call unstructured's special Unmarshal implementation, which calls
+ // back into that same decoder :-/
+ // See kubernetes/kubernetes#74373.
+
+ // we error out if rawObj is an empty object.
+ if len(rawObj.Raw) == 0 {
+ return fmt.Errorf("there is no content to decode")
+ }
+ if unstructuredInto, isUnstructured := into.(*unstructured.Unstructured); isUnstructured {
+ // unmarshal into unstructured's underlying object to avoid calling the decoder
+ return json.Unmarshal(rawObj.Raw, &unstructuredInto.Object)
+ }
+
+ deserializer := d.codecs.UniversalDeserializer()
+ return runtime.DecodeInto(deserializer, rawObj.Raw, into)
+}
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/defaulter.go b/vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/defaulter.go
new file mode 100644
index 000000000..0d9aa7a83
--- /dev/null
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/defaulter.go
@@ -0,0 +1,74 @@
+/*
+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 admission
+
+import (
+ "context"
+ "encoding/json"
+ "net/http"
+
+ "k8s.io/apimachinery/pkg/runtime"
+)
+
+// Defaulter defines functions for setting defaults on resources.
+type Defaulter interface {
+ runtime.Object
+ Default()
+}
+
+// DefaultingWebhookFor creates a new Webhook for Defaulting the provided type.
+func DefaultingWebhookFor(defaulter Defaulter) *Webhook {
+ return &Webhook{
+ Handler: &mutatingHandler{defaulter: defaulter},
+ }
+}
+
+type mutatingHandler struct {
+ defaulter Defaulter
+ 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.
+func (h *mutatingHandler) Handle(ctx context.Context, req Request) Response {
+ if h.defaulter == nil {
+ panic("defaulter should never be nil")
+ }
+
+ // Get the object in the request
+ obj := h.defaulter.DeepCopyObject().(Defaulter)
+ if err := h.decoder.Decode(req, obj); err != nil {
+ return Errored(http.StatusBadRequest, err)
+ }
+
+ // Default the object
+ obj.Default()
+ marshalled, err := json.Marshal(obj)
+ if err != nil {
+ return Errored(http.StatusInternalServerError, err)
+ }
+
+ // Create the patch
+ return PatchResponseFromRaw(req.Object.Raw, marshalled)
+}
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/defaulter_custom.go b/vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/defaulter_custom.go
new file mode 100644
index 000000000..a012784e4
--- /dev/null
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/defaulter_custom.go
@@ -0,0 +1,85 @@
+/*
+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 admission
+
+import (
+ "context"
+ "encoding/json"
+
+ "errors"
+ "net/http"
+
+ apierrors "k8s.io/apimachinery/pkg/api/errors"
+ "k8s.io/apimachinery/pkg/runtime"
+)
+
+// CustomDefaulter defines functions for setting defaults on resources.
+type CustomDefaulter interface {
+ Default(ctx context.Context, obj runtime.Object) error
+}
+
+// WithCustomDefaulter creates a new Webhook for a CustomDefaulter interface.
+func WithCustomDefaulter(obj runtime.Object, defaulter CustomDefaulter) *Webhook {
+ return &Webhook{
+ Handler: &defaulterForType{object: obj, defaulter: defaulter},
+ }
+}
+
+type defaulterForType struct {
+ defaulter CustomDefaulter
+ object runtime.Object
+ decoder *Decoder
+}
+
+var _ DecoderInjector = &defaulterForType{}
+
+func (h *defaulterForType) InjectDecoder(d *Decoder) error {
+ h.decoder = d
+ return nil
+}
+
+// Handle handles admission requests.
+func (h *defaulterForType) Handle(ctx context.Context, req Request) Response {
+ if h.defaulter == nil {
+ panic("defaulter should never be nil")
+ }
+ if h.object == nil {
+ panic("object should never be nil")
+ }
+
+ // Get the object in the request
+ obj := h.object.DeepCopyObject()
+ if err := h.decoder.Decode(req, obj); err != nil {
+ return Errored(http.StatusBadRequest, err)
+ }
+
+ // Default the object
+ if err := h.defaulter.Default(ctx, obj); err != nil {
+ var apiStatus apierrors.APIStatus
+ if errors.As(err, &apiStatus) {
+ return validationResponseFromStatus(false, apiStatus.Status())
+ }
+ return Denied(err.Error())
+ }
+
+ // Create the patch
+ marshalled, err := json.Marshal(obj)
+ if err != nil {
+ return Errored(http.StatusInternalServerError, err)
+ }
+ return PatchResponseFromRaw(req.Object.Raw, marshalled)
+}
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/doc.go b/vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/doc.go
new file mode 100644
index 000000000..0b274dd02
--- /dev/null
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/doc.go
@@ -0,0 +1,28 @@
+/*
+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 admission provides implementation for admission webhook and methods to implement admission webhook handlers.
+
+See examples/mutatingwebhook.go and examples/validatingwebhook.go for examples of admission webhooks.
+*/
+package admission
+
+import (
+ logf "sigs.k8s.io/controller-runtime/pkg/internal/log"
+)
+
+var log = logf.RuntimeLog.WithName("admission")
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/http.go b/vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/http.go
new file mode 100644
index 000000000..3fa8872ff
--- /dev/null
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/http.go
@@ -0,0 +1,146 @@
+/*
+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 admission
+
+import (
+ "encoding/json"
+ "errors"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "net/http"
+
+ v1 "k8s.io/api/admission/v1"
+ "k8s.io/api/admission/v1beta1"
+ "k8s.io/apimachinery/pkg/runtime"
+ "k8s.io/apimachinery/pkg/runtime/schema"
+ "k8s.io/apimachinery/pkg/runtime/serializer"
+ utilruntime "k8s.io/apimachinery/pkg/util/runtime"
+)
+
+var admissionScheme = runtime.NewScheme()
+var admissionCodecs = serializer.NewCodecFactory(admissionScheme)
+
+func init() {
+ utilruntime.Must(v1.AddToScheme(admissionScheme))
+ utilruntime.Must(v1beta1.AddToScheme(admissionScheme))
+}
+
+var _ http.Handler = &Webhook{}
+
+func (wh *Webhook) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+ var body []byte
+ var err error
+ ctx := r.Context()
+ if wh.WithContextFunc != nil {
+ ctx = wh.WithContextFunc(ctx, r)
+ }
+
+ var reviewResponse Response
+ if r.Body == nil {
+ err = errors.New("request body is empty")
+ wh.log.Error(err, "bad request")
+ reviewResponse = Errored(http.StatusBadRequest, err)
+ wh.writeResponse(w, reviewResponse)
+ return
+ }
+
+ defer r.Body.Close()
+ if body, err = ioutil.ReadAll(r.Body); err != nil {
+ wh.log.Error(err, "unable to read the body from the incoming request")
+ reviewResponse = Errored(http.StatusBadRequest, err)
+ wh.writeResponse(w, reviewResponse)
+ return
+ }
+
+ // verify the content type is accurate
+ if contentType := r.Header.Get("Content-Type"); contentType != "application/json" {
+ 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)
+ reviewResponse = Errored(http.StatusBadRequest, err)
+ wh.writeResponse(w, reviewResponse)
+ return
+ }
+
+ // Both v1 and v1beta1 AdmissionReview types are exactly the same, so the v1beta1 type can
+ // be decoded into the v1 type. However the runtime codec's decoder guesses which type to
+ // decode into by type name if an Object's TypeMeta isn't set. By setting TypeMeta of an
+ // unregistered type to the v1 GVK, the decoder will coerce a v1beta1 AdmissionReview to v1.
+ // The actual AdmissionReview GVK will be used to write a typed response in case the
+ // webhook config permits multiple versions, otherwise this response will fail.
+ req := Request{}
+ ar := unversionedAdmissionReview{}
+ // avoid an extra copy
+ ar.Request = &req.AdmissionRequest
+ ar.SetGroupVersionKind(v1.SchemeGroupVersion.WithKind("AdmissionReview"))
+ _, actualAdmRevGVK, err := admissionCodecs.UniversalDeserializer().Decode(body, nil, &ar)
+ if err != nil {
+ wh.log.Error(err, "unable to decode the request")
+ reviewResponse = Errored(http.StatusBadRequest, err)
+ wh.writeResponse(w, reviewResponse)
+ return
+ }
+ wh.log.V(1).Info("received request", "UID", req.UID, "kind", req.Kind, "resource", req.Resource)
+
+ reviewResponse = wh.Handle(ctx, req)
+ wh.writeResponseTyped(w, reviewResponse, actualAdmRevGVK)
+}
+
+// writeResponse writes response to w generically, i.e. without encoding GVK information.
+func (wh *Webhook) writeResponse(w io.Writer, response Response) {
+ wh.writeAdmissionResponse(w, v1.AdmissionReview{Response: &response.AdmissionResponse})
+}
+
+// writeResponseTyped writes response to w with GVK set to admRevGVK, which is necessary
+// if multiple AdmissionReview versions are permitted by the webhook.
+func (wh *Webhook) writeResponseTyped(w io.Writer, response Response, admRevGVK *schema.GroupVersionKind) {
+ ar := v1.AdmissionReview{
+ Response: &response.AdmissionResponse,
+ }
+ // Default to a v1 AdmissionReview, otherwise the API server may not recognize the request
+ // if multiple AdmissionReview versions are permitted by the webhook config.
+ // TODO(estroz): this should be configurable since older API servers won't know about v1.
+ if admRevGVK == nil || *admRevGVK == (schema.GroupVersionKind{}) {
+ ar.SetGroupVersionKind(v1.SchemeGroupVersion.WithKind("AdmissionReview"))
+ } else {
+ ar.SetGroupVersionKind(*admRevGVK)
+ }
+ wh.writeAdmissionResponse(w, ar)
+}
+
+// writeAdmissionResponse writes ar to w.
+func (wh *Webhook) writeAdmissionResponse(w io.Writer, ar v1.AdmissionReview) {
+ if err := json.NewEncoder(w).Encode(ar); err != nil {
+ wh.log.Error(err, "unable to encode the response")
+ wh.writeResponse(w, Errored(http.StatusInternalServerError, err))
+ } else {
+ res := ar.Response
+ if log := wh.log; log.V(1).Enabled() {
+ if res.Result != nil {
+ log = log.WithValues("code", res.Result.Code, "reason", res.Result.Reason)
+ }
+ log.V(1).Info("wrote response", "UID", res.UID, "allowed", res.Allowed)
+ }
+ }
+}
+
+// unversionedAdmissionReview is used to decode both v1 and v1beta1 AdmissionReview types.
+type unversionedAdmissionReview struct {
+ v1.AdmissionReview
+}
+
+var _ runtime.Object = &unversionedAdmissionReview{}
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/inject.go b/vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/inject.go
new file mode 100644
index 000000000..d5af0d598
--- /dev/null
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/inject.go
@@ -0,0 +1,31 @@
+/*
+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
+}
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/multi.go b/vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/multi.go
new file mode 100644
index 000000000..26900cf2e
--- /dev/null
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/multi.go
@@ -0,0 +1,147 @@
+/*
+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 admission
+
+import (
+ "context"
+ "encoding/json"
+ "fmt"
+ "net/http"
+
+ jsonpatch "gomodules.xyz/jsonpatch/v2"
+ admissionv1 "k8s.io/api/admission/v1"
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+
+ "sigs.k8s.io/controller-runtime/pkg/runtime/inject"
+)
+
+type multiMutating []Handler
+
+func (hs multiMutating) Handle(ctx context.Context, req Request) Response {
+ patches := []jsonpatch.JsonPatchOperation{}
+ for _, handler := range hs {
+ resp := handler.Handle(ctx, req)
+ if !resp.Allowed {
+ return resp
+ }
+ if resp.PatchType != nil && *resp.PatchType != admissionv1.PatchTypeJSONPatch {
+ return Errored(http.StatusInternalServerError,
+ fmt.Errorf("unexpected patch type returned by the handler: %v, only allow: %v",
+ resp.PatchType, admissionv1.PatchTypeJSONPatch))
+ }
+ patches = append(patches, resp.Patches...)
+ }
+ var err error
+ marshaledPatch, err := json.Marshal(patches)
+ if err != nil {
+ return Errored(http.StatusBadRequest, fmt.Errorf("error when marshaling the patch: %w", err))
+ }
+ return Response{
+ AdmissionResponse: admissionv1.AdmissionResponse{
+ Allowed: true,
+ Result: &metav1.Status{
+ Code: http.StatusOK,
+ },
+ Patch: marshaledPatch,
+ PatchType: func() *admissionv1.PatchType { pt := admissionv1.PatchTypeJSONPatch; return &pt }(),
+ },
+ }
+}
+
+// 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
+// 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
+// ensure patches are disjoint.
+func MultiMutatingHandler(handlers ...Handler) Handler {
+ return multiMutating(handlers)
+}
+
+type multiValidating []Handler
+
+func (hs multiValidating) Handle(ctx context.Context, req Request) Response {
+ for _, handler := range hs {
+ resp := handler.Handle(ctx, req)
+ if !resp.Allowed {
+ return resp
+ }
+ }
+ return Response{
+ AdmissionResponse: admissionv1.AdmissionResponse{
+ Allowed: true,
+ Result: &metav1.Status{
+ Code: http.StatusOK,
+ },
+ },
+ }
+}
+
+// MultiValidatingHandler combines multiple validating webhook handlers into a single
+// validating webhook handler. Handlers are called in sequential order, and the first
+// `allowed: false` response may short-circuit the rest.
+func MultiValidatingHandler(handlers ...Handler) Handler {
+ 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
+}
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/response.go b/vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/response.go
new file mode 100644
index 000000000..24ff1dee3
--- /dev/null
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/response.go
@@ -0,0 +1,121 @@
+/*
+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 admission
+
+import (
+ "net/http"
+
+ jsonpatch "gomodules.xyz/jsonpatch/v2"
+ admissionv1 "k8s.io/api/admission/v1"
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+)
+
+// Allowed constructs a response indicating that the given operation
+// is allowed (without any patches).
+func Allowed(reason string) Response {
+ return ValidationResponse(true, reason)
+}
+
+// Denied constructs a response indicating that the given operation
+// is not allowed.
+func Denied(reason string) Response {
+ return ValidationResponse(false, reason)
+}
+
+// Patched constructs a response indicating that the given operation is
+// allowed, and that the target object should be modified by the given
+// JSONPatch operations.
+func Patched(reason string, patches ...jsonpatch.JsonPatchOperation) Response {
+ resp := Allowed(reason)
+ resp.Patches = patches
+
+ return resp
+}
+
+// Errored creates a new Response for error-handling a request.
+func Errored(code int32, err error) Response {
+ return Response{
+ AdmissionResponse: admissionv1.AdmissionResponse{
+ Allowed: false,
+ Result: &metav1.Status{
+ Code: code,
+ Message: err.Error(),
+ },
+ },
+ }
+}
+
+// ValidationResponse returns a response for admitting a request.
+func ValidationResponse(allowed bool, reason string) Response {
+ code := http.StatusForbidden
+ if allowed {
+ code = http.StatusOK
+ }
+ resp := Response{
+ AdmissionResponse: admissionv1.AdmissionResponse{
+ Allowed: allowed,
+ Result: &metav1.Status{
+ Code: int32(code),
+ },
+ },
+ }
+ if len(reason) > 0 {
+ resp.Result.Reason = metav1.StatusReason(reason)
+ }
+ return resp
+}
+
+// PatchResponseFromRaw takes 2 byte arrays and returns a new response with json patch.
+// The original object should be passed in as raw bytes to avoid the roundtripping problem
+// described in https://github.com/kubernetes-sigs/kubebuilder/issues/510.
+func PatchResponseFromRaw(original, current []byte) Response {
+ patches, err := jsonpatch.CreatePatch(original, current)
+ if err != nil {
+ return Errored(http.StatusInternalServerError, err)
+ }
+ return Response{
+ Patches: patches,
+ AdmissionResponse: admissionv1.AdmissionResponse{
+ Allowed: true,
+ PatchType: func() *admissionv1.PatchType {
+ if len(patches) == 0 {
+ return nil
+ }
+ pt := admissionv1.PatchTypeJSONPatch
+ return &pt
+ }(),
+ },
+ }
+}
+
+// validationResponseFromStatus returns a response for admitting a request with provided Status object.
+func validationResponseFromStatus(allowed bool, status metav1.Status) Response {
+ resp := Response{
+ AdmissionResponse: admissionv1.AdmissionResponse{
+ Allowed: allowed,
+ Result: &status,
+ },
+ }
+ return resp
+}
+
+// WithWarnings adds the given warnings to the Response.
+// If any warnings were already given, they will not be overwritten.
+func (r Response) WithWarnings(warnings ...string) Response {
+ r.AdmissionResponse.Warnings = append(r.AdmissionResponse.Warnings, warnings...)
+ return r
+}
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/validator.go b/vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/validator.go
new file mode 100644
index 000000000..4b27e75ed
--- /dev/null
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/validator.go
@@ -0,0 +1,122 @@
+/*
+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 admission
+
+import (
+ "context"
+ goerrors "errors"
+ "net/http"
+
+ v1 "k8s.io/api/admission/v1"
+ apierrors "k8s.io/apimachinery/pkg/api/errors"
+ "k8s.io/apimachinery/pkg/runtime"
+)
+
+// Validator defines functions for validating an operation.
+type Validator interface {
+ runtime.Object
+ ValidateCreate() error
+ ValidateUpdate(old runtime.Object) error
+ ValidateDelete() error
+}
+
+// ValidatingWebhookFor creates a new Webhook for validating the provided type.
+func ValidatingWebhookFor(validator Validator) *Webhook {
+ return &Webhook{
+ Handler: &validatingHandler{validator: validator},
+ }
+}
+
+type validatingHandler struct {
+ validator Validator
+ 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.
+func (h *validatingHandler) Handle(ctx context.Context, req Request) Response {
+ if h.validator == nil {
+ panic("validator should never be nil")
+ }
+
+ // Get the object in the request
+ obj := h.validator.DeepCopyObject().(Validator)
+ if req.Operation == v1.Create {
+ err := h.decoder.Decode(req, obj)
+ if err != nil {
+ return Errored(http.StatusBadRequest, err)
+ }
+
+ err = obj.ValidateCreate()
+ if err != nil {
+ 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()
+
+ err := h.decoder.DecodeRaw(req.Object, obj)
+ if err != nil {
+ return Errored(http.StatusBadRequest, err)
+ }
+ err = h.decoder.DecodeRaw(req.OldObject, oldObj)
+ if err != nil {
+ return Errored(http.StatusBadRequest, err)
+ }
+
+ err = obj.ValidateUpdate(oldObj)
+ if err != nil {
+ 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
+ // OldObject contains the object being deleted
+ err := h.decoder.DecodeRaw(req.OldObject, obj)
+ if err != nil {
+ return Errored(http.StatusBadRequest, err)
+ }
+
+ err = obj.ValidateDelete()
+ if err != nil {
+ var apiStatus apierrors.APIStatus
+ if goerrors.As(err, &apiStatus) {
+ return validationResponseFromStatus(false, apiStatus.Status())
+ }
+ return Denied(err.Error())
+ }
+ }
+
+ return Allowed("")
+}
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/validator_custom.go b/vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/validator_custom.go
new file mode 100644
index 000000000..38d556511
--- /dev/null
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/validator_custom.go
@@ -0,0 +1,111 @@
+/*
+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 admission
+
+import (
+ "context"
+ "errors"
+ "fmt"
+ "net/http"
+
+ v1 "k8s.io/api/admission/v1"
+ apierrors "k8s.io/apimachinery/pkg/api/errors"
+ "k8s.io/apimachinery/pkg/runtime"
+)
+
+// CustomValidator defines functions for validating an operation.
+type CustomValidator interface {
+ ValidateCreate(ctx context.Context, obj runtime.Object) error
+ ValidateUpdate(ctx context.Context, oldObj, newObj runtime.Object) error
+ ValidateDelete(ctx context.Context, obj runtime.Object) error
+}
+
+// WithCustomValidator creates a new Webhook for validating the provided type.
+func WithCustomValidator(obj runtime.Object, validator CustomValidator) *Webhook {
+ return &Webhook{
+ Handler: &validatorForType{object: obj, validator: validator},
+ }
+}
+
+type validatorForType struct {
+ validator CustomValidator
+ object runtime.Object
+ 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.
+func (h *validatorForType) Handle(ctx context.Context, req Request) Response {
+ if h.validator == nil {
+ panic("validator should never be nil")
+ }
+ if h.object == nil {
+ panic("object should never be nil")
+ }
+
+ // Get the object in the request
+ obj := h.object.DeepCopyObject()
+
+ var err error
+ switch req.Operation {
+ case v1.Create:
+ if err := h.decoder.Decode(req, obj); err != nil {
+ return Errored(http.StatusBadRequest, err)
+ }
+
+ err = h.validator.ValidateCreate(ctx, obj)
+ case v1.Update:
+ oldObj := obj.DeepCopyObject()
+ if err := h.decoder.DecodeRaw(req.Object, obj); err != nil {
+ return Errored(http.StatusBadRequest, err)
+ }
+ if err := h.decoder.DecodeRaw(req.OldObject, oldObj); err != nil {
+ return Errored(http.StatusBadRequest, err)
+ }
+
+ err = h.validator.ValidateUpdate(ctx, oldObj, obj)
+ case v1.Delete:
+ // In reference to PR: https://github.com/kubernetes/kubernetes/pull/76346
+ // OldObject contains the object being deleted
+ if err := h.decoder.DecodeRaw(req.OldObject, obj); err != nil {
+ return Errored(http.StatusBadRequest, err)
+ }
+
+ err = h.validator.ValidateDelete(ctx, obj)
+ default:
+ return Errored(http.StatusBadRequest, fmt.Errorf("unknown operation request %q", req.Operation))
+ }
+
+ // Check the error message first.
+ if err != nil {
+ var apiStatus apierrors.APIStatus
+ if errors.As(err, &apiStatus) {
+ return validationResponseFromStatus(false, apiStatus.Status())
+ }
+ return Denied(err.Error())
+ }
+
+ // Return allowed if everything succeeded.
+ return Allowed("")
+}
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/webhook.go b/vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/webhook.go
new file mode 100644
index 000000000..cf7dbcf68
--- /dev/null
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/webhook/admission/webhook.go
@@ -0,0 +1,255 @@
+/*
+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 admission
+
+import (
+ "context"
+ "errors"
+ "net/http"
+
+ "github.com/go-logr/logr"
+ jsonpatch "gomodules.xyz/jsonpatch/v2"
+ admissionv1 "k8s.io/api/admission/v1"
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ "k8s.io/apimachinery/pkg/runtime"
+ "k8s.io/apimachinery/pkg/util/json"
+ "k8s.io/client-go/kubernetes/scheme"
+
+ logf "sigs.k8s.io/controller-runtime/pkg/internal/log"
+ "sigs.k8s.io/controller-runtime/pkg/runtime/inject"
+ "sigs.k8s.io/controller-runtime/pkg/webhook/internal/metrics"
+)
+
+var (
+ errUnableToEncodeResponse = errors.New("unable to encode response")
+)
+
+// Request defines the input for an admission handler.
+// It contains information to identify the object in
+// question (group, version, kind, resource, subresource,
+// name, namespace), as well as the operation in question
+// (e.g. Get, Create, etc), and the object itself.
+type Request struct {
+ admissionv1.AdmissionRequest
+}
+
+// Response is the output of an admission handler.
+// It contains a response indicating if a given
+// operation is allowed, as well as a set of patches
+// to mutate the object in the case of a mutating admission handler.
+type Response struct {
+ // Patches are the JSON patches for mutating webhooks.
+ // Using this instead of setting Response.Patch to minimize
+ // overhead of serialization and deserialization.
+ // Patches set here will override any patches in the response,
+ // so leave this empty if you want to set the patch response directly.
+ Patches []jsonpatch.JsonPatchOperation
+ // AdmissionResponse is the raw admission response.
+ // The Patch field in it will be overwritten by the listed patches.
+ admissionv1.AdmissionResponse
+}
+
+// Complete populates any fields that are yet to be set in
+// the underlying AdmissionResponse, It mutates the response.
+func (r *Response) Complete(req Request) error {
+ r.UID = req.UID
+
+ // ensure that we have a valid status code
+ if r.Result == nil {
+ r.Result = &metav1.Status{}
+ }
+ if r.Result.Code == 0 {
+ r.Result.Code = http.StatusOK
+ }
+ // TODO(directxman12): do we need to populate this further, and/or
+ // is code actually necessary (the same webhook doesn't use it)
+
+ if len(r.Patches) == 0 {
+ return nil
+ }
+
+ var err error
+ r.Patch, err = json.Marshal(r.Patches)
+ if err != nil {
+ return err
+ }
+ patchType := admissionv1.PatchTypeJSONPatch
+ r.PatchType = &patchType
+
+ return nil
+}
+
+// Handler can handle an AdmissionRequest.
+type Handler interface {
+ // Handle yields a response to an AdmissionRequest.
+ //
+ // The supplied context is extracted from the received http.Request, allowing wrapping
+ // http.Handlers to inject values into and control cancelation of downstream request processing.
+ Handle(context.Context, Request) Response
+}
+
+// HandlerFunc implements Handler interface using a single function.
+type HandlerFunc func(context.Context, Request) Response
+
+var _ Handler = HandlerFunc(nil)
+
+// Handle process the AdmissionRequest by invoking the underlying function.
+func (f HandlerFunc) Handle(ctx context.Context, req Request) Response {
+ return f(ctx, req)
+}
+
+// Webhook represents each individual webhook.
+//
+// It must be registered with a webhook.Server or
+// populated by StandaloneWebhook to be ran on an arbitrary HTTP server.
+type Webhook struct {
+ // Handler actually processes an admission request returning whether it was allowed or denied,
+ // and potentially patches to apply to the handler.
+ Handler Handler
+
+ // WithContextFunc will allow you to take the http.Request.Context() and
+ // add any additional information such as passing the request path or
+ // headers thus allowing you to read them from within the handler
+ WithContextFunc func(context.Context, *http.Request) context.Context
+
+ // decoder is constructed on receiving a scheme and passed down to then handler
+ decoder *Decoder
+
+ 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
+}
+
+// Handle processes AdmissionRequest.
+// If the webhook is mutating type, it delegates the AdmissionRequest to each handler and merge the patches.
+// If the webhook is validating type, it delegates the AdmissionRequest to each handler and
+// deny the request if anyone denies.
+func (wh *Webhook) Handle(ctx context.Context, req Request) Response {
+ resp := wh.Handler.Handle(ctx, req)
+ if err := resp.Complete(req); err != nil {
+ wh.log.Error(err, "unable to encode response")
+ return Errored(http.StatusInternalServerError, errUnableToEncodeResponse)
+ }
+
+ return resp
+}
+
+// InjectScheme injects a scheme into the webhook, in order to construct a Decoder.
+func (wh *Webhook) InjectScheme(s *runtime.Scheme) error {
+ // TODO(directxman12): we should have a better way to pass this down
+
+ var err error
+ 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
+}
+
+// GetDecoder returns a decoder to decode the objects embedded in admission requests.
+// It may be nil if we haven't received a scheme to use to determine object types yet.
+func (wh *Webhook) GetDecoder() *Decoder {
+ return wh.decoder
+}
+
+// InjectFunc injects the field setter into the webhook.
+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 setFields(wh.Handler)
+}
+
+// StandaloneOptions let you configure a StandaloneWebhook.
+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.
+ // If none is set, it defaults to log.Log global logger.
+ Logger logr.Logger
+ // MetricsPath is used for labelling prometheus metrics
+ // by the path is served on.
+ // If none is set, prometheus metrics will not be generated.
+ MetricsPath string
+}
+
+// StandaloneWebhook prepares a webhook for use without a webhook.Server,
+// passing in the information normally populated by webhook.Server
+// and instrumenting the webhook with metrics.
+//
+// Use this to attach your webhook to an arbitrary HTTP server or mux.
+//
+// Note that you are responsible for terminating TLS if you use StandaloneWebhook
+// in your own server/mux. In order to be accessed by a kubernetes cluster,
+// all webhook servers require TLS.
+func StandaloneWebhook(hook *Webhook, opts StandaloneOptions) (http.Handler, error) {
+ if opts.Scheme == nil {
+ opts.Scheme = scheme.Scheme
+ }
+
+ if err := hook.InjectScheme(opts.Scheme); err != nil {
+ return nil, err
+ }
+
+ if opts.Logger == nil {
+ opts.Logger = logf.RuntimeLog.WithName("webhook")
+ }
+ hook.log = opts.Logger
+
+ if opts.MetricsPath == "" {
+ return hook, nil
+ }
+ return metrics.InstrumentedHook(opts.MetricsPath, hook), nil
+}
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/webhook/alias.go b/vendor/sigs.k8s.io/controller-runtime/pkg/webhook/alias.go
new file mode 100644
index 000000000..293137db4
--- /dev/null
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/webhook/alias.go
@@ -0,0 +1,79 @@
+/*
+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 webhook
+
+import (
+ "gomodules.xyz/jsonpatch/v2"
+ "sigs.k8s.io/controller-runtime/pkg/webhook/admission"
+)
+
+// define some aliases for common bits of the webhook functionality
+
+// Defaulter defines functions for setting defaults on resources.
+type Defaulter = admission.Defaulter
+
+// Validator defines functions for validating an operation.
+type Validator = admission.Validator
+
+// CustomDefaulter defines functions for setting defaults on resources.
+type CustomDefaulter = admission.CustomDefaulter
+
+// CustomValidator defines functions for validating an operation.
+type CustomValidator = admission.CustomValidator
+
+// AdmissionRequest defines the input for an admission handler.
+// It contains information to identify the object in
+// question (group, version, kind, resource, subresource,
+// name, namespace), as well as the operation in question
+// (e.g. Get, Create, etc), and the object itself.
+type AdmissionRequest = admission.Request
+
+// AdmissionResponse is the output of an admission handler.
+// It contains a response indicating if a given
+// operation is allowed, as well as a set of patches
+// to mutate the object in the case of a mutating admission handler.
+type AdmissionResponse = admission.Response
+
+// Admission is webhook suitable for registration with the server
+// an admission webhook that validates API operations and potentially
+// mutates their contents.
+type Admission = admission.Webhook
+
+// AdmissionHandler knows how to process admission requests, validating them,
+// and potentially mutating the objects they contain.
+type AdmissionHandler = admission.Handler
+
+// AdmissionDecoder knows how to decode objects from admission requests.
+type AdmissionDecoder = admission.Decoder
+
+// JSONPatchOp represents a single JSONPatch patch operation.
+type JSONPatchOp = jsonpatch.Operation
+
+var (
+ // Allowed indicates that the admission request should be allowed for the given reason.
+ Allowed = admission.Allowed
+
+ // Denied indicates that the admission request should be denied for the given reason.
+ Denied = admission.Denied
+
+ // Patched indicates that the admission request should be allowed for the given reason,
+ // and that the contained object should be mutated using the given patches.
+ Patched = admission.Patched
+
+ // Errored indicates that an error occurred in the admission request.
+ Errored = admission.Errored
+)
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/webhook/conversion/conversion.go b/vendor/sigs.k8s.io/controller-runtime/pkg/webhook/conversion/conversion.go
new file mode 100644
index 000000000..a5b7a282c
--- /dev/null
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/webhook/conversion/conversion.go
@@ -0,0 +1,345 @@
+/*
+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 conversion provides implementation for CRD conversion webhook that implements handler for version conversion requests for types that are convertible.
+
+See pkg/conversion for interface definitions required to ensure an API Type is convertible.
+*/
+package conversion
+
+import (
+ "encoding/json"
+ "fmt"
+ "net/http"
+
+ apix "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
+ "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"
+ "sigs.k8s.io/controller-runtime/pkg/conversion"
+ logf "sigs.k8s.io/controller-runtime/pkg/log"
+)
+
+var (
+ log = logf.Log.WithName("conversion-webhook")
+)
+
+// Webhook implements a CRD conversion webhook HTTP handler.
+type Webhook struct {
+ scheme *runtime.Scheme
+ decoder *Decoder
+}
+
+// InjectScheme injects a scheme into the webhook, in order to construct a Decoder.
+func (wh *Webhook) InjectScheme(s *runtime.Scheme) error {
+ var err error
+ wh.scheme = s
+ wh.decoder, err = NewDecoder(s)
+ if err != nil {
+ return err
+ }
+
+ return nil
+}
+
+// ensure Webhook implements http.Handler
+var _ http.Handler = &Webhook{}
+
+func (wh *Webhook) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+ convertReview := &apix.ConversionReview{}
+ err := json.NewDecoder(r.Body).Decode(convertReview)
+ if err != nil {
+ log.Error(err, "failed to read conversion request")
+ w.WriteHeader(http.StatusBadRequest)
+ return
+ }
+
+ // TODO(droot): may be move the conversion logic to a separate module to
+ // decouple it from the http layer ?
+ resp, err := wh.handleConvertRequest(convertReview.Request)
+ if err != nil {
+ log.Error(err, "failed to convert", "request", convertReview.Request.UID)
+ convertReview.Response = errored(err)
+ } else {
+ convertReview.Response = resp
+ }
+ convertReview.Response.UID = convertReview.Request.UID
+ convertReview.Request = nil
+
+ err = json.NewEncoder(w).Encode(convertReview)
+ if err != nil {
+ log.Error(err, "failed to write response")
+ return
+ }
+}
+
+// handles a version conversion request.
+func (wh *Webhook) handleConvertRequest(req *apix.ConversionRequest) (*apix.ConversionResponse, error) {
+ if req == nil {
+ return nil, fmt.Errorf("conversion request is nil")
+ }
+ var objects []runtime.RawExtension
+
+ for _, obj := range req.Objects {
+ src, gvk, err := wh.decoder.Decode(obj.Raw)
+ if err != nil {
+ return nil, err
+ }
+ dst, err := wh.allocateDstObject(req.DesiredAPIVersion, gvk.Kind)
+ if err != nil {
+ return nil, err
+ }
+ err = wh.convertObject(src, dst)
+ if err != nil {
+ return nil, err
+ }
+ objects = append(objects, runtime.RawExtension{Object: dst})
+ }
+ return &apix.ConversionResponse{
+ UID: req.UID,
+ ConvertedObjects: objects,
+ Result: metav1.Status{
+ Status: metav1.StatusSuccess,
+ },
+ }, nil
+}
+
+// convertObject will convert given a src object to dst object.
+// Note(droot): couldn't find a way to reduce the cyclomatic complexity under 10
+// without compromising readability, so disabling gocyclo linter
+func (wh *Webhook) convertObject(src, dst runtime.Object) error {
+ srcGVK := src.GetObjectKind().GroupVersionKind()
+ dstGVK := dst.GetObjectKind().GroupVersionKind()
+
+ if srcGVK.GroupKind() != dstGVK.GroupKind() {
+ return fmt.Errorf("src %T and dst %T does not belong to same API Group", src, dst)
+ }
+
+ if srcGVK == dstGVK {
+ return fmt.Errorf("conversion is not allowed between same type %T", src)
+ }
+
+ srcIsHub, dstIsHub := isHub(src), isHub(dst)
+ srcIsConvertible, dstIsConvertible := isConvertible(src), isConvertible(dst)
+
+ switch {
+ case srcIsHub && dstIsConvertible:
+ return dst.(conversion.Convertible).ConvertFrom(src.(conversion.Hub))
+ case dstIsHub && srcIsConvertible:
+ return src.(conversion.Convertible).ConvertTo(dst.(conversion.Hub))
+ case srcIsConvertible && dstIsConvertible:
+ return wh.convertViaHub(src.(conversion.Convertible), dst.(conversion.Convertible))
+ default:
+ return fmt.Errorf("%T is not convertible to %T", src, dst)
+ }
+}
+
+func (wh *Webhook) convertViaHub(src, dst conversion.Convertible) error {
+ hub, err := wh.getHub(src)
+ if err != nil {
+ return err
+ }
+
+ if hub == nil {
+ return fmt.Errorf("%s does not have any Hub defined", src)
+ }
+
+ err = src.ConvertTo(hub)
+ if err != nil {
+ return fmt.Errorf("%T failed to convert to hub version %T : %w", src, hub, err)
+ }
+
+ err = dst.ConvertFrom(hub)
+ if err != nil {
+ return fmt.Errorf("%T failed to convert from hub version %T : %w", dst, hub, err)
+ }
+
+ return nil
+}
+
+// getHub returns an instance of the Hub for passed-in object's group/kind.
+func (wh *Webhook) getHub(obj runtime.Object) (conversion.Hub, error) {
+ gvks, err := objectGVKs(wh.scheme, obj)
+ if err != nil {
+ return nil, err
+ }
+ if len(gvks) == 0 {
+ return nil, fmt.Errorf("error retrieving gvks for object : %v", obj)
+ }
+
+ var hub conversion.Hub
+ var hubFoundAlready bool
+ for _, gvk := range gvks {
+ instance, err := wh.scheme.New(gvk)
+ if err != nil {
+ return nil, fmt.Errorf("failed to allocate an instance for gvk %v: %w", gvk, err)
+ }
+ if val, isHub := instance.(conversion.Hub); isHub {
+ if hubFoundAlready {
+ return nil, fmt.Errorf("multiple hub version defined for %T", obj)
+ }
+ hubFoundAlready = true
+ hub = val
+ }
+ }
+ return hub, nil
+}
+
+// allocateDstObject returns an instance for a given GVK.
+func (wh *Webhook) allocateDstObject(apiVersion, kind string) (runtime.Object, error) {
+ gvk := schema.FromAPIVersionAndKind(apiVersion, kind)
+
+ obj, err := wh.scheme.New(gvk)
+ if err != nil {
+ return obj, err
+ }
+
+ t, err := meta.TypeAccessor(obj)
+ if err != nil {
+ return obj, err
+ }
+
+ t.SetAPIVersion(apiVersion)
+ t.SetKind(kind)
+
+ return obj, nil
+}
+
+// IsConvertible determines if given type is convertible or not. For a type
+// to be convertible, the group-kind needs to have a Hub type defined and all
+// non-hub types must be able to convert to/from Hub.
+func IsConvertible(scheme *runtime.Scheme, obj runtime.Object) (bool, error) {
+ var hubs, spokes, nonSpokes []runtime.Object
+
+ gvks, err := objectGVKs(scheme, obj)
+ if err != nil {
+ return false, err
+ }
+ if len(gvks) == 0 {
+ return false, fmt.Errorf("error retrieving gvks for object : %v", obj)
+ }
+
+ for _, gvk := range gvks {
+ instance, err := scheme.New(gvk)
+ if err != nil {
+ return false, fmt.Errorf("failed to allocate an instance for gvk %v: %w", gvk, err)
+ }
+
+ if isHub(instance) {
+ hubs = append(hubs, instance)
+ continue
+ }
+
+ if !isConvertible(instance) {
+ nonSpokes = append(nonSpokes, instance)
+ continue
+ }
+
+ spokes = append(spokes, instance)
+ }
+
+ if len(gvks) == 1 {
+ return false, nil // single version
+ }
+
+ if len(hubs) == 0 && len(spokes) == 0 {
+ // multiple version detected with no conversion implementation. This is
+ // true for multi-version built-in types.
+ return false, nil
+ }
+
+ if len(hubs) == 1 && len(nonSpokes) == 0 { // convertible
+ return true, nil
+ }
+
+ return false, PartialImplementationError{
+ hubs: hubs,
+ nonSpokes: nonSpokes,
+ spokes: spokes,
+ }
+}
+
+// objectGVKs returns all (Group,Version,Kind) for the Group/Kind of given object.
+func objectGVKs(scheme *runtime.Scheme, obj runtime.Object) ([]schema.GroupVersionKind, error) {
+ // NB: we should not use `obj.GetObjectKind().GroupVersionKind()` to get the
+ // GVK here, since it is parsed from apiVersion and kind fields and it may
+ // return empty GVK if obj is an uninitialized object.
+ objGVKs, _, err := scheme.ObjectKinds(obj)
+ if err != nil {
+ return nil, err
+ }
+ if len(objGVKs) != 1 {
+ return nil, fmt.Errorf("expect to get only one GVK for %v", obj)
+ }
+ objGVK := objGVKs[0]
+ knownTypes := scheme.AllKnownTypes()
+
+ var gvks []schema.GroupVersionKind
+ for gvk := range knownTypes {
+ if objGVK.GroupKind() == gvk.GroupKind() {
+ gvks = append(gvks, gvk)
+ }
+ }
+ return gvks, nil
+}
+
+// PartialImplementationError represents an error due to partial conversion
+// implementation such as hub without spokes, multiple hubs or spokes without hub.
+type PartialImplementationError struct {
+ gvk schema.GroupVersionKind
+ hubs []runtime.Object
+ nonSpokes []runtime.Object
+ spokes []runtime.Object
+}
+
+func (e PartialImplementationError) Error() string {
+ if len(e.hubs) == 0 {
+ return fmt.Sprintf("no hub defined for gvk %s", e.gvk)
+ }
+ if len(e.hubs) > 1 {
+ return fmt.Sprintf("multiple(%d) hubs defined for group-kind '%s' ",
+ len(e.hubs), e.gvk.GroupKind())
+ }
+ if len(e.nonSpokes) > 0 {
+ return fmt.Sprintf("%d inconvertible types detected for group-kind '%s'",
+ len(e.nonSpokes), e.gvk.GroupKind())
+ }
+ return ""
+}
+
+// isHub determines if passed-in object is a Hub or not.
+func isHub(obj runtime.Object) bool {
+ _, yes := obj.(conversion.Hub)
+ return yes
+}
+
+// isConvertible determines if passed-in object is a convertible.
+func isConvertible(obj runtime.Object) bool {
+ _, yes := obj.(conversion.Convertible)
+ return yes
+}
+
+// helper to construct error response.
+func errored(err error) *apix.ConversionResponse {
+ return &apix.ConversionResponse{
+ Result: metav1.Status{
+ Status: metav1.StatusFailure,
+ Message: err.Error(),
+ },
+ }
+}
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/webhook/conversion/decoder.go b/vendor/sigs.k8s.io/controller-runtime/pkg/webhook/conversion/decoder.go
new file mode 100644
index 000000000..6a9e9c236
--- /dev/null
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/webhook/conversion/decoder.go
@@ -0,0 +1,47 @@
+/*
+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 conversion
+
+import (
+ "k8s.io/apimachinery/pkg/runtime"
+ "k8s.io/apimachinery/pkg/runtime/schema"
+ "k8s.io/apimachinery/pkg/runtime/serializer"
+)
+
+// Decoder knows how to decode the contents of a CRD version conversion
+// request into a concrete object.
+// TODO(droot): consider reusing decoder from admission pkg for this.
+type Decoder struct {
+ codecs serializer.CodecFactory
+}
+
+// NewDecoder creates a Decoder given the runtime.Scheme
+func NewDecoder(scheme *runtime.Scheme) (*Decoder, error) {
+ return &Decoder{codecs: serializer.NewCodecFactory(scheme)}, nil
+}
+
+// Decode decodes the inlined object.
+func (d *Decoder) Decode(content []byte) (runtime.Object, *schema.GroupVersionKind, error) {
+ deserializer := d.codecs.UniversalDeserializer()
+ return deserializer.Decode(content, nil, nil)
+}
+
+// DecodeInto decodes the inlined object in the into the passed-in runtime.Object.
+func (d *Decoder) DecodeInto(content []byte, into runtime.Object) error {
+ deserializer := d.codecs.UniversalDeserializer()
+ return runtime.DecodeInto(deserializer, content, into)
+}
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/webhook/doc.go b/vendor/sigs.k8s.io/controller-runtime/pkg/webhook/doc.go
new file mode 100644
index 000000000..2c93f0d99
--- /dev/null
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/webhook/doc.go
@@ -0,0 +1,28 @@
+/*
+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 webhook provides methods to build and bootstrap a webhook server.
+
+Currently, it only supports admission webhooks. It will support CRD conversion webhooks in the near future.
+*/
+package webhook
+
+import (
+ logf "sigs.k8s.io/controller-runtime/pkg/internal/log"
+)
+
+var log = logf.RuntimeLog.WithName("webhook")
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/webhook/internal/metrics/metrics.go b/vendor/sigs.k8s.io/controller-runtime/pkg/webhook/internal/metrics/metrics.go
new file mode 100644
index 000000000..557004908
--- /dev/null
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/webhook/internal/metrics/metrics.go
@@ -0,0 +1,85 @@
+/*
+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 metrics
+
+import (
+ "net/http"
+
+ "github.com/prometheus/client_golang/prometheus"
+ "github.com/prometheus/client_golang/prometheus/promhttp"
+
+ "sigs.k8s.io/controller-runtime/pkg/metrics"
+)
+
+var (
+ // RequestLatency is a prometheus metric which is a histogram of the latency
+ // of processing admission requests.
+ RequestLatency = prometheus.NewHistogramVec(
+ prometheus.HistogramOpts{
+ Name: "controller_runtime_webhook_latency_seconds",
+ Help: "Histogram of the latency of processing admission requests",
+ },
+ []string{"webhook"},
+ )
+
+ // RequestTotal is a prometheus metric which is a counter of the total processed admission requests.
+ RequestTotal = func() *prometheus.CounterVec {
+ return prometheus.NewCounterVec(
+ prometheus.CounterOpts{
+ Name: "controller_runtime_webhook_requests_total",
+ Help: "Total number of admission requests by HTTP status code.",
+ },
+ []string{"webhook", "code"},
+ )
+ }()
+
+ // RequestInFlight is a prometheus metric which is a gauge of the in-flight admission requests.
+ RequestInFlight = func() *prometheus.GaugeVec {
+ return prometheus.NewGaugeVec(
+ prometheus.GaugeOpts{
+ Name: "controller_runtime_webhook_requests_in_flight",
+ Help: "Current number of admission requests being served.",
+ },
+ []string{"webhook"},
+ )
+ }()
+)
+
+func init() {
+ metrics.Registry.MustRegister(RequestLatency, RequestTotal, RequestInFlight)
+}
+
+// InstrumentedHook adds some instrumentation on top of the given webhook.
+func InstrumentedHook(path string, hookRaw http.Handler) http.Handler {
+ lbl := prometheus.Labels{"webhook": path}
+
+ lat := RequestLatency.MustCurryWith(lbl)
+ cnt := RequestTotal.MustCurryWith(lbl)
+ gge := RequestInFlight.With(lbl)
+
+ // Initialize the most likely HTTP status codes.
+ cnt.WithLabelValues("200")
+ cnt.WithLabelValues("500")
+
+ return promhttp.InstrumentHandlerDuration(
+ lat,
+ promhttp.InstrumentHandlerCounter(
+ cnt,
+ promhttp.InstrumentHandlerInFlight(gge, hookRaw),
+ ),
+ )
+}
diff --git a/vendor/sigs.k8s.io/controller-runtime/pkg/webhook/server.go b/vendor/sigs.k8s.io/controller-runtime/pkg/webhook/server.go
new file mode 100644
index 000000000..1db38113f
--- /dev/null
+++ b/vendor/sigs.k8s.io/controller-runtime/pkg/webhook/server.go
@@ -0,0 +1,339 @@
+/*
+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 webhook
+
+import (
+ "context"
+ "crypto/tls"
+ "crypto/x509"
+ "fmt"
+ "io/ioutil"
+ "net"
+ "net/http"
+ "os"
+ "path/filepath"
+ "strconv"
+ "sync"
+ "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/healthz"
+ "sigs.k8s.io/controller-runtime/pkg/runtime/inject"
+ "sigs.k8s.io/controller-runtime/pkg/webhook/internal/metrics"
+)
+
+// DefaultPort is the default port that the webhook server serves.
+var DefaultPort = 9443
+
+// Server is an admission webhook server that can serve traffic and
+// generates related k8s resources for deploying.
+//
+// TLS is required for a webhook to be accessed by kubernetes, so
+// you must provide a CertName and KeyName or have valid cert/key
+// at the default locations (tls.crt and tls.key). If you do not
+// want to configure TLS (i.e for testing purposes) run an
+// admission.StandaloneWebhook in your own server.
+type Server struct {
+ // Host is the address that the server will listen on.
+ // Defaults to "" - all addresses.
+ Host string
+
+ // Port is the port number that the server will serve.
+ // It will be defaulted to 9443 if unspecified.
+ Port int
+
+ // CertDir is the directory that contains the server key and certificate. The
+ // server key and certificate.
+ CertDir string
+
+ // CertName is the server certificate name. Defaults to tls.crt.
+ CertName string
+
+ // KeyName is the server key name. Defaults to tls.key.
+ KeyName string
+
+ // ClientCAName is the CA certificate name which server used to verify remote(client)'s certificate.
+ // Defaults to "", which means server does not verify client's certificate.
+ ClientCAName string
+
+ // TLSVersion is the minimum version of TLS supported. Accepts
+ // "", "1.0", "1.1", "1.2" and "1.3" only ("" is equivalent to "1.0" for backwards compatibility)
+ TLSMinVersion string
+
+ // WebhookMux is the multiplexer that handles different webhooks.
+ WebhookMux *http.ServeMux
+
+ // webhooks keep track of all registered webhooks for dependency injection,
+ // and to provide better panic messages on duplicate webhook registration.
+ 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 sync.Once
+
+ // started is set to true immediately before the server is started
+ // and thus can be used to check if the server has been started
+ started bool
+
+ // mu protects access to the webhook map & setFields for Start, Register, etc
+ mu sync.Mutex
+}
+
+// setDefaults does defaulting for the Server.
+func (s *Server) setDefaults() {
+ s.webhooks = map[string]http.Handler{}
+ if s.WebhookMux == nil {
+ s.WebhookMux = http.NewServeMux()
+ }
+
+ if s.Port <= 0 {
+ 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
+// the webhook server doesn't need leader election.
+func (*Server) NeedLeaderElection() bool {
+ return false
+}
+
+// Register marks the given webhook as being served at the given path.
+// It panics if two hooks are registered on the same path.
+func (s *Server) Register(path string, hook http.Handler) {
+ s.mu.Lock()
+ defer s.mu.Unlock()
+
+ s.defaultingOnce.Do(s.setDefaults)
+ if _, found := s.webhooks[path]; found {
+ 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.WebhookMux.Handle(path, metrics.InstrumentedHook(path, hook))
+
+ regLog := log.WithValues("path", path)
+ 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")
+// to the values accepted by tls.Config (for example 0x301).
+func tlsVersion(version string) (uint16, error) {
+ switch version {
+ // default is previous behaviour
+ case "":
+ return tls.VersionTLS10, nil
+ case "1.0":
+ return tls.VersionTLS10, nil
+ case "1.1":
+ return tls.VersionTLS11, nil
+ case "1.2":
+ return tls.VersionTLS12, nil
+ case "1.3":
+ return tls.VersionTLS13, nil
+ default:
+ return 0, fmt.Errorf("invalid TLSMinVersion %v: expects 1.0, 1.1, 1.2, 1.3 or empty", version)
+ }
+}
+
+// Start runs the server.
+// It will install the webhook related resources depend on the server configuration.
+func (s *Server) Start(ctx context.Context) error {
+ s.defaultingOnce.Do(s.setDefaults)
+
+ baseHookLog := log.WithName("webhooks")
+ baseHookLog.Info("Starting webhook server")
+
+ certPath := filepath.Join(s.CertDir, s.CertName)
+ 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 {
+ return err
+ }
+
+ cfg := &tls.Config{ //nolint:gosec
+ NextProtos: []string{"h2"},
+ GetCertificate: certWatcher.GetCertificate,
+ MinVersion: tlsMinVersion,
+ }
+
+ // load CA to verify client certificate
+ if s.ClientCAName != "" {
+ certPool := x509.NewCertPool()
+ clientCABytes, err := ioutil.ReadFile(filepath.Join(s.CertDir, s.ClientCAName))
+ if err != nil {
+ return fmt.Errorf("failed to read client CA cert: %v", err)
+ }
+
+ ok := certPool.AppendCertsFromPEM(clientCABytes)
+ if !ok {
+ return fmt.Errorf("failed to append client CA cert to CA pool")
+ }
+
+ cfg.ClientCAs = certPool
+ cfg.ClientAuth = tls.RequireAndVerifyClientCert
+ }
+
+ listener, err := tls.Listen("tcp", net.JoinHostPort(s.Host, strconv.Itoa(s.Port)), cfg)
+ if err != nil {
+ return err
+ }
+
+ log.Info("Serving webhook server", "host", s.Host, "port", s.Port)
+
+ srv := &http.Server{
+ Handler: s.WebhookMux,
+ }
+
+ idleConnsClosed := make(chan struct{})
+ go func() {
+ <-ctx.Done()
+ log.Info("shutting down webhook server")
+
+ // TODO: use a context with reasonable timeout
+ if err := srv.Shutdown(context.Background()); err != nil {
+ // Error from closing listeners, or context timeout
+ log.Error(err, "error shutting down the HTTP server")
+ }
+ close(idleConnsClosed)
+ }()
+
+ s.mu.Lock()
+ s.started = true
+ s.mu.Unlock()
+ if err := srv.Serve(listener); err != nil && err != http.ErrServerClosed {
+ return err
+ }
+
+ <-idleConnsClosed
+ return nil
+}
+
+// StartedChecker returns an healthz.Checker which is healthy after the
+// server has been started.
+func (s *Server) StartedChecker() healthz.Checker {
+ config := &tls.Config{
+ InsecureSkipVerify: true, // nolint:gosec // config is used to connect to our own webhook port.
+ }
+ return func(req *http.Request) error {
+ s.mu.Lock()
+ defer s.mu.Unlock()
+
+ if !s.started {
+ return fmt.Errorf("webhook server has not been started yet")
+ }
+
+ d := &net.Dialer{Timeout: 10 * time.Second}
+ conn, err := tls.DialWithDialer(d, "tcp", net.JoinHostPort(s.Host, strconv.Itoa(s.Port)), config)
+ if err != nil {
+ return fmt.Errorf("webhook server is not reachable: %v", err)
+ }
+
+ if err := conn.Close(); err != nil {
+ return fmt.Errorf("webhook server is not reachable: closing connection: %v", err)
+ }
+
+ return nil
+ }
+}
+
+// InjectFunc injects the field setter into the server.
+func (s *Server) InjectFunc(f inject.Func) error {
+ s.setFields = f
+
+ // 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
+}