From ab635c608eb78c1470c0037393c9fe567e01d620 Mon Sep 17 00:00:00 2001 From: Jawed khelil Date: Mon, 5 Feb 2024 08:52:12 +0100 Subject: [PATCH] go mod vendor --- go.mod | 7 +- go.sum | 4 +- .../.gitignore | 0 .../LICENSE | 0 .../manifestival/client-go-client/README.md | 40 ++ .../manifestival/client-go-client/client.go | 84 +++ .../client-go-client/pkg/dynamic/interface.go | 13 + .../dynamic/rest_mapper_resource_interface.go | 48 ++ .../pkg/dynamic/unsafe_resource_interface.go | 27 + .../controller-runtime-client/README.md | 37 -- .../controller-runtime-client/client.go | 95 --- .../pkg/environment/client_config.go | 86 +++ vendor/knative.dev/pkg/injection/README.md | 540 ++++++++++++++++++ vendor/knative.dev/pkg/injection/clients.go | 83 +++ vendor/knative.dev/pkg/injection/config.go | 50 ++ vendor/knative.dev/pkg/injection/context.go | 85 +++ vendor/knative.dev/pkg/injection/doc.go | 105 ++++ vendor/knative.dev/pkg/injection/ducks.go | 40 ++ vendor/knative.dev/pkg/injection/factories.go | 40 ++ .../knative.dev/pkg/injection/health_check.go | 109 ++++ vendor/knative.dev/pkg/injection/informers.go | 134 +++++ vendor/knative.dev/pkg/injection/injection.go | 68 +++ vendor/knative.dev/pkg/injection/interface.go | 144 +++++ vendor/knative.dev/pkg/signals/signal.go | 84 +++ .../knative.dev/pkg/signals/signal_posix.go | 27 + .../knative.dev/pkg/signals/signal_windows.go | 23 + vendor/modules.txt | 8 +- 27 files changed, 1843 insertions(+), 138 deletions(-) rename vendor/github.com/manifestival/{controller-runtime-client => client-go-client}/.gitignore (100%) rename vendor/github.com/manifestival/{controller-runtime-client => client-go-client}/LICENSE (100%) create mode 100644 vendor/github.com/manifestival/client-go-client/README.md create mode 100644 vendor/github.com/manifestival/client-go-client/client.go create mode 100644 vendor/github.com/manifestival/client-go-client/pkg/dynamic/interface.go create mode 100644 vendor/github.com/manifestival/client-go-client/pkg/dynamic/rest_mapper_resource_interface.go create mode 100644 vendor/github.com/manifestival/client-go-client/pkg/dynamic/unsafe_resource_interface.go delete mode 100644 vendor/github.com/manifestival/controller-runtime-client/README.md delete mode 100644 vendor/github.com/manifestival/controller-runtime-client/client.go create mode 100644 vendor/knative.dev/pkg/environment/client_config.go create mode 100644 vendor/knative.dev/pkg/injection/README.md create mode 100644 vendor/knative.dev/pkg/injection/clients.go create mode 100644 vendor/knative.dev/pkg/injection/config.go create mode 100644 vendor/knative.dev/pkg/injection/context.go create mode 100644 vendor/knative.dev/pkg/injection/doc.go create mode 100644 vendor/knative.dev/pkg/injection/ducks.go create mode 100644 vendor/knative.dev/pkg/injection/factories.go create mode 100644 vendor/knative.dev/pkg/injection/health_check.go create mode 100644 vendor/knative.dev/pkg/injection/informers.go create mode 100644 vendor/knative.dev/pkg/injection/injection.go create mode 100644 vendor/knative.dev/pkg/injection/interface.go create mode 100644 vendor/knative.dev/pkg/signals/signal.go create mode 100644 vendor/knative.dev/pkg/signals/signal_posix.go create mode 100644 vendor/knative.dev/pkg/signals/signal_windows.go diff --git a/go.mod b/go.mod index a34955ba..9416b841 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,6 @@ go 1.20 require ( github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 github.com/go-logr/logr v1.4.1 - github.com/manifestival/controller-runtime-client v0.4.0 github.com/manifestival/manifestival v0.7.2 github.com/onsi/ginkgo/v2 v2.15.0 github.com/onsi/gomega v1.31.0 @@ -19,6 +18,11 @@ require ( sigs.k8s.io/controller-runtime v0.14.6 ) +require ( + github.com/manifestival/client-go-client v0.5.0 + knative.dev/pkg v0.0.0-20230320014357-4c84b1b51ee8 +) + require ( contrib.go.opencensus.io/exporter/ocagent v0.7.1-0.20200907061046-05415f1de66d // indirect contrib.go.opencensus.io/exporter/prometheus v0.4.2 // indirect @@ -93,7 +97,6 @@ require ( k8s.io/klog/v2 v2.90.1 // indirect k8s.io/kube-openapi v0.0.0-20230308215209-15aac26d736a // indirect k8s.io/utils v0.0.0-20230313181309-38a27ef9d749 // indirect - knative.dev/pkg v0.0.0-20230320014357-4c84b1b51ee8 // indirect sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect sigs.k8s.io/yaml v1.3.0 // indirect diff --git a/go.sum b/go.sum index 030e19c2..cc2f049b 100644 --- a/go.sum +++ b/go.sum @@ -396,8 +396,8 @@ github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7 github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= -github.com/manifestival/controller-runtime-client v0.4.0 h1:AK+nTZ1rhPTfAc3upnSe3TiOvAWuRmxi1vjEr55dSUM= -github.com/manifestival/controller-runtime-client v0.4.0/go.mod h1:DrsviSegfdlpVsynTUZonKE5gFkMQupenlzVmDbC6S0= +github.com/manifestival/client-go-client v0.5.0 h1:LZUidASM6rwTEI40wtxYDKi+VHhDRnYT4xuYuLjExp4= +github.com/manifestival/client-go-client v0.5.0/go.mod h1:sDehep6aHdIEdUKnRSvueGf2TbQfd653Sn2picTeQqM= github.com/manifestival/manifestival v0.6.0/go.mod h1:3Qq9cnPy7sv7FVhg2Kvw0ebb35R4OdctS4UjTjHlHm4= github.com/manifestival/manifestival v0.7.2 h1:l4uFdWX/xQK4QcRfqGoMtBvaZeWPEuwD6hVsCwUqZY4= github.com/manifestival/manifestival v0.7.2/go.mod h1:nl3T6HlfHCeidooWVTMI9vYNTBkQ1GdhLNb+smozbdk= diff --git a/vendor/github.com/manifestival/controller-runtime-client/.gitignore b/vendor/github.com/manifestival/client-go-client/.gitignore similarity index 100% rename from vendor/github.com/manifestival/controller-runtime-client/.gitignore rename to vendor/github.com/manifestival/client-go-client/.gitignore diff --git a/vendor/github.com/manifestival/controller-runtime-client/LICENSE b/vendor/github.com/manifestival/client-go-client/LICENSE similarity index 100% rename from vendor/github.com/manifestival/controller-runtime-client/LICENSE rename to vendor/github.com/manifestival/client-go-client/LICENSE diff --git a/vendor/github.com/manifestival/client-go-client/README.md b/vendor/github.com/manifestival/client-go-client/README.md new file mode 100644 index 00000000..a2f6637f --- /dev/null +++ b/vendor/github.com/manifestival/client-go-client/README.md @@ -0,0 +1,40 @@ +[![Build Status](https://github.com/manifestival/client-go-client/workflows/Build%20and%20Test/badge.svg)](https://github.com/manifestival/client-go-client/actions) + +# client-go-client + +A [client-go](https://github.com/kubernetes/client-go) implementation +of the [Manifestival](https://github.com/manifestival/manifestival) +`Client`. + +Usage +----- + +```go +import ( + mfc "github.com/manifestival/client-go-client" + mf "github.com/manifestival/manifestival" + "k8s.io/client-go/rest" +) + +func main() { + var config *rest.Config = ... + + manifest, err := mfc.NewManifest("file.yaml", config) + if err != nil { + panic("Failed to load manifest") + } + manifest.Apply() + + // a slightly more complex example + client, _ := mfc.NewClient(config) + m, err := mf.ManifestFrom(mf.Recursive("dir/"), mf.UseClient(client)) + if err != nil { + panic("Failed to load manifest") + } + m.Apply() +} +``` + +The `NewManifest` function in this library delegates to the function +of the same name in the `manifestival` package after constructing a +`manifestival.Client` implementation from the `*rest.Config`. diff --git a/vendor/github.com/manifestival/client-go-client/client.go b/vendor/github.com/manifestival/client-go-client/client.go new file mode 100644 index 00000000..558ed823 --- /dev/null +++ b/vendor/github.com/manifestival/client-go-client/client.go @@ -0,0 +1,84 @@ +package client + +import ( + "context" + mfDynamic "github.com/manifestival/client-go-client/pkg/dynamic" + mf "github.com/manifestival/manifestival" + 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/client-go/dynamic" + "k8s.io/client-go/rest" +) + +// NewManifest returns a manifestival Manifest based on a path and config +func NewManifest(pathname string, config *rest.Config, opts ...mf.Option) (mf.Manifest, error) { + client, err := NewClient(config) + if err != nil { + return mf.Manifest{}, err + } + return mf.NewManifest(pathname, append(opts, mf.UseClient(client))...) +} + +// NewClient returns a manifestival client based on a rest config +func NewClient(config *rest.Config) (mf.Client, error) { + resourceGetter, err := mfDynamic.NewForConfig(config) + if err != nil { + return nil, err + } + return &clientGoClient{resourceGetter: resourceGetter}, nil +} + +// NewUnsafeDynamicClient returns a manifestival client based on dynamic kubernetes client +func NewUnsafeDynamicClient(client dynamic.Interface) (mf.Client, error) { + resourceGetter := mfDynamic.NewUnsafeResourceGetter(client) + return &clientGoClient{resourceGetter: resourceGetter}, nil +} + +type clientGoClient struct { + resourceGetter mfDynamic.ResourceGetter +} + +// verify implementation +var _ mf.Client = (*clientGoClient)(nil) + +func (c *clientGoClient) Create(obj *unstructured.Unstructured, options ...mf.ApplyOption) error { + resource, err := c.resourceGetter.ResourceInterface(obj) + if err != nil { + return err + } + opts := mf.ApplyWith(options) + _, err = resource.Create(context.TODO(), obj, *opts.ForCreate) + return err +} + +func (c *clientGoClient) Update(obj *unstructured.Unstructured, options ...mf.ApplyOption) error { + resource, err := c.resourceGetter.ResourceInterface(obj) + if err != nil { + return err + } + opts := mf.ApplyWith(options) + _, err = resource.Update(context.TODO(), obj, *opts.ForUpdate) + return err +} + +func (c *clientGoClient) Delete(obj *unstructured.Unstructured, options ...mf.DeleteOption) error { + resource, err := c.resourceGetter.ResourceInterface(obj) + if err != nil { + return err + } + opts := mf.DeleteWith(options) + err = resource.Delete(context.TODO(), obj.GetName(), *opts.ForDelete) + if apierrors.IsNotFound(err) && opts.IgnoreNotFound { + return nil + } + return err +} + +func (c *clientGoClient) Get(obj *unstructured.Unstructured) (*unstructured.Unstructured, error) { + resource, err := c.resourceGetter.ResourceInterface(obj) + if err != nil { + return nil, err + } + return resource.Get(context.TODO(), obj.GetName(), metav1.GetOptions{}) +} diff --git a/vendor/github.com/manifestival/client-go-client/pkg/dynamic/interface.go b/vendor/github.com/manifestival/client-go-client/pkg/dynamic/interface.go new file mode 100644 index 00000000..21ae0521 --- /dev/null +++ b/vendor/github.com/manifestival/client-go-client/pkg/dynamic/interface.go @@ -0,0 +1,13 @@ +package dynamic + +import ( + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/client-go/dynamic" +) + +// ResourceGetter is the interface to returning a Resource +type ResourceGetter interface { + // ResourceInterface translates an Unstructured object to a ResourceInterface + // The ResourceInterface can then be used to execute k8s api calls. + ResourceInterface(obj *unstructured.Unstructured) (dynamic.ResourceInterface, error) +} diff --git a/vendor/github.com/manifestival/client-go-client/pkg/dynamic/rest_mapper_resource_interface.go b/vendor/github.com/manifestival/client-go-client/pkg/dynamic/rest_mapper_resource_interface.go new file mode 100644 index 00000000..3360482e --- /dev/null +++ b/vendor/github.com/manifestival/client-go-client/pkg/dynamic/rest_mapper_resource_interface.go @@ -0,0 +1,48 @@ +package dynamic + +import ( + "k8s.io/apimachinery/pkg/api/meta" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/client-go/dynamic" + "k8s.io/client-go/rest" + "sigs.k8s.io/controller-runtime/pkg/client/apiutil" +) + +type clientRestMapper struct { + client dynamic.Interface + mapper meta.RESTMapper +} + +// NewForConfig returns a ResourceGetter for a rest config. +func NewForConfig(config *rest.Config) (ResourceGetter, error) { + client, err := dynamic.NewForConfig(config) + if err != nil { + return nil, err + } + + mapper, err := apiutil.NewDynamicRESTMapper(config) + + if err != nil { + return nil, err + } + + resourceGetter := &clientRestMapper{ + client: client, + mapper: mapper, + } + return resourceGetter, nil +} + +func (cm *clientRestMapper) ResourceInterface(obj *unstructured.Unstructured) (dynamic.ResourceInterface, error) { + gvk := obj.GroupVersionKind() + mapping, err := cm.mapper.RESTMapping(gvk.GroupKind(), gvk.Version) + if err != nil { + return nil, err + } + if mapping.Scope.Name() == meta.RESTScopeNameRoot { + return cm.client.Resource(mapping.Resource), nil + } + return cm.client.Resource(mapping.Resource).Namespace(obj.GetNamespace()), nil +} + +var _ ResourceGetter = (*clientRestMapper)(nil) diff --git a/vendor/github.com/manifestival/client-go-client/pkg/dynamic/unsafe_resource_interface.go b/vendor/github.com/manifestival/client-go-client/pkg/dynamic/unsafe_resource_interface.go new file mode 100644 index 00000000..55e512ca --- /dev/null +++ b/vendor/github.com/manifestival/client-go-client/pkg/dynamic/unsafe_resource_interface.go @@ -0,0 +1,27 @@ +package dynamic + +import ( + "k8s.io/apimachinery/pkg/api/meta" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/client-go/dynamic" +) + +type unsafeResourceInterface struct { + client dynamic.Interface +} + +// NewUnsafeResourceGetter returns a ResourceGetter based on a dynamic client. +// It is considered unsafe because it makes an assumption on the resource name +// based on the Kind. +func NewUnsafeResourceGetter(client dynamic.Interface) ResourceGetter { + return &unsafeResourceInterface{ + client: client, + } +} + +func (unsaferi *unsafeResourceInterface) ResourceInterface(obj *unstructured.Unstructured) (dynamic.ResourceInterface, error) { + plural, _ := meta.UnsafeGuessKindToResource(obj.GroupVersionKind()) + return unsaferi.client.Resource(plural).Namespace(obj.GetNamespace()), nil +} + +var _ ResourceGetter = (*unsafeResourceInterface)(nil) diff --git a/vendor/github.com/manifestival/controller-runtime-client/README.md b/vendor/github.com/manifestival/controller-runtime-client/README.md deleted file mode 100644 index 2774bd73..00000000 --- a/vendor/github.com/manifestival/controller-runtime-client/README.md +++ /dev/null @@ -1,37 +0,0 @@ -# controller-runtime-client - -A [controller-runtime](https://github.com/kubernetes-sigs/controller-runtime) -implementation of the -[Manifestival](https://github.com/manifestival/manifestival) `Client`. - -Usage ------ - -```go -import ( - mfc "github.com/manifestival/controller-runtime-client" - mf "github.com/manifestival/manifestival" - "sigs.k8s.io/controller-runtime/pkg/client" -) - -func main() { - var client client.Client = ... - - manifest, err := mfc.NewManifest("file.yaml", client) - if err != nil { - panic("Failed to load manifest") - } - manifest.Apply() - - // a slightly more complex example - m, err := mf.ManifestFrom(mf.Recursive("dir/"), mf.UseClient(mfc.NewClient(client))) - if err != nil { - panic("Failed to load manifest") - } - m.Apply() -} -``` - -The `NewManifest` function in this library delegates to the function -of the same name in the `manifestival` package after constructing a -`manifestival.Client` implementation from the `client.Client`. diff --git a/vendor/github.com/manifestival/controller-runtime-client/client.go b/vendor/github.com/manifestival/controller-runtime-client/client.go deleted file mode 100644 index 2e890730..00000000 --- a/vendor/github.com/manifestival/controller-runtime-client/client.go +++ /dev/null @@ -1,95 +0,0 @@ -package client - -import ( - "context" - - mf "github.com/manifestival/manifestival" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" - "sigs.k8s.io/controller-runtime/pkg/client" -) - -func NewManifest(pathname string, client client.Client, opts ...mf.Option) (mf.Manifest, error) { - return mf.NewManifest(pathname, append(opts, mf.UseClient(NewClient(client)))...) -} - -func NewClient(client client.Client) mf.Client { - return &controllerRuntimeClient{client: client} -} - -type controllerRuntimeClient struct { - client client.Client -} - -// verify implementation -var _ mf.Client = (*controllerRuntimeClient)(nil) - -func (c *controllerRuntimeClient) Create(obj *unstructured.Unstructured, options ...mf.ApplyOption) error { - return c.client.Create(context.TODO(), obj, createWith(options)...) -} - -func (c *controllerRuntimeClient) Update(obj *unstructured.Unstructured, options ...mf.ApplyOption) error { - return c.client.Update(context.TODO(), obj, updateWith(options)...) -} - -func (c *controllerRuntimeClient) Delete(obj *unstructured.Unstructured, options ...mf.DeleteOption) error { - err := c.client.Delete(context.TODO(), obj, deleteWith(options)...) - opts := mf.DeleteWith(options) - if opts.IgnoreNotFound { - return client.IgnoreNotFound(err) - } - return err -} - -func (c *controllerRuntimeClient) Get(obj *unstructured.Unstructured) (*unstructured.Unstructured, error) { - key := client.ObjectKey{Namespace: obj.GetNamespace(), Name: obj.GetName()} - result := &unstructured.Unstructured{} - result.SetGroupVersionKind(obj.GroupVersionKind()) - err := c.client.Get(context.TODO(), key, result) - return result, err -} - -func createWith(opts []mf.ApplyOption) []client.CreateOption { - result := []client.CreateOption{} - for _, opt := range opts { - if opt == mf.DryRunAll { - result = append(result, client.DryRunAll) - } - if t, ok := opt.(mf.FieldManager); ok { - result = append(result, client.FieldOwner(string(t))) - } - } - return result -} - -func updateWith(opts []mf.ApplyOption) []client.UpdateOption { - result := []client.UpdateOption{} - for _, opt := range opts { - if opt == mf.DryRunAll { - result = append(result, client.DryRunAll) - } - if t, ok := opt.(mf.FieldManager); ok { - result = append(result, client.FieldOwner(string(t))) - } - } - return result -} - -func deleteWith(opts []mf.DeleteOption) []client.DeleteOption { - result := []client.DeleteOption{} - for _, opt := range opts { - if opt == mf.DryRunAll { - result = append(result, client.DryRunAll) - continue - } - switch v := opt.(type) { - case mf.GracePeriodSeconds: - result = append(result, client.GracePeriodSeconds(int64(v))) - case mf.Preconditions: - result = append(result, client.Preconditions(metav1.Preconditions(v))) - case mf.PropagationPolicy: - result = append(result, client.PropagationPolicy(metav1.DeletionPropagation(v))) - } - } - return result -} diff --git a/vendor/knative.dev/pkg/environment/client_config.go b/vendor/knative.dev/pkg/environment/client_config.go new file mode 100644 index 00000000..04d4220b --- /dev/null +++ b/vendor/knative.dev/pkg/environment/client_config.go @@ -0,0 +1,86 @@ +/* +Copyright 2021 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package environment + +import ( + "flag" + "fmt" + "math" + "os" + + "k8s.io/client-go/rest" + "k8s.io/client-go/tools/clientcmd" + clientcmdapi "k8s.io/client-go/tools/clientcmd/api" +) + +// ClientConfig holds the information about the environment and can be configured with flags +type ClientConfig struct { + Cluster string // K8s cluster (defaults to cluster in kubeconfig) + ServerURL string // ServerURL - The address of the Kubernetes API server. Overrides any value in kubeconfig. + Burst int // Burst - Maximum burst for throttle. + QPS float64 // QPS - Maximum QPS to the server from the client. + Kubeconfig string // Kubeconfig - Path to a kubeconfig. Current casing is present for backwards compatibility +} + +func (c *ClientConfig) InitFlags(fs *flag.FlagSet) { + fs.StringVar(&c.Cluster, "cluster", "", "Defaults to the current cluster in kubeconfig.") + + fs.StringVar(&c.ServerURL, "server", "", + "The address of the Kubernetes API server. Overrides any value in kubeconfig. Only required if out-of-cluster.") + + fs.StringVar(&c.Kubeconfig, "kubeconfig", os.Getenv("KUBECONFIG"), + "Path to a kubeconfig. Only required if out-of-cluster.") + + fs.IntVar(&c.Burst, "kube-api-burst", 0, "Maximum burst for throttle.") + + fs.Float64Var(&c.QPS, "kube-api-qps", 0, "Maximum QPS to the server from the client.") +} + +func (c *ClientConfig) GetRESTConfig() (*rest.Config, error) { + if c.Burst < 0 { + return nil, fmt.Errorf("provided burst value %d must be > 0", c.Burst) + } + if c.QPS < 0 || c.QPS > math.MaxFloat32 { + return nil, fmt.Errorf("provided QPS value %f must be >0 and <3.4+e38", c.QPS) + } + + loadingRules := clientcmd.NewDefaultClientConfigLoadingRules() + overrides := &clientcmd.ConfigOverrides{} + + if c.Kubeconfig != "" { + loadingRules.ExplicitPath = c.Kubeconfig + } + if c.Cluster != "" { + overrides.Context = clientcmdapi.Context{Cluster: c.Cluster} + } else if c.ServerURL != "" { + overrides.ClusterInfo = clientcmdapi.Cluster{Server: c.ServerURL} + } + + config, err := clientcmd.NewNonInteractiveDeferredLoadingClientConfig( + loadingRules, + overrides, + ).ClientConfig() + + if err != nil { + return nil, fmt.Errorf("failed to create client config: %w", err) + } + + config.QPS = float32(c.QPS) + config.Burst = c.Burst + + return config, nil +} diff --git a/vendor/knative.dev/pkg/injection/README.md b/vendor/knative.dev/pkg/injection/README.md new file mode 100644 index 00000000..d7c80ada --- /dev/null +++ b/vendor/knative.dev/pkg/injection/README.md @@ -0,0 +1,540 @@ +# Knative Dependency Injection + +This library supports the production of controller processes with minimal +boilerplate outside of the reconciler implementation. + +## Building Controllers + +To adopt this model of controller construction, implementations should start +with the following controller constructor: + +```go +import ( + "context" + + "knative.dev/pkg/configmap" + "knative.dev/pkg/controller" + "knative.dev/pkg/logging" + kindreconciler "knative.dev//pkg/client/injection/reconciler///" +) + +func NewController(ctx context.Context, cmw configmap.Watcher) *controller.Impl { + logger := logging.FromContext(ctx) + + // TODO(you): Access informers + + r := &Reconciler{ + // TODO(you): Pass listers, clients, and other stuff. + } + impl := kindreconciler.NewImpl(ctx, r) + + // TODO(you): Set up event handlers. + + return impl +} +``` + +### Generated Reconcilers + +A code generator is available for simple subset of reconciliation requirements. +A label above the API type will signal to the injection code generator to +generate a strongly typed reconciler. Use `+genreconciler` to generate the +reconcilers. + +```go +// +genclient +// +genreconciler +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +type ExampleType struct { + ... +} +``` + +`+genreconciler` will produce a helper method to get a controller impl. + +Update `NewController` as follows: + +```go +"knative.dev/pkg/controller" +... +impl := controller.NewContext(ctx, c, controller.ControllerOptions{ + Logger: logger, + WorkQueueName: "NameOfController", +}) +``` + +becomes + +```go +kindreconciler "knative.dev//pkg/client/injection/reconciler///" +... +impl := kindreconciler.NewImpl(ctx, c) +``` + +See +[Generated Reconciler Responsibilities](#generated-reconciler-responsibilities) +for more information. + +## Implementing Reconcilers + +Type `Reconciler` is expected to implement `Reconcile`: + +```go +func (r *Reconciler) Reconcile(ctx context.Context, key string) error { + ... +} +``` + +### Generated Reconcilers + +If generated reconcilers are used, Type `Reconciler` is expected to implement +`ReconcileKind`: + +```go +func (r *Reconciler) ReconcileKind(ctx context.Context, o *samplesv1alpha1.AddressableService) reconciler.Event { + ... +} +``` + +And if finalizers are required, + +```go +func (r *Reconciler) FinalizeKind(ctx context.Context, o *samplesv1alpha1.AddressableService) reconciler.Event { + ... +} +``` + +See +[Generated Reconciler Responsibilities](#generated-reconciler-responsibilities) +for more information. + +## Consuming Informers + +Knative controllers use "informers" to set up the various event hooks needed to +queue work, and pass the "listers" fed by the informers' caches to the nested +"Reconciler" for accessing objects. + +Our controller constructor is passed a `context.Context` onto which we inject +any informers we access. The accessors for these informers are in little stub +libraries, which we have hand rolled for Kubernetes (more on how to generate +these below). + +```go +import ( + // These are how you access a client or informer off of the "ctx" passed + // to set up the controller. + "knative.dev/pkg/client/injection/kube/client" + svcinformer "knative.dev/pkg/client/injection/kube/informers/core/v1/service" + + // Other imports ... +) + +func NewController(ctx context.Context, cmw configmap.Watcher) *controller.Impl { + logger := logging.FromContext(ctx) + + // Access informers + svcInformer := svcinformer.Get(ctx) + + c := &Reconciler{ + // Pass the lister and client to the Reconciler. + Client: kubeclient.Get(ctx), + ServiceLister: svcInformer.Lister(), + } + logger = logger.Named("NameOfController") + impl := controller.NewContext(ctx, c, controller.ControllerOptions{ + Logger: logger, + WorkQueueName: "NameOfController", + }) + + // Set up event handlers. + svcInformer.Informer().AddEventHandler(...) + + return impl +} + +``` + +> How it works: by importing the accessor for a client or informer we link it +> and trigger the `init()` method for its package to run at startup. Each of +> these libraries registers themselves similar to our `init()` and controller +> processes can leverage this to setup and inject all of the registered things +> onto a context to pass to your `NewController()`. + +## Testing Controllers + +Similar to `injection.Default`, we also have `injection.Fake`. While linking the +normal accessors sets up the former, linking their fakes set up the latter. + +```go +import ( + "testing" + + // Link the fakes for any informers our controller accesses. + _ "knative.dev/pkg/client/injection/kube/informers/core/v1/service/fake" + + "k8s.io/client-go/rest" + "knative.dev/pkg/injection" + logtesting "knative.dev/pkg/logging/testing" +) + +func TestFoo(t *testing.T) { + ctx := logtesting.TestContextWithLogger(t) + + // Setup a context from all of the injected fakes. + ctx, _ = injection.Fake.SetupInformers(ctx, &rest.Config{}) + cmw := configmap.NewStaticWatcher(...) + ctrl := NewController(ctx, cmw) + + // Test the controller process. +} +``` + +The fake clients also support manually setting up contexts seeded with objects: + +```go +import ( + "testing" + + fakekubeclient "knative.dev/pkg/client/injection/kube/client/fake" + + "k8s.io/client-go/rest" + "knative.dev/pkg/injection" + logtesting "knative.dev/pkg/logging/testing" +) + +func TestFoo(t *testing.T) { + ctx := logtesting.TestContextWithLogger(t) + + objs := []runtime.Object{ + // Some list of initial objects in the client. + } + + ctx, kubeClient := fakekubeclient.With(ctx, objs...) + + // The fake clients returned by our library are the actual fake type, + // which enables us to access test-specific methods, e.g. + kubeClient.AppendReactor(...) + + c := &Reconciler{ + Client: kubeClient, + } + + // Test the reconciler... +} +``` + +## Starting controllers + +All we do is import the controller packages and pass their constructors along +with a component name (single word) to our shared main. Then our shared main +method sets it all up and runs our controllers. + +```go +package main + +import ( + // The set of controllers this process will run. + "github.com/knative/foo/pkg/reconciler/bar" + "github.com/knative/baz/pkg/reconciler/blah" + + // This defines the shared main for injected controllers. + "knative.dev/pkg/injection/sharedmain" +) + +func main() { + sharedmain.Main("componentname", + bar.NewController, + blah.NewController, + ) +} + +``` + +## Generating Injection Stubs. + +To make generating stubs simple, we have harnessed the Kubernetes +code-generation tooling to produce `injection-gen`. Similar to how you might +ordinarily run the other `foo-gen` processed: + +```shell +CODEGEN_PKG=${CODEGEN_PKG:-$(cd ${REPO_ROOT}; ls -d -1 ./vendor/k8s.io/code-generator 2>/dev/null || echo ../code-generator)} + +${CODEGEN_PKG}/generate-groups.sh "deepcopy,client,informer,lister" \ + github.com/knative/sample-controller/pkg/client github.com/knative/sample-controller/pkg/apis \ + "samples:v1alpha1" \ + --go-header-file ${REPO_ROOT}/hack/boilerplate/boilerplate.go.txt +``` + +To run `injection-gen` you run the following (replacing the import path and api +group): + +```shell + +KNATIVE_CODEGEN_PKG=${KNATIVE_CODEGEN_PKG:-$(cd ${REPO_ROOT}; ls -d -1 ./vendor/knative.dev/pkg 2>/dev/null || echo ../pkg)} + +${KNATIVE_CODEGEN_PKG}/hack/generate-knative.sh "injection" \ + github.com/knative/sample-controller/pkg/client github.com/knative/sample-controller/pkg/apis \ + "samples:v1alpha1" \ + --go-header-file ${REPO_ROOT}/hack/boilerplate/boilerplate.go.txt + +``` + +To ensure the appropriate tooling is vendored, add the following to +`Gopkg.toml`: + +```toml +required = [ + "knative.dev/pkg/codegen/cmd/injection-gen", +] + +# .. Constraints + +# Keeps things like the generate-knative.sh script +[[prune.project]] + name = "knative.dev/pkg" + unused-packages = false + non-go = false +``` + +## Generated Reconciler Responsibilities + +The goal of generating the reconcilers is to provide the controller implementer +a strongly typed interface, and ensure correct reconciler behaviour around +status updates, Kubernetes event creation, and queue management. + +We have already helped the queue management with libraries in this repo. But +there was a gap in support and standards around how status updates (and retries) +are performed, and when Kubernetes events are created for the resource. + +The general flow with generated reconcilers looks like the following: + +``` +[k8s] -> [watches] -> [reconciler enqeueue] -> [Reconcile(key)] -> [ReconcileKind(resource)] + ^-- you set up. ^-- generated ^-- stubbed and you customize +``` + +Optionally, support for finalizers: + +``` +[Reconcile(key)] -> - no -> [ReconcileKind(resource)] + ` + (optional) + `- yes -> [FinalizeKind(resource)] +``` + +- `ReconcileKind` is only called if the resource's deletion timestamp is empty. +- `FinalizeKind` is optional, and if implemented by the reconciler will be + called when the resource's deletion timestamp is set. + +The responsibility and consequences of using the generated +`ReconcileKind(resource)` method are as follows: + +- In `NewController`, set up watches and reconciler enqueue requests as before. +- Implementing `ReconcileKind(ctx, resource)` to handle active resources. +- Implementing `FinalizeKind(ctx, resource)` to finalize deleting active + resources. + - NOTE: Implementing `FinalizeKind` will result in the reconciler using + finalizers on the resource. +- Resulting changes from `Reconcile` calling `ReconcileKind(ctx, resource)`: + - DO NOT edit the spec of `resource`, it will be ignored. + - DO NOT edit the metadata of `resource`, it will be ignored. + - If `resource.status` is changed, `Reconcile` will synchronize it back to the + API Server. + - Note: the watches setup for `resource.Kind` will see the update to status + and cause another reconciliation. +- `ReconcileKind(ctx, resource)` returns a + [`reconciler.Event`](../reconciler/events.go) results in: +- If `event` is an `error` (`reconciler.Event` extends `error` internally), + `Reconciler` will produce a `Warning` kubernetes event with _reason_ + `InternalError` and the body of the error as the message. + - Additionally, the `error` will be returned from `Reconciler` and `key` will + requeue back into the reconciler key queue. +- If `event` is a `reconciler.Event`, `Reconciler` will log a typed and reasoned + Kubernetes Event based on the contents of `event`. + - `event` is not considered an error for requeue and nil is returned from + `Reconciler`. +- If additional events are required to be produced, an implementation can pull a + recorder from the context: `recorder := controller.GetEventRecorder(ctx)`. + +Future features to be considered: + +- Document how we leverage `configStore` and specifically + `ctx = r.configStore.ToContext(ctx)` inside `Reconcile`. +- Adjust `+genreconciler` to allow for generated reconcilers to be made without + annotating the type struct. +- Add class-based annotation filtering. + +### ConfigStore + +Config store is used to decorate the context with a snapshot of configmaps to be +used in a reconciler method. + +To add this feature to the generated reconciler, it will have to be passed in on +`reconciler.NewImpl` like so: + +```go +kindreconciler "knative.dev//pkg/client/injection/reconciler///" +... +impl := kindreconciler.NewImpl(ctx, c, func(impl *controller.Impl) controller.Options { + // Setup options that require access to a controller.Impl. + configsToResync := []interface{}{ + &some.Config{}, + } + resyncOnConfigChange := configmap.TypeFilter(configsToResync...)(func(string, interface{}) { + impl.FilteredGlobalResync(myFilterFunc, kindInformer.Informer()) + }) + configStore := config.NewStore(c.Logger.Named("config-store"), resyncOnConfigChange) + configStore.WatchConfigs(cmw) + + // Return the controller options. + return controller.Options{ + ConfigStore: configStore, + } +}) +``` + +### Filtering on controller promotion + +The generated controllers implement the +[LeaderAwareFuncs](https://github.com/knative/pkg/blob/main/reconciler/leader.go#L66-L72) +interface to support HA controller deployments. When a generated controller is +promoted, by default it will trigger [a re-reconcile of every resource it +manages](https://github.com/knative/pkg/blob/main/client/injection/apiextensions/reconciler/apiextensions/v1/customresourcedefinition/controller.go#L68-L81). +To filter which objects get reconciled, pass a `PromoteFilterFunc` to the +controller's constructor: + +```go +kindreconciler "knative.dev//pkg/client/injection/reconciler///" +pkgreconciler "knative.dev/pkg/reconciler" +... +impl := kindreconciler.NewImpl(ctx, c, func(impl *controller.Impl) controller.Options { + return controller.Options{ + PromoteFilterFunc: pkgreconciler.LabelFilterFunc("mylabel", "myvalue", false), + } +}) +``` + + +### Artifacts + +The artifacts are targeted to the configured `client/injection` directory: + +```go +kindreconciler "knative.dev//pkg/client/injection/reconciler///" +``` + +Controller related artifacts: + +- `NewImpl` - gets an injection based client and lister for ``, sets up + Kubernetes Event recorders, and delegates to `controller.NewContext` for queue + management. + +```go +impl := reconciler.NewImpl(ctx, reconcilerInstance) +``` + +Reconciler related artifacts: + +- `Interface` - defines the strongly typed interfaces to be implemented by a + controller reconciling ``. + +```go +// Check that our Reconciler implements Interface +var _ addressableservicereconciler.Interface = (*Reconciler)(nil) +``` + +- `Finalizer` - defines the strongly typed interfaces to be implemented by a + controller finalizing ``. + +```go +// Check that our Reconciler implements Interface +var _ addressableservicereconciler.Finalizer = (*Reconciler)(nil) +``` + +#### Annotation based class filters + +Sometimes a reconciler only wants to reconcile a class of resource identified by +a special annotation on the Custom Resource. + +This behavior can be enabled in the generators by adding the annotation class +key to the type struct: + +```go +// +genreconciler:class=example.com/filter.class +``` + +The `genreconciler` generator code will now have the addition of +`classValue string` to `NewImpl` and `NewReconciler` (for tests): + +```go +NewImpl(ctx context.Context, r Interface, classValue string, optionsFns ...controller.OptionsFn) *controller.Impl +``` + +```go +NewReconciler(ctx context.Context, logger *zap.SugaredLogger, client versioned.Interface, lister pubv1alpha1.BarLister, recorder record.EventRecorder, r Interface, classValue string, options ...controller.Options) controller.Reconciler +``` + +`ReconcileKind` and `FinalizeKind` will NOT be called for resources that DO NOT +have the provided `+genreconciler:class=` key annotation. Additionally the +value of the `` annotation on a resource must match the value provided to +`NewImpl` (or `NewReconcile`) for `ReconcileKind` or `FinalizeKind` to be called +for that resource. + +#### Annotation based common logic + +**krshapedlogic=false may be used to omit common reconciler logic** + +Reconcilers can handle common logic for resources that conform to the KRShaped +interface. This allows the generated code to automatically increment +ObservedGeneration. + +```go +// +genreconciler +``` + +Setting this annotation will emit the following in the generated reconciler. + +```go +reconciler.PreProcessReconcile(ctx, resource) + +reconcileEvent = r.reconciler.ReconcileKind(ctx, resource) + +reconciler.PostProcessReconcile(ctx, resource, oldResource) +``` + +#### Stubs + +To enable stubs generation, add the stubs flag: + +```go +// +genreconciler:stubs +``` + +Or with the class annotation: + +```go +// +genreconciler:class=example.com/filter.class,stubs +``` + +The stubs are intended to be used to get started, or to use as reference. It is +intended to be copied out of the `client` dir. + +`knative.dev//pkg/client/injection/reconciler////stubs/controller.go` + +- A basic implementation of `NewController`. + +`knative.dev//pkg/client/injection/reconciler////stubs/reconciler.go` + +- A basic implementation of `type Reconciler struct {}` and + `Reconciler.ReconcileKind`. +- A commented out example of a basic implementation of + `Reconciler.FinalizeKind`. +- An example `reconciler.Event`: `newReconciledNormal` + +### Examples + +Please look at +[`sample-controller`](http://github.com/knative/sample-controller) or +[`sample-source`](http://github.com/knative/sample-source) for working +integrations of the generated geconciler code. diff --git a/vendor/knative.dev/pkg/injection/clients.go b/vendor/knative.dev/pkg/injection/clients.go new file mode 100644 index 00000000..92e99121 --- /dev/null +++ b/vendor/knative.dev/pkg/injection/clients.go @@ -0,0 +1,83 @@ +/* +Copyright 2019 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package injection + +import ( + "context" + + "k8s.io/client-go/rest" +) + +// ClientInjector holds the type of a callback that attaches a particular +// client type to a context. +type ClientInjector func(context.Context, *rest.Config) context.Context + +// ClientFetcher holds the type of a callback that returns a particular client type +// from a context. +type ClientFetcher func(context.Context) interface{} + +func (i *impl) RegisterClient(ci ClientInjector) { + i.m.Lock() + defer i.m.Unlock() + + i.clients = append(i.clients, ci) +} + +func (i *impl) GetClients() []ClientInjector { + i.m.RLock() + defer i.m.RUnlock() + + // Copy the slice before returning. + return append(i.clients[:0:0], i.clients...) +} + +func (i *impl) RegisterClientFetcher(f ClientFetcher) { + i.m.Lock() + defer i.m.Unlock() + + i.clientFetchers = append(i.clientFetchers, f) +} + +func (i *impl) FetchAllClients(ctx context.Context) []interface{} { + i.m.RLock() + defer i.m.RUnlock() + + clients := make([]interface{}, 0, len(i.clientFetchers)) + for _, f := range i.clientFetchers { + clients = append(clients, f(ctx)) + } + return clients +} + +// DynamicClientInjector holds the type of a callback that attaches a particular +// client type to a context. +type DynamicClientInjector func(context.Context) context.Context + +func (i *impl) RegisterDynamicClient(ci DynamicClientInjector) { + i.m.Lock() + defer i.m.Unlock() + + i.dynamicClients = append(i.dynamicClients, ci) +} + +func (i *impl) GetDynamicClients() []DynamicClientInjector { + i.m.RLock() + defer i.m.RUnlock() + + // Copy the slice before returning. + return append(i.dynamicClients[:0:0], i.dynamicClients...) +} diff --git a/vendor/knative.dev/pkg/injection/config.go b/vendor/knative.dev/pkg/injection/config.go new file mode 100644 index 00000000..c3531b9e --- /dev/null +++ b/vendor/knative.dev/pkg/injection/config.go @@ -0,0 +1,50 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package injection + +import ( + "flag" + "log" + + "k8s.io/client-go/rest" + "k8s.io/klog/v2" + "knative.dev/pkg/environment" +) + +// ParseAndGetRESTConfigOrDie parses the rest config flags and creates a client or +// dies by calling log.Fatalf. +func ParseAndGetRESTConfigOrDie() *rest.Config { + env := new(environment.ClientConfig) + env.InitFlags(flag.CommandLine) + klog.InitFlags(flag.CommandLine) + flag.Parse() + cfg, err := env.GetRESTConfig() + if err != nil { + log.Fatal("Error building kubeconfig: ", err) + } + return cfg +} + +// GetRESTConfig returns a rest.Config to be used for kubernetes client creation. +// Deprecated: use environment.ClientConfig package +func GetRESTConfig(serverURL, kubeconfig string) (*rest.Config, error) { + env := environment.ClientConfig{ + Kubeconfig: kubeconfig, + ServerURL: serverURL, + } + return env.GetRESTConfig() +} diff --git a/vendor/knative.dev/pkg/injection/context.go b/vendor/knative.dev/pkg/injection/context.go new file mode 100644 index 00000000..af8bf22a --- /dev/null +++ b/vendor/knative.dev/pkg/injection/context.go @@ -0,0 +1,85 @@ +/* +Copyright 2019 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package injection + +import ( + "context" + + "k8s.io/client-go/rest" +) + +// nsKey is the key that namespaces are associated with on +// contexts returned by WithNamespaceScope. +type nsKey struct{} + +// WithNamespaceScope associates a namespace scoping with the +// provided context, which will scope the informers produced +// by the downstream informer factories. +func WithNamespaceScope(ctx context.Context, namespace string) context.Context { + return context.WithValue(ctx, nsKey{}, namespace) +} + +// HasNamespaceScope determines whether the provided context has +// been scoped to a particular namespace. +func HasNamespaceScope(ctx context.Context) bool { + return GetNamespaceScope(ctx) != "" +} + +// GetNamespaceScope accesses the namespace associated with the +// provided context. This should be called when the injection +// logic is setting up shared informer factories. +func GetNamespaceScope(ctx context.Context) string { + value := ctx.Value(nsKey{}) + if value == nil { + return "" + } + return value.(string) +} + +// cfgKey is the key that the config is associated with. +type cfgKey struct{} + +// WithConfig associates a given config with the context. +func WithConfig(ctx context.Context, cfg *rest.Config) context.Context { + return context.WithValue(ctx, cfgKey{}, cfg) +} + +// GetConfig gets the current config from the context. +func GetConfig(ctx context.Context) *rest.Config { + value := ctx.Value(cfgKey{}) + if value == nil { + return nil + } + return value.(*rest.Config) +} + +// rvKey is the key that the resource version is associated with. +type rvKey struct{} + +// WithResourceVersion associates a resource version with the context. +func WithResourceVersion(ctx context.Context, resourceVersion string) context.Context { + return context.WithValue(ctx, rvKey{}, resourceVersion) +} + +// GetResourceVersion gets the resource version associated with the context. +func GetResourceVersion(ctx context.Context) string { + value := ctx.Value(rvKey{}) + if value == nil { + return "" + } + return value.(string) +} diff --git a/vendor/knative.dev/pkg/injection/doc.go b/vendor/knative.dev/pkg/injection/doc.go new file mode 100644 index 00000000..960674de --- /dev/null +++ b/vendor/knative.dev/pkg/injection/doc.go @@ -0,0 +1,105 @@ +/* +Copyright 2019 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Package injection defines the mechanisms through which clients, informers +// and shared informer factories are injected into a shared controller binary +// implementation. +// +// There are two primary contexts where the usage of the injection package is +// interesting. The first is in the context of implementations of +// `controller.Reconciler` being wrapped in a `*controller.Impl`: +// +// import ( +// // Simply linking this triggers the injection of the informer, which links +// // the factory triggering its injection, and which links the client, +// // triggering its injection. All you need to know is that it works :) +// deployinformer "knative.dev/pkg/injection/informers/kubeinformers/appsv1/deployment" +// "knative.dev/pkg/injection" +// ) +// +// func NewController(ctx context.Context) *controller.Impl { +// deploymentInformer := deployinformer.Get(ctx) +// // Pass deploymentInformer.Lister() to Reconciler +// ... +// // Set up events on deploymentInformer.Informer() +// ... +// } +// +// Then in `package main` the entire controller process can be set up via: +// +// package main +// +// import ( +// // The set of controllers this controller process runs. +// // Linking these will register their transitive dependencies, after +// // which the shared main can set up the rest. +// "github.com/knative/foo/pkg/reconciler/matt" +// "github.com/knative/foo/pkg/reconciler/scott" +// "github.com/knative/foo/pkg/reconciler/ville" +// "github.com/knative/foo/pkg/reconciler/dave" +// +// // This defines the shared main for injected controllers. +// "knative.dev/pkg/injection/sharedmain" +// ) +// +// func main() { +// sharedmain.Main("mycomponent", +// // We pass in the list of controllers to construct, and that's it! +// // If we forget to add this, go will complain about the unused import. +// matt.NewController, +// scott.NewController, +// ville.NewController, +// dave.NewController, +// ) +// } +// +// If you want to adapt the above to run the controller within a single +// namespace, you can instead do something like: +// +// package main +// +// import ( +// // The set of controllers this controller process runs. +// // Linking these will register their transitive dependencies, after +// // which the shared main can set up the rest. +// "github.com/knative/foo/pkg/reconciler/matt" +// "github.com/knative/foo/pkg/reconciler/scott" +// "github.com/knative/foo/pkg/reconciler/ville" +// "github.com/knative/foo/pkg/reconciler/dave" +// +// // This defines the shared main for injected controllers. +// "knative.dev/pkg/injection/sharedmain" +// +// // These are used to set up the context. +// "knative.dev/pkg/injection" +// "knative.dev/pkg/signals" +// ) +// +// func main() { +// // Scope the shared informer factories to the provided namespace. +// ctx := injection.WithNamespace(signals.NewContext(), "the-namespace") +// +// // Use our initial context when setting up the controllers. +// sharedmain.MainWithContext(ctx, "mycomponent", +// // We pass in the list of controllers to construct, and that's it! +// // If we forget to add this, go will complain about the unused import. +// matt.NewController, +// scott.NewController, +// ville.NewController, +// dave.NewController, +// ) +// } +package injection diff --git a/vendor/knative.dev/pkg/injection/ducks.go b/vendor/knative.dev/pkg/injection/ducks.go new file mode 100644 index 00000000..3c321f68 --- /dev/null +++ b/vendor/knative.dev/pkg/injection/ducks.go @@ -0,0 +1,40 @@ +/* +Copyright 2019 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package injection + +import ( + "context" +) + +// DuckFactoryInjector holds the type of a callback that attaches a particular +// duck-type informer factory to a context. +type DuckFactoryInjector func(context.Context) context.Context + +func (i *impl) RegisterDuck(ii DuckFactoryInjector) { + i.m.Lock() + defer i.m.Unlock() + + i.ducks = append(i.ducks, ii) +} + +func (i *impl) GetDucks() []DuckFactoryInjector { + i.m.RLock() + defer i.m.RUnlock() + + // Copy the slice before returning. + return append(i.ducks[:0:0], i.ducks...) +} diff --git a/vendor/knative.dev/pkg/injection/factories.go b/vendor/knative.dev/pkg/injection/factories.go new file mode 100644 index 00000000..fc913612 --- /dev/null +++ b/vendor/knative.dev/pkg/injection/factories.go @@ -0,0 +1,40 @@ +/* +Copyright 2019 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package injection + +import ( + "context" +) + +// InformerFactoryInjector holds the type of a callback that attaches a particular +// factory type to a context. +type InformerFactoryInjector func(context.Context) context.Context + +func (i *impl) RegisterInformerFactory(ifi InformerFactoryInjector) { + i.m.Lock() + defer i.m.Unlock() + + i.factories = append(i.factories, ifi) +} + +func (i *impl) GetInformerFactories() []InformerFactoryInjector { + i.m.RLock() + defer i.m.RUnlock() + + // Copy the slice before returning. + return append(i.factories[:0:0], i.factories...) +} diff --git a/vendor/knative.dev/pkg/injection/health_check.go b/vendor/knative.dev/pkg/injection/health_check.go new file mode 100644 index 00000000..2899c7e3 --- /dev/null +++ b/vendor/knative.dev/pkg/injection/health_check.go @@ -0,0 +1,109 @@ +/* +Copyright 2023 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package injection + +import ( + "context" + "errors" + "net/http" + "strconv" + "time" + + "knative.dev/pkg/logging" +) + +// HealthCheckDefaultPort defines the default port number for health probes +const HealthCheckDefaultPort = 8080 + +// ServeHealthProbes sets up liveness and readiness probes. +// If user sets no probes explicitly via the context then defaults are added. +func ServeHealthProbes(ctx context.Context, port int) error { + logger := logging.FromContext(ctx) + server := http.Server{ReadHeaderTimeout: time.Minute, Handler: muxWithHandles(ctx), Addr: ":" + strconv.Itoa(port)} + go func() { + <-ctx.Done() + _ = server.Shutdown(ctx) + }() + + // start the web server on port and accept requests + logger.Infof("Probes server listening on port %s", port) + if err := server.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) { + return err + } + return nil +} + +func muxWithHandles(ctx context.Context) *http.ServeMux { + mux := http.NewServeMux() + readiness := getReadinessHandleOrDefault(ctx) + liveness := getLivenessHandleOrDefault(ctx) + mux.HandleFunc("/readiness", *readiness) + mux.HandleFunc("/health", *liveness) + return mux +} + +func newDefaultProbesHandle(sigCtx context.Context) http.HandlerFunc { + logger := logging.FromContext(sigCtx) + return func(w http.ResponseWriter, r *http.Request) { + f := func() error { + select { + // When we get SIGTERM (sigCtx done), let readiness probes start failing. + case <-sigCtx.Done(): + logger.Info("Signal context canceled") + return errors.New("received SIGTERM from kubelet") + default: + return nil + } + } + if err := f(); err != nil { + logger.Errorf("Healthcheck failed: %v", err) + http.Error(w, err.Error(), http.StatusInternalServerError) + } else { + w.WriteHeader(http.StatusOK) + } + } +} + +type addReadinessKey struct{} + +// AddReadiness signals to probe setup logic to add a user provided probe handler +func AddReadiness(ctx context.Context, handlerFunc http.HandlerFunc) context.Context { + return context.WithValue(ctx, addReadinessKey{}, &handlerFunc) +} + +func getReadinessHandleOrDefault(ctx context.Context) *http.HandlerFunc { + if ctx.Value(addReadinessKey{}) != nil { + return ctx.Value(addReadinessKey{}).(*http.HandlerFunc) + } + defaultHandle := newDefaultProbesHandle(ctx) + return &defaultHandle +} + +type addLivenessKey struct{} + +// AddLiveness signals to probe setup logic to add a user provided probe handler +func AddLiveness(ctx context.Context, handlerFunc http.HandlerFunc) context.Context { + return context.WithValue(ctx, addLivenessKey{}, &handlerFunc) +} + +func getLivenessHandleOrDefault(ctx context.Context) *http.HandlerFunc { + if ctx.Value(addLivenessKey{}) != nil { + return ctx.Value(addLivenessKey{}).(*http.HandlerFunc) + } + defaultHandle := newDefaultProbesHandle(ctx) + return &defaultHandle +} diff --git a/vendor/knative.dev/pkg/injection/informers.go b/vendor/knative.dev/pkg/injection/informers.go new file mode 100644 index 00000000..ce5d481e --- /dev/null +++ b/vendor/knative.dev/pkg/injection/informers.go @@ -0,0 +1,134 @@ +/* +Copyright 2019 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package injection + +import ( + "context" + + "k8s.io/client-go/rest" + + "knative.dev/pkg/controller" +) + +// InformerInjector holds the type of a callback that attaches a particular +// informer type to a context. +type InformerInjector func(context.Context) (context.Context, controller.Informer) + +// DynamicInformerInjector holds the type of a callback that attaches a particular +// informer type (backed by a Dynamic) to a context. +type DynamicInformerInjector func(context.Context) context.Context + +// FilteredInformersInjector holds the type of a callback that attaches a set of particular +// filtered informers type to a context. +type FilteredInformersInjector func(context.Context) (context.Context, []controller.Informer) + +func (i *impl) RegisterInformer(ii InformerInjector) { + i.m.Lock() + defer i.m.Unlock() + + i.informers = append(i.informers, ii) +} + +func (i *impl) RegisterDynamicInformer(ii DynamicInformerInjector) { + i.m.Lock() + defer i.m.Unlock() + + i.dynamicInformers = append(i.dynamicInformers, ii) +} + +func (i *impl) RegisterFilteredInformers(fii FilteredInformersInjector) { + i.m.Lock() + defer i.m.Unlock() + + i.filteredInformers = append(i.filteredInformers, fii) +} + +func (i *impl) GetInformers() []InformerInjector { + i.m.RLock() + defer i.m.RUnlock() + + // Copy the slice before returning. + return append(i.informers[:0:0], i.informers...) +} + +func (i *impl) GetDynamicInformers() []DynamicInformerInjector { + i.m.RLock() + defer i.m.RUnlock() + + // Copy the slice before returning. + return append(i.dynamicInformers[:0:0], i.dynamicInformers...) +} + +func (i *impl) GetFilteredInformers() []FilteredInformersInjector { + i.m.RLock() + defer i.m.RUnlock() + + // Copy the slice before returning. + return append(i.filteredInformers[:0:0], i.filteredInformers...) +} + +func (i *impl) SetupDynamic(ctx context.Context) context.Context { + // Based on the reconcilers we have linked, build up a set of clients and inject + // them onto the context. + for _, ci := range i.GetDynamicClients() { + ctx = ci(ctx) + } + + // Based on the reconcilers we have linked, build up a set of informers + // and inject them onto the context. + for _, ii := range i.GetDynamicInformers() { + ctx = ii(ctx) + } + + return ctx +} + +func (i *impl) SetupInformers(ctx context.Context, cfg *rest.Config) (context.Context, []controller.Informer) { + // Based on the reconcilers we have linked, build up a set of clients and inject + // them onto the context. + for _, ci := range i.GetClients() { + ctx = ci(ctx, cfg) + } + + // Based on the reconcilers we have linked, build up a set of informer factories + // and inject them onto the context. + for _, ifi := range i.GetInformerFactories() { + ctx = ifi(ctx) + } + + // Based on the reconcilers we have linked, build up a set of duck informer factories + // and inject them onto the context. + for _, duck := range i.GetDucks() { + ctx = duck(ctx) + } + + // Based on the reconcilers we have linked, build up a set of informers + // and inject them onto the context. + var inf controller.Informer + var filteredinfs []controller.Informer + informers := make([]controller.Informer, 0, len(i.GetInformers())) + for _, ii := range i.GetInformers() { + ctx, inf = ii(ctx) + informers = append(informers, inf) + } + for _, fii := range i.GetFilteredInformers() { + ctx, filteredinfs = fii(ctx) + informers = append(informers, filteredinfs...) + + } + return ctx, informers +} diff --git a/vendor/knative.dev/pkg/injection/injection.go b/vendor/knative.dev/pkg/injection/injection.go new file mode 100644 index 00000000..f06e06f1 --- /dev/null +++ b/vendor/knative.dev/pkg/injection/injection.go @@ -0,0 +1,68 @@ +/* +Copyright 2019 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package injection + +import ( + "context" + + "go.uber.org/zap" + "k8s.io/client-go/rest" + + "knative.dev/pkg/controller" + "knative.dev/pkg/logging" + "knative.dev/pkg/signals" +) + +// EnableInjectionOrDie enables Knative Client Injection, and provides a +// callback to start the informers. Both Context and Config are optional. +// Returns context with rest config set and a callback to start the informers +// after watches have been set. +// +// Typical integration: +// ```go +// +// ctx, startInformers := injection.EnableInjectionOrDie(signals.NewContext(), nil) +// ... start watches with informers, if required ... +// startInformers() +// +// ``` +func EnableInjectionOrDie(ctx context.Context, cfg *rest.Config) (context.Context, func()) { + if ctx == nil { + ctx = signals.NewContext() + } + if cfg == nil { + cfg = ParseAndGetRESTConfigOrDie() + } + + // Respect user provided settings, but if omitted customize the default behavior. + if cfg.QPS == 0 { + cfg.QPS = rest.DefaultQPS + } + if cfg.Burst == 0 { + cfg.Burst = rest.DefaultBurst + } + ctx = WithConfig(ctx, cfg) + + ctx, informers := Default.SetupInformers(ctx, cfg) + + return ctx, func() { + logging.FromContext(ctx).Info("Starting informers...") + if err := controller.StartInformers(ctx.Done(), informers...); err != nil { + logging.FromContext(ctx).Fatalw("Failed to start informers", zap.Error(err)) + } + } +} diff --git a/vendor/knative.dev/pkg/injection/interface.go b/vendor/knative.dev/pkg/injection/interface.go new file mode 100644 index 00000000..15886401 --- /dev/null +++ b/vendor/knative.dev/pkg/injection/interface.go @@ -0,0 +1,144 @@ +/* +Copyright 2019 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package injection + +import ( + "context" + "sync" + + "k8s.io/client-go/rest" + + "knative.dev/pkg/configmap" + "knative.dev/pkg/controller" +) + +// Interface is the interface for interacting with injection +// implementations, such as our Default and Fake below. +type Interface interface { + // RegisterClient registers a new injector callback for associating + // a new client with a context. + RegisterClient(ClientInjector) + + // GetClients fetches all of the registered client injectors. + GetClients() []ClientInjector + + // RegisterClientFetcher registers a new callback that fetches a client from + // a given context. + RegisterClientFetcher(ClientFetcher) + + // FetchAllClients returns all known clients from the given context. + FetchAllClients(context.Context) []interface{} + + // RegisterInformerFactory registers a new injector callback for associating + // a new informer factory with a context. + RegisterInformerFactory(InformerFactoryInjector) + + // GetInformerFactories fetches all of the registered informer factory injectors. + GetInformerFactories() []InformerFactoryInjector + + // RegisterDuck registers a new duck.InformerFactory for a particular type. + RegisterDuck(ii DuckFactoryInjector) + + // GetDucks accesses the set of registered ducks. + GetDucks() []DuckFactoryInjector + + // RegisterInformer registers a new injector callback for associating + // a new informer with a context. + RegisterInformer(InformerInjector) + + // RegisterFilteredInformers registers a new filtered informer injector callback for associating + // a new set of informers with a context. + RegisterFilteredInformers(FilteredInformersInjector) + + // GetInformers fetches all of the registered informer injectors. + GetInformers() []InformerInjector + + // GetFilteredInformers fetches all of the registered filtered informer injectors. + GetFilteredInformers() []FilteredInformersInjector + + // SetupInformers runs all of the injectors against a context, starting with + // the clients and the given rest.Config. The resulting context is returned + // along with a list of the .Informer() for each of the injected informers, + // which is suitable for passing to controller.StartInformers(). + // This does not setup or start any controllers. + SetupInformers(context.Context, *rest.Config) (context.Context, []controller.Informer) +} + +// DynamicInterface is the interface for interacting with dynamicclient-based injection +// implementations, such as Dynamic below. +type DynamicInterface interface { + // RegisterDynamicClient registers a new injector callback for associating + // a new dynamicclient-based client with a context. + RegisterDynamicClient(DynamicClientInjector) + + // GetDynamicClients fetches all of the registered dynamicclient-based client injectors. + GetDynamicClients() []DynamicClientInjector + + // RegisterDynamicInformer registers a new injector callback for associating + // a new dynamicclient-based informer with a context. + RegisterDynamicInformer(DynamicInformerInjector) + + // GetDynamicInformers fetches all of the registered dynamicclient-based informer injectors. + GetDynamicInformers() []DynamicInformerInjector + + // SetupDynamic runs all of the injectors against a context, starting with + // the clients and the given stream. A context infused with the various elements + // is returned. + SetupDynamic(context.Context) context.Context +} + +type ControllerConstructor func(context.Context, configmap.Watcher) *controller.Impl + +// NamedControllerConstructor is a ControllerConstructor with an associated name. +type NamedControllerConstructor struct { + // Name is the name associated with the controller returned by ControllerConstructor. + Name string + // ControllerConstructor is a constructor for a controller. + ControllerConstructor ControllerConstructor +} + +var ( + // Check that impl implements Interface + _ Interface = (*impl)(nil) + + // Default is the injection interface with which informers should register + // to make themselves available to the controller process when reconcilers + // are being run for real. + Default Interface = &impl{} + + // Dynamic is the injection interface to use when bootstrapping a version + // of things based on the prototype dynamicclient-based reconciler framework. + Dynamic DynamicInterface = &impl{} + + // Fake is the injection interface with which informers should register + // to make themselves available to the controller process when it is being + // unit tested. + Fake Interface = &impl{} +) + +type impl struct { + m sync.RWMutex + + clients []ClientInjector + dynamicClients []DynamicClientInjector + clientFetchers []ClientFetcher + factories []InformerFactoryInjector + informers []InformerInjector + dynamicInformers []DynamicInformerInjector + filteredInformers []FilteredInformersInjector + ducks []DuckFactoryInjector +} diff --git a/vendor/knative.dev/pkg/signals/signal.go b/vendor/knative.dev/pkg/signals/signal.go new file mode 100644 index 00000000..65bab425 --- /dev/null +++ b/vendor/knative.dev/pkg/signals/signal.go @@ -0,0 +1,84 @@ +/* +Copyright 2018 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES 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" + "time" +) + +var onlyOneSignalHandler = make(chan struct{}) + +// 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. +func SetupSignalHandler() (stopCh <-chan struct{}) { + close(onlyOneSignalHandler) // panics when called twice + + stop := make(chan struct{}) + c := make(chan os.Signal, 2) + signal.Notify(c, shutdownSignals...) + go func() { + <-c + close(stop) + <-c + os.Exit(1) // second signal. Exit directly. + }() + + return stop +} + +// NewContext creates a new context with SetupSignalHandler() +// as our Done() channel. +func NewContext() context.Context { + return &signalContext{stopCh: SetupSignalHandler()} +} + +type signalContext struct { + stopCh <-chan struct{} +} + +// Deadline implements context.Context +func (scc *signalContext) Deadline() (deadline time.Time, ok bool) { + return +} + +// Done implements context.Context +func (scc *signalContext) Done() <-chan struct{} { + return scc.stopCh +} + +// Err implements context.Context. If the underlying stop channel is closed, Err +// always returns context.Canceled, and nil otherwise. +func (scc *signalContext) Err() error { + select { + case _, ok := <-scc.Done(): + if !ok { + // TODO: revisit this behavior when Deadline() implementation is changed + return context.Canceled + } + default: + } + return nil +} + +// Value implements context.Context +func (scc *signalContext) Value(key interface{}) interface{} { + return nil +} diff --git a/vendor/knative.dev/pkg/signals/signal_posix.go b/vendor/knative.dev/pkg/signals/signal_posix.go new file mode 100644 index 00000000..39345db0 --- /dev/null +++ b/vendor/knative.dev/pkg/signals/signal_posix.go @@ -0,0 +1,27 @@ +//go:build !windows +// +build !windows + +/* +Copyright 2018 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES 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/knative.dev/pkg/signals/signal_windows.go b/vendor/knative.dev/pkg/signals/signal_windows.go new file mode 100644 index 00000000..a5a4026f --- /dev/null +++ b/vendor/knative.dev/pkg/signals/signal_windows.go @@ -0,0 +1,23 @@ +/* +Copyright 2018 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES 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/modules.txt b/vendor/modules.txt index ac237883..c277a708 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -132,9 +132,10 @@ github.com/kelseyhightower/envconfig github.com/mailru/easyjson/buffer github.com/mailru/easyjson/jlexer github.com/mailru/easyjson/jwriter -# github.com/manifestival/controller-runtime-client v0.4.0 +# github.com/manifestival/client-go-client v0.5.0 ## explicit; go 1.15 -github.com/manifestival/controller-runtime-client +github.com/manifestival/client-go-client +github.com/manifestival/client-go-client/pkg/dynamic # github.com/manifestival/manifestival v0.7.2 ## explicit; go 1.15 github.com/manifestival/manifestival @@ -757,7 +758,9 @@ knative.dev/pkg/apis/duck/v1 knative.dev/pkg/changeset knative.dev/pkg/configmap knative.dev/pkg/controller +knative.dev/pkg/environment knative.dev/pkg/hash +knative.dev/pkg/injection knative.dev/pkg/kmap knative.dev/pkg/kmeta knative.dev/pkg/kmp @@ -769,6 +772,7 @@ knative.dev/pkg/metrics/metricskey knative.dev/pkg/network knative.dev/pkg/ptr knative.dev/pkg/reconciler +knative.dev/pkg/signals knative.dev/pkg/system knative.dev/pkg/tracker # sigs.k8s.io/controller-runtime v0.14.6