diff --git a/Gopkg.lock b/Gopkg.lock index 4a1b5e1d79..57bc1e1900 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -304,7 +304,7 @@ version = "v1.4.0" [[projects]] - digest = "1:8dd9272378a4111be95176ffe295d19914a0583238306d0da4006ffba7a26a65" + digest = "1:da523152c84c86f4868f189da82e34bcc7273683d0232ac33773cc4223c2a6a9" name = "github.com/knative/pkg" packages = [ "apis", @@ -324,8 +324,12 @@ "client/clientset/versioned/typed/authentication/v1alpha1/fake", "client/clientset/versioned/typed/istio/v1alpha3", "client/clientset/versioned/typed/istio/v1alpha3/fake", + "codegen/cmd/injection-gen", + "codegen/cmd/injection-gen/args", + "codegen/cmd/injection-gen/generators", "configmap", "controller", + "injection", "kmeta", "kmp", "logging", @@ -339,8 +343,8 @@ "system/testing", "tracker", ] - pruneopts = "NUT" - revision = "17ec1ed50dad75d031eb87430874e1d1d534b77a" + pruneopts = "T" + revision = "c6f03fa600afb9d05c24dbf14ba8b3f41838f28c" [[projects]] branch = "master" @@ -1080,8 +1084,10 @@ "github.com/knative/pkg/apis/duck", "github.com/knative/pkg/apis/duck/v1alpha1", "github.com/knative/pkg/client/clientset/versioned/fake", + "github.com/knative/pkg/codegen/cmd/injection-gen", "github.com/knative/pkg/configmap", "github.com/knative/pkg/controller", + "github.com/knative/pkg/injection", "github.com/knative/pkg/kmeta", "github.com/knative/pkg/logging", "github.com/knative/pkg/logging/logkey", diff --git a/Gopkg.toml b/Gopkg.toml index 70b7710a29..533feec82f 100644 --- a/Gopkg.toml +++ b/Gopkg.toml @@ -8,6 +8,7 @@ required = [ "k8s.io/code-generator/cmd/client-gen", "k8s.io/code-generator/cmd/lister-gen", "k8s.io/code-generator/cmd/informer-gen", + "github.com/knative/pkg/codegen/cmd/injection-gen", "github.com/knative/test-infra/scripts", "github.com/knative/test-infra/tools/dep-collector", ] @@ -18,8 +19,8 @@ required = [ [[override]] name = "github.com/knative/pkg" - # HEAD as of 2019-05-31 - revision = "17ec1ed50dad75d031eb87430874e1d1d534b77a" + # HEAD as of 2919-06-06 + revision = "c6f03fa600afb9d05c24dbf14ba8b3f41838f28c" [[override]] name = "go.uber.org/zap" @@ -74,3 +75,7 @@ required = [ name = "github.com/knative/test-infra" non-go = false +[[prune.project]] + name = "github.com/knative/pkg" + unused-packages = false + non-go = false diff --git a/hack/update-codegen.sh b/hack/update-codegen.sh index ca93317e0b..40636988e1 100755 --- a/hack/update-codegen.sh +++ b/hack/update-codegen.sh @@ -22,6 +22,8 @@ source $(dirname $0)/../vendor/github.com/knative/test-infra/scripts/library.sh CODEGEN_PKG=${CODEGEN_PKG:-$(cd ${REPO_ROOT_DIR}; ls -d -1 ./vendor/k8s.io/code-generator 2>/dev/null || echo ../../../k8s.io/code-generator)} +KNATIVE_CODEGEN_PKG=${KNATIVE_CODEGEN_PKG:-$(cd ${REPO_ROOT_DIR}; ls -d -1 ./vendor/github.com/knative/pkg 2>/dev/null || echo ../pkg)} + # generate the code with: # --output-base because this script should also be able to run inside the vendor dir of # k8s.io/kubernetes. The output-base is needed for the generators to output into the vendor dir @@ -31,6 +33,12 @@ ${CODEGEN_PKG}/generate-groups.sh "deepcopy,client,informer,lister" \ "events:v1alpha1" \ --go-header-file ${REPO_ROOT_DIR}/hack/boilerplate/boilerplate.go.txt +# Knative Injection +${KNATIVE_CODEGEN_PKG}/hack/generate-knative.sh "injection" \ + github.com/GoogleCloudPlatform/cloud-run-events/pkg/client github.com/GoogleCloudPlatform/cloud-run-events/pkg/apis \ + "events:v1alpha1" \ + --go-header-file ${REPO_ROOT_DIR}/hack/boilerplate/boilerplate.go.txt + # Because the kubernetes code generators force pacakges to lowercase, the update-deps script will be confused for # imports of github.com/googlecloudplatform/... We will update that to use the correct casing in the generated code. # The following will find all files (not directories, specified by -type f) under ${REPO_ROOT_DIR}/pkg/client, and diff --git a/pkg/client/injection/client/client.go b/pkg/client/injection/client/client.go new file mode 100644 index 0000000000..39ce651255 --- /dev/null +++ b/pkg/client/injection/client/client.go @@ -0,0 +1,49 @@ +/* +Copyright 2019 Google LLC + +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. +*/ + +// Code generated by injection-gen. DO NOT EDIT. + +package client + +import ( + "context" + + versioned "github.com/GoogleCloudPlatform/cloud-run-events/pkg/client/clientset/versioned" + injection "github.com/knative/pkg/injection" + logging "github.com/knative/pkg/logging" + rest "k8s.io/client-go/rest" +) + +func init() { + injection.Default.RegisterClient(withClient) +} + +// Key is used as the key for associating information with a context.Context. +type Key struct{} + +func withClient(ctx context.Context, cfg *rest.Config) context.Context { + return context.WithValue(ctx, Key{}, versioned.NewForConfigOrDie(cfg)) +} + +// Get extracts the versioned.Interface client from the context. +func Get(ctx context.Context) versioned.Interface { + untyped := ctx.Value(Key{}) + if untyped == nil { + logging.FromContext(ctx).Fatalf( + "Unable to fetch %T from context.", (versioned.Interface)(nil)) + } + return untyped.(versioned.Interface) +} diff --git a/pkg/client/injection/client/fake/fake.go b/pkg/client/injection/client/fake/fake.go new file mode 100644 index 0000000000..4d8ca4c04f --- /dev/null +++ b/pkg/client/injection/client/fake/fake.go @@ -0,0 +1,54 @@ +/* +Copyright 2019 Google LLC + +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. +*/ + +// Code generated by injection-gen. DO NOT EDIT. + +package fake + +import ( + "context" + + fake "github.com/GoogleCloudPlatform/cloud-run-events/pkg/client/clientset/versioned/fake" + client "github.com/GoogleCloudPlatform/cloud-run-events/pkg/client/injection/client" + injection "github.com/knative/pkg/injection" + logging "github.com/knative/pkg/logging" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/client-go/rest" +) + +func init() { + injection.Fake.RegisterClient(withClient) +} + +func withClient(ctx context.Context, cfg *rest.Config) context.Context { + ctx, _ = With(ctx) + return ctx +} + +func With(ctx context.Context, objects ...runtime.Object) (context.Context, *fake.Clientset) { + cs := fake.NewSimpleClientset(objects...) + return context.WithValue(ctx, client.Key{}, cs), cs +} + +// Get extracts the Kubernetes client from the context. +func Get(ctx context.Context) *fake.Clientset { + untyped := ctx.Value(client.Key{}) + if untyped == nil { + logging.FromContext(ctx).Fatalf( + "Unable to fetch %T from context.", (*fake.Clientset)(nil)) + } + return untyped.(*fake.Clientset) +} diff --git a/pkg/client/injection/informers/events/factory/eventsfactory.go b/pkg/client/injection/informers/events/factory/eventsfactory.go new file mode 100644 index 0000000000..831ef49471 --- /dev/null +++ b/pkg/client/injection/informers/events/factory/eventsfactory.go @@ -0,0 +1,52 @@ +/* +Copyright 2019 Google LLC + +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. +*/ + +// Code generated by injection-gen. DO NOT EDIT. + +package eventsfactory + +import ( + "context" + + externalversions "github.com/GoogleCloudPlatform/cloud-run-events/pkg/client/informers/externalversions" + client "github.com/GoogleCloudPlatform/cloud-run-events/pkg/client/injection/client" + controller "github.com/knative/pkg/controller" + injection "github.com/knative/pkg/injection" + logging "github.com/knative/pkg/logging" +) + +func init() { + injection.Default.RegisterInformerFactory(withInformerFactory) +} + +// Key is used as the key for associating information with a context.Context. +type Key struct{} + +func withInformerFactory(ctx context.Context) context.Context { + c := client.Get(ctx) + return context.WithValue(ctx, Key{}, + externalversions.NewSharedInformerFactory(c, controller.GetResyncPeriod(ctx))) +} + +// Get extracts the InformerFactory from the context. +func Get(ctx context.Context) externalversions.SharedInformerFactory { + untyped := ctx.Value(Key{}) + if untyped == nil { + logging.FromContext(ctx).Fatalf( + "Unable to fetch %T from context.", (externalversions.SharedInformerFactory)(nil)) + } + return untyped.(externalversions.SharedInformerFactory) +} diff --git a/pkg/client/injection/informers/events/factory/fake/fake.go b/pkg/client/injection/informers/events/factory/fake/fake.go new file mode 100644 index 0000000000..31c662d239 --- /dev/null +++ b/pkg/client/injection/informers/events/factory/fake/fake.go @@ -0,0 +1,41 @@ +/* +Copyright 2019 Google LLC + +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. +*/ + +// Code generated by injection-gen. DO NOT EDIT. + +package fake + +import ( + "context" + + externalversions "github.com/GoogleCloudPlatform/cloud-run-events/pkg/client/informers/externalversions" + fake "github.com/GoogleCloudPlatform/cloud-run-events/pkg/client/injection/client/fake" + factory "github.com/GoogleCloudPlatform/cloud-run-events/pkg/client/injection/informers/events/factory" + controller "github.com/knative/pkg/controller" + injection "github.com/knative/pkg/injection" +) + +var Get = factory.Get + +func init() { + injection.Fake.RegisterInformerFactory(withInformerFactory) +} + +func withInformerFactory(ctx context.Context) context.Context { + c := fake.Get(ctx) + return context.WithValue(ctx, factory.Key{}, + externalversions.NewSharedInformerFactory(c, controller.GetResyncPeriod(ctx))) +} diff --git a/pkg/client/injection/informers/events/v1alpha1/pubsubsource/fake/fake.go b/pkg/client/injection/informers/events/v1alpha1/pubsubsource/fake/fake.go new file mode 100644 index 0000000000..51f5853169 --- /dev/null +++ b/pkg/client/injection/informers/events/v1alpha1/pubsubsource/fake/fake.go @@ -0,0 +1,40 @@ +/* +Copyright 2019 Google LLC + +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. +*/ + +// Code generated by injection-gen. DO NOT EDIT. + +package fake + +import ( + "context" + + fake "github.com/GoogleCloudPlatform/cloud-run-events/pkg/client/injection/informers/events/factory/fake" + pubsubsource "github.com/GoogleCloudPlatform/cloud-run-events/pkg/client/injection/informers/events/v1alpha1/pubsubsource" + controller "github.com/knative/pkg/controller" + injection "github.com/knative/pkg/injection" +) + +var Get = pubsubsource.Get + +func init() { + injection.Fake.RegisterInformer(withInformer) +} + +func withInformer(ctx context.Context) (context.Context, controller.Informer) { + f := fake.Get(ctx) + inf := f.Events().V1alpha1().PubSubSources() + return context.WithValue(ctx, pubsubsource.Key{}, inf), inf.Informer() +} diff --git a/pkg/client/injection/informers/events/v1alpha1/pubsubsource/pubsubsource.go b/pkg/client/injection/informers/events/v1alpha1/pubsubsource/pubsubsource.go new file mode 100644 index 0000000000..892d25b6a1 --- /dev/null +++ b/pkg/client/injection/informers/events/v1alpha1/pubsubsource/pubsubsource.go @@ -0,0 +1,52 @@ +/* +Copyright 2019 Google LLC + +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. +*/ + +// Code generated by injection-gen. DO NOT EDIT. + +package pubsubsource + +import ( + "context" + + v1alpha1 "github.com/GoogleCloudPlatform/cloud-run-events/pkg/client/informers/externalversions/events/v1alpha1" + factory "github.com/GoogleCloudPlatform/cloud-run-events/pkg/client/injection/informers/events/factory" + controller "github.com/knative/pkg/controller" + injection "github.com/knative/pkg/injection" + logging "github.com/knative/pkg/logging" +) + +func init() { + injection.Default.RegisterInformer(withInformer) +} + +// Key is used for associating the Informer inside the context.Context. +type Key struct{} + +func withInformer(ctx context.Context) (context.Context, controller.Informer) { + f := factory.Get(ctx) + inf := f.Events().V1alpha1().PubSubSources() + return context.WithValue(ctx, Key{}, inf), inf.Informer() +} + +// Get extracts the typed informer from the context. +func Get(ctx context.Context) v1alpha1.PubSubSourceInformer { + untyped := ctx.Value(Key{}) + if untyped == nil { + logging.FromContext(ctx).Fatalf( + "Unable to fetch %T from context.", (v1alpha1.PubSubSourceInformer)(nil)) + } + return untyped.(v1alpha1.PubSubSourceInformer) +} diff --git a/vendor/github.com/knative/pkg/.gitattributes b/vendor/github.com/knative/pkg/.gitattributes new file mode 100644 index 0000000000..95f18a118b --- /dev/null +++ b/vendor/github.com/knative/pkg/.gitattributes @@ -0,0 +1,10 @@ +# This file is documented at https://git-scm.com/docs/gitattributes. +# Linguist-specific attributes are documented at +# https://github.com/github/linguist. + +**/zz_generated.*.go linguist-generated=true +/client/** linguist-generated=true +/test/** coverage-excluded=true +/metrics/gcp_metadata.go coverage-excluded=true + +*.sh text eol=lf diff --git a/vendor/github.com/knative/pkg/.github/issue-template.md b/vendor/github.com/knative/pkg/.github/issue-template.md new file mode 100644 index 0000000000..cb9b5e00a4 --- /dev/null +++ b/vendor/github.com/knative/pkg/.github/issue-template.md @@ -0,0 +1,32 @@ + + +## Expected Behavior + +## Actual Behavior + +## Steps to Reproduce the Problem + +1. +2. +3. + +## Additional Info diff --git a/vendor/github.com/knative/pkg/.github/pull-request-template.md b/vendor/github.com/knative/pkg/.github/pull-request-template.md new file mode 100644 index 0000000000..033ec443c7 --- /dev/null +++ b/vendor/github.com/knative/pkg/.github/pull-request-template.md @@ -0,0 +1,6 @@ + diff --git a/vendor/github.com/knative/pkg/.gitignore b/vendor/github.com/knative/pkg/.gitignore new file mode 100644 index 0000000000..85baa82ae0 --- /dev/null +++ b/vendor/github.com/knative/pkg/.gitignore @@ -0,0 +1,11 @@ +# Operating system temporary files +.DS_Store + +# Editor/IDE specific settings +.idea +.vscode/ +*.iml + +# Temporary output of build tools +bazel-* +*.out diff --git a/vendor/github.com/knative/pkg/CONTRIBUTING.md b/vendor/github.com/knative/pkg/CONTRIBUTING.md new file mode 100644 index 0000000000..16eddb0acd --- /dev/null +++ b/vendor/github.com/knative/pkg/CONTRIBUTING.md @@ -0,0 +1,5 @@ +# Contribution guidelines + +So you want to hack on Knative `pkg`? Yay! Please refer to Knative's overall +[contribution guidelines](https://github.com/knative/docs/blob/master/community/CONTRIBUTING.md) +to find out how you can help. diff --git a/vendor/github.com/knative/pkg/DEVELOPMENT.md b/vendor/github.com/knative/pkg/DEVELOPMENT.md new file mode 100644 index 0000000000..31565202ee --- /dev/null +++ b/vendor/github.com/knative/pkg/DEVELOPMENT.md @@ -0,0 +1,71 @@ +# Development + +This doc explains how to setup a development environment so you can get started +[contributing](https://github.com/knative/docs/blob/master/community/CONTRIBUTING.md) +to Knative `pkg`. Also take a look at: + +- [The pull request workflow](https://github.com/knative/docs/blob/master/community/CONTRIBUTING.md#pull-requests) + +## Getting started + +1. Create [a GitHub account](https://github.com/join) +1. Setup + [GitHub access via SSH](https://help.github.com/articles/connecting-to-github-with-ssh/) +1. Install [requirements](#requirements) +1. Set up your [shell environment](#environment-setup) +1. [Create and checkout a repo fork](#checkout-your-fork) + +Before submitting a PR, see also [CONTRIBUTING.md](./CONTRIBUTING.md). + +### Requirements + +You must install these tools: + +1. [`go`](https://golang.org/doc/install): The language Knative `pkg` is built + in +1. [`git`](https://help.github.com/articles/set-up-git/): For source control +1. [`dep`](https://github.com/golang/dep): For managing external dependencies. + +### Environment setup + +To get started you'll need to set these environment variables (we recommend +adding them to your `.bashrc`): + +1. `GOPATH`: If you don't have one, simply pick a directory and add + `export GOPATH=...` +1. `$GOPATH/bin` on `PATH`: This is so that tooling installed via `go get` will + work properly. + +`.bashrc` example: + +```shell +export GOPATH="$HOME/go" +export PATH="${PATH}:${GOPATH}/bin" +``` + +### Checkout your fork + +The Go tools require that you clone the repository to the +`src/github.com/knative/pkg` directory in your +[`GOPATH`](https://github.com/golang/go/wiki/SettingGOPATH). + +To check out this repository: + +1. Create your own + [fork of this repo](https://help.github.com/articles/fork-a-repo/) +1. Clone it to your machine: + +```shell +mkdir -p ${GOPATH}/src/github.com/knative +cd ${GOPATH}/src/github.com/knative +git clone git@github.com:${YOUR_GITHUB_USERNAME}/pkg.git +cd pkg +git remote add upstream git@github.com:knative/pkg.git +git remote set-url --push upstream no_push +``` + +_Adding the `upstream` remote sets you up nicely for regularly +[syncing your fork](https://help.github.com/articles/syncing-a-fork/)._ + +Once you reach this point you are ready to do a full build and deploy as +described below. diff --git a/vendor/github.com/knative/pkg/Gopkg.lock b/vendor/github.com/knative/pkg/Gopkg.lock new file mode 100644 index 0000000000..67eb5019ab --- /dev/null +++ b/vendor/github.com/knative/pkg/Gopkg.lock @@ -0,0 +1,1180 @@ +# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'. + + +[[projects]] + digest = "1:ef8da480a66d7e8e9819261c3526685601b573e0005e84b75e47548d82021a7d" + name = "cloud.google.com/go" + packages = [ + "compute/metadata", + "container/apiv1", + "internal/version", + "monitoring/apiv3", + "trace/apiv2", + ] + pruneopts = "NUT" + revision = "0ebda48a7f143b1cce9eb37a8c1106ac762a3430" + version = "v0.34.0" + +[[projects]] + digest = "1:43fbf05ea84c860a4e86b557d156b1e72511cd29375d3f71adb522362710aea7" + name = "contrib.go.opencensus.io/exporter/stackdriver" + packages = [ + ".", + "monitoredresource", + ] + pruneopts = "NUT" + revision = "ab5a58af316a529613aadf9f50eeed1b6f044b2f" + version = "v0.9.2" + +[[projects]] + branch = "master" + digest = "1:cef70b547ce62d12ea8e5dcb9905bccb57ea1bb253ee6809fd79a17c29ca3cd5" + name = "contrib.go.opencensus.io/resource" + packages = ["resourcekeys"] + pruneopts = "NUT" + revision = "21591786a5e0c21806209b266cc6dfdfa85b3cdb" + +[[projects]] + digest = "1:4a31397b1b81c6856aab6d2d963a727b4235af18adaaedc2cc51646ae812f683" + name = "github.com/aws/aws-sdk-go" + packages = [ + "aws", + "aws/awserr", + "aws/awsutil", + "aws/client", + "aws/client/metadata", + "aws/corehandlers", + "aws/credentials", + "aws/credentials/ec2rolecreds", + "aws/credentials/endpointcreds", + "aws/credentials/processcreds", + "aws/credentials/stscreds", + "aws/csm", + "aws/defaults", + "aws/ec2metadata", + "aws/endpoints", + "aws/request", + "aws/session", + "aws/signer/v4", + "internal/ini", + "internal/sdkio", + "internal/sdkrand", + "internal/sdkuri", + "internal/shareddefaults", + "private/protocol", + "private/protocol/query", + "private/protocol/query/queryutil", + "private/protocol/rest", + "private/protocol/xml/xmlutil", + "service/sts", + ] + pruneopts = "NUT" + revision = "3991042237b45cf58c9d5f34295942d5533c28c6" + version = "v1.16.11" + +[[projects]] + branch = "master" + digest = "1:707ebe952a8b3d00b343c01536c79c73771d100f63ec6babeaed5c79e2b8a8dd" + name = "github.com/beorn7/perks" + packages = ["quantile"] + pruneopts = "NUT" + revision = "3a771d992973f24aa725d07868b467d1ddfceafb" + +[[projects]] + digest = "1:fa965c1fd0f17153f608037e109e62104058bc1d08d44849867795fd306fa8b8" + name = "github.com/census-instrumentation/opencensus-proto" + packages = [ + "gen-go/agent/common/v1", + "gen-go/metrics/v1", + "gen-go/resource/v1", + ] + pruneopts = "NUT" + revision = "7f2434bc10da710debe5c4315ed6d4df454b4024" + version = "v0.1.0" + +[[projects]] + digest = "1:6b21090f60571b20b3ddc2c8e48547dffcf409498ed6002c2cada023725ed377" + name = "github.com/davecgh/go-spew" + packages = ["spew"] + pruneopts = "NUT" + revision = "782f4967f2dc4564575ca782fe2d04090b5faca8" + +[[projects]] + digest = "1:32598368f409bbee79deb9d43569fcd92b9fb27f39155f5e166b3371217f051f" + name = "github.com/evanphx/json-patch" + packages = ["."] + pruneopts = "NUT" + revision = "72bf35d0ff611848c1dc9df0f976c81192392fa5" + version = "v4.1.0" + +[[projects]] + digest = "1:abfe129dc92b16fbf0cc9d6336096a2823151756f62072a700eb10754141b38e" + name = "github.com/ghodss/yaml" + packages = ["."] + pruneopts = "NUT" + revision = "73d445a93680fa1a78ae23a5839bad48f32ba1ee" + +[[projects]] + digest = "1:373397317168dd5ac00efda13940668f1947fd641f572b9cf386a86a99c63ca9" + name = "github.com/gobuffalo/envy" + packages = ["."] + pruneopts = "NUT" + revision = "801d7253ade1f895f74596b9a96147ed2d3b087e" + version = "v1.6.11" + +[[projects]] + digest = "1:a6afc27b2a73a5506832f3c5a1c19a30772cb69e7bd1ced4639eb36a55db224f" + name = "github.com/gogo/protobuf" + packages = [ + "proto", + "sortkeys", + ] + pruneopts = "NUT" + revision = "c0656edd0d9eab7c66d1eb0c568f9039345796f7" + +[[projects]] + digest = "1:78b8040ece2ff622580def2708b9eb0b2857711b6744c475439bf337e9c677ea" + name = "github.com/golang/glog" + packages = ["."] + pruneopts = "NUT" + revision = "44145f04b68cf362d9c4df2182967c2275eaefed" + +[[projects]] + branch = "master" + digest = "1:b7cb6054d3dff43b38ad2e92492f220f57ae6087ee797dca298139776749ace8" + name = "github.com/golang/groupcache" + packages = ["lru"] + pruneopts = "NUT" + revision = "5b532d6fd5efaf7fa130d4e859a2fde0fc3a9e1b" + +[[projects]] + digest = "1:4dacf728c83400b3e9d1d3025dd3c1e93e9a1b033726d1b193dc209f3fa9cb7a" + name = "github.com/golang/protobuf" + packages = [ + "proto", + "protoc-gen-go/descriptor", + "ptypes", + "ptypes/any", + "ptypes/duration", + "ptypes/empty", + "ptypes/struct", + "ptypes/timestamp", + "ptypes/wrappers", + ] + pruneopts = "NUT" + revision = "aa810b61a9c79d51363740d207bb46cf8e620ed5" + version = "v1.2.0" + +[[projects]] + branch = "master" + digest = "1:245bd4eb633039cd66106a5d340ae826d87f4e36a8602fcc940e14176fd26ea7" + name = "github.com/google/btree" + packages = ["."] + pruneopts = "NUT" + revision = "e89373fe6b4a7413d7acd6da1725b83ef713e6e4" + +[[projects]] + digest = "1:010d46ea3c1e730897e53058d1013a963f3f987675dda87df64f891b945281db" + name = "github.com/google/go-cmp" + packages = [ + "cmp", + "cmp/cmpopts", + "cmp/internal/diff", + "cmp/internal/flags", + "cmp/internal/function", + "cmp/internal/value", + ] + pruneopts = "NUT" + revision = "6f77996f0c42f7b84e5a2b252227263f93432e9b" + +[[projects]] + digest = "1:f9425215dccf1c63f659ec781ca46bc81804341821d0cd8d2459c5b58f8bd067" + name = "github.com/google/gofuzz" + packages = ["."] + pruneopts = "NUT" + revision = "44d81051d367757e1c7c6a5a86423ece9afcf63c" + +[[projects]] + branch = "master" + digest = "1:0d5e3798bfa2642ac268341c96710b8def1f3cbc3bc803c421d90704d72107d8" + name = "github.com/google/licenseclassifier" + packages = [ + ".", + "internal/sets", + "stringclassifier", + "stringclassifier/internal/pq", + "stringclassifier/searchset", + "stringclassifier/searchset/tokenizer", + ] + pruneopts = "NUT" + revision = "e979a0b10eebe748549c702a25e997c556349da6" + +[[projects]] + digest = "1:ab3ec1fe3e39bac4b3ab63390767766622be35b7cab03f47f787f9ec60522a53" + name = "github.com/google/uuid" + packages = ["."] + pruneopts = "NUT" + revision = "0cd6bf5da1e1c83f8b45653022c74f71af0538a4" + version = "v1.1.1" + +[[projects]] + digest = "1:fd4d1f4c2d75aee3833ee7d8ef11fcf42ddec3c63d1819548288c3d868d6eb14" + name = "github.com/googleapis/gax-go" + packages = [ + ".", + "v2", + ] + pruneopts = "NUT" + revision = "c8a15bac9b9fe955bd9f900272f9a306465d28cf" + version = "v2.0.3" + +[[projects]] + digest = "1:27b4ab41ffdc76ad6db56db327a4db234a59588ef059fc3fd678ba0bc6b9094f" + name = "github.com/googleapis/gnostic" + packages = [ + "OpenAPIv2", + "compiler", + "extensions", + ] + pruneopts = "NUT" + revision = "0c5108395e2debce0d731cf0287ddf7242066aba" + +[[projects]] + digest = "1:4a0c072e44da763409da72d41492373a034baf2e6d849c76d239b4abdfbb6c49" + name = "github.com/gorilla/websocket" + packages = ["."] + pruneopts = "NUT" + revision = "66b9c49e59c6c48f0ffce28c2d8b8a5678502c6d" + version = "v1.4.0" + +[[projects]] + branch = "master" + digest = "1:7fdf3223c7372d1ced0b98bf53457c5e89d89aecbad9a77ba9fcc6e01f9e5621" + name = "github.com/gregjones/httpcache" + packages = [ + ".", + "diskcache", + ] + pruneopts = "NUT" + revision = "9cad4c3443a7200dd6400aef47183728de563a38" + +[[projects]] + digest = "1:475b179287e8afdcd352014b2c2500e67decdf63e66125e2129286873453e1cd" + name = "github.com/hashicorp/golang-lru" + packages = [ + ".", + "simplelru", + ] + pruneopts = "NUT" + revision = "a0d98a5f288019575c6d1f4bb1573fef2d1fcdc4" + +[[projects]] + digest = "1:9a52adf44086cead3b384e5d0dbf7a1c1cce65e67552ee3383a8561c42a18cd3" + name = "github.com/imdario/mergo" + packages = ["."] + pruneopts = "NUT" + revision = "9f23e2d6bd2a77f959b2bf6acdbefd708a83a4a4" + version = "v0.3.6" + +[[projects]] + digest = "1:1f2aebae7e7c856562355ec0198d8ca2fa222fb05e5b1b66632a1fce39631885" + name = "github.com/jmespath/go-jmespath" + packages = ["."] + pruneopts = "NUT" + revision = "c2b33e84" + +[[projects]] + digest = "1:da62aa6632d04e080b8a8b85a59ed9ed1550842a0099a55f3ae3a20d02a3745a" + name = "github.com/joho/godotenv" + packages = ["."] + pruneopts = "NUT" + revision = "23d116af351c84513e1946b527c88823e476be13" + version = "v1.3.0" + +[[projects]] + digest = "1:0243cffa4a3410f161ee613dfdd903a636d07e838a42d341da95d81f42cd1d41" + name = "github.com/json-iterator/go" + packages = ["."] + pruneopts = "NUT" + revision = "f2b4162afba35581b6d4a50d3b8f34e33c144682" + +[[projects]] + branch = "master" + digest = "1:1bfc083da5bbeb7abaac53c56890eb14eb11bac9ec985bfe338c4bbb0540c9ba" + name = "github.com/knative/test-infra" + packages = [ + "scripts", + "tools/dep-collector", + ] + pruneopts = "UT" + revision = "1576da30069624094cf01719452da944b3046826" + +[[projects]] + digest = "1:56dbf15e091bf7926cb33a57cb6bdfc658fc6d3498d2f76f10a97ce7856f1fde" + name = "github.com/markbates/inflect" + packages = ["."] + pruneopts = "NUT" + revision = "24b83195037b3bc61fcda2d28b7b0518bce293b6" + version = "v1.0.4" + +[[projects]] + branch = "master" + digest = "1:0e9bfc47ab9941ecc3344e580baca5deb4091177e84dd9773b48b38ec26b93d5" + name = "github.com/mattbaird/jsonpatch" + packages = ["."] + pruneopts = "NUT" + revision = "81af80346b1a01caae0cbc27fd3c1ba5b11e189f" + +[[projects]] + digest = "1:5985ef4caf91ece5d54817c11ea25f182697534f8ae6521eadcd628c142ac4b6" + name = "github.com/matttproud/golang_protobuf_extensions" + packages = ["pbutil"] + pruneopts = "NUT" + revision = "c12348ce28de40eed0136aa2b644d0ee0650e56c" + version = "v1.0.1" + +[[projects]] + digest = "1:2f42fa12d6911c7b7659738758631bec870b7e9b4c6be5444f963cdcfccc191f" + name = "github.com/modern-go/concurrent" + packages = ["."] + pruneopts = "NUT" + revision = "bacd9c7ef1dd9b15be4a9909b8ac7a4e313eec94" + version = "1.0.3" + +[[projects]] + digest = "1:c6aca19413b13dc59c220ad7430329e2ec454cc310bc6d8de2c7e2b93c18a0f6" + name = "github.com/modern-go/reflect2" + packages = ["."] + pruneopts = "NUT" + revision = "4b7aa43c6742a2c18fdef89dd197aaae7dac7ccd" + version = "1.0.1" + +[[projects]] + digest = "1:22d4043da943b919108e0d1b07983b8d29edeadfba9fb8f3213208d3e9798aae" + name = "github.com/openzipkin/zipkin-go" + packages = [ + ".", + "idgenerator", + "model", + "propagation", + "reporter", + "reporter/http", + "reporter/recorder", + ] + pruneopts = "NUT" + revision = "1b5162aa314e6ccfcf83777bfb5218988c9e8283" + version = "v0.1.6" + +[[projects]] + branch = "master" + digest = "1:3bf17a6e6eaa6ad24152148a631d18662f7212e21637c2699bff3369b7f00fa2" + name = "github.com/petar/GoLLRB" + packages = ["llrb"] + pruneopts = "NUT" + revision = "53be0d36a84c2a886ca057d34b6aa4468df9ccb4" + +[[projects]] + digest = "1:6c6d91dc326ed6778783cff869c49fb2f61303cdd2ebbcf90abe53505793f3b6" + name = "github.com/peterbourgon/diskv" + packages = ["."] + pruneopts = "NUT" + revision = "5f041e8faa004a95c88a202771f4cc3e991971e6" + version = "v2.0.1" + +[[projects]] + digest = "1:14715f705ff5dfe0ffd6571d7d201dd8e921030f8070321a79380d8ca4ec1a24" + name = "github.com/pkg/errors" + packages = ["."] + pruneopts = "NUT" + revision = "ba968bfe8b2f7e042a574c888954fccecfa385b4" + version = "v0.8.1" + +[[projects]] + digest = "1:7c7cfeecd2b7147bcfec48a4bf622b4879e26aec145a9e373ce51d0c23b16f6b" + name = "github.com/prometheus/client_golang" + packages = [ + "prometheus", + "prometheus/internal", + "prometheus/promhttp", + ] + pruneopts = "NUT" + revision = "505eaef017263e299324067d40ca2c48f6a2cf50" + version = "v0.9.2" + +[[projects]] + branch = "master" + digest = "1:2d5cd61daa5565187e1d96bae64dbbc6080dacf741448e9629c64fd93203b0d4" + name = "github.com/prometheus/client_model" + packages = ["go"] + pruneopts = "NUT" + revision = "5c3871d89910bfb32f5fcab2aa4b9ec68e65a99f" + +[[projects]] + branch = "master" + digest = "1:fad5a35eea6a1a33d6c8f949fbc146f24275ca809ece854248187683f52cc30b" + name = "github.com/prometheus/common" + packages = [ + "expfmt", + "internal/bitbucket.org/ww/goautoneg", + "model", + ] + pruneopts = "NUT" + revision = "c7de2306084e37d54b8be01f3541a8464345e9a5" + +[[projects]] + branch = "master" + digest = "1:102dea0c03a915acfc634b7c67f2662012b5483b56d9025e33f5188e112759b6" + name = "github.com/prometheus/procfs" + packages = [ + ".", + "internal/util", + "nfs", + "xfs", + ] + pruneopts = "NUT" + revision = "185b4288413d2a0dd0806f78c90dde719829e5ae" + +[[projects]] + digest = "1:e09ada96a5a41deda4748b1659cc8953961799e798aea557257b56baee4ecaf3" + name = "github.com/rogpeppe/go-internal" + packages = [ + "modfile", + "module", + "semver", + ] + pruneopts = "NUT" + revision = "4bbc89b6501cca7dd6b5557d78d70c8d2c6e8b97" + +[[projects]] + digest = "1:d917313f309bda80d27274d53985bc65651f81a5b66b820749ac7f8ef061fd04" + name = "github.com/sergi/go-diff" + packages = ["diffmatchpatch"] + pruneopts = "NUT" + revision = "1744e2970ca51c86172c8190fadad617561ed6e7" + version = "v1.0.0" + +[[projects]] + digest = "1:9d8420bbf131d1618bde6530af37c3799340d3762cc47210c1d9532a4c3a2779" + name = "github.com/spf13/pflag" + packages = ["."] + pruneopts = "NUT" + revision = "298182f68c66c05229eb03ac171abe6e309ee79a" + version = "v1.0.3" + +[[projects]] + digest = "1:b8baa7541ef444be218da02d3a7b607d33513263660e489d86d429afbffcdd86" + name = "go.opencensus.io" + packages = [ + ".", + "exporter/prometheus", + "exporter/zipkin", + "internal", + "internal/tagencoding", + "metric/metricdata", + "metric/metricproducer", + "plugin/ocgrpc", + "plugin/ochttp", + "plugin/ochttp/propagation/b3", + "resource", + "stats", + "stats/internal", + "stats/view", + "tag", + "trace", + "trace/internal", + "trace/propagation", + "trace/tracestate", + ] + pruneopts = "NUT" + revision = "75c0cca22312e51bfd4fafdbe9197ae399e18b38" + version = "v0.20.2" + +[[projects]] + digest = "1:22f696cee54865fb8e9ff91df7b633f6b8f22037a8015253c6b6a71ca82219c7" + name = "go.uber.org/atomic" + packages = ["."] + pruneopts = "NUT" + revision = "1ea20fb1cbb1cc08cbd0d913a96dead89aa18289" + version = "v1.3.2" + +[[projects]] + digest = "1:58ca93bdf81bac106ded02226b5395a0595d5346cdc4caa8d9c1f3a5f8f9976e" + name = "go.uber.org/multierr" + packages = ["."] + pruneopts = "NUT" + revision = "3c4937480c32f4c13a875a1829af76c98ca3d40a" + version = "v1.1.0" + +[[projects]] + digest = "1:5ab79d2a36037de1ab2908733a2cab0c08b12f6956e3e1eab07cd1b2abf7b903" + name = "go.uber.org/zap" + packages = [ + ".", + "buffer", + "internal/bufferpool", + "internal/color", + "internal/exit", + "internal/ztest", + "zapcore", + "zaptest", + ] + pruneopts = "NUT" + revision = "67bc79d13d155c02fd008f721863ff8cc5f30659" + +[[projects]] + digest = "1:624a05c7c6ed502bf77364cd3d54631383dafc169982fddd8ee77b53c3d9cccf" + name = "golang.org/x/crypto" + packages = ["ssh/terminal"] + pruneopts = "NUT" + revision = "81e90905daefcd6fd217b62423c0908922eadb30" + +[[projects]] + branch = "master" + digest = "1:3033eba8bb0c8f2c6720e68e4c14e55b577ae9debb5f5b7b8cc6f319d89edc82" + name = "golang.org/x/net" + packages = [ + "context", + "context/ctxhttp", + "http/httpguts", + "http2", + "http2/hpack", + "idna", + "internal/timeseries", + "trace", + ] + pruneopts = "NUT" + revision = "49bb7cea24b1df9410e1712aa6433dae904ff66a" + +[[projects]] + branch = "master" + digest = "1:dcb89c032286a9c3c5118a1496f8e0e237c1437f5356ac9602f6fdef560a5c21" + name = "golang.org/x/oauth2" + packages = [ + ".", + "google", + "internal", + "jws", + "jwt", + ] + pruneopts = "NUT" + revision = "c57b0facaced709681d9f90397429b9430a74754" + +[[projects]] + branch = "master" + digest = "1:c313aef534e493304f3666fbd24dca5932ebf776a82b7a40f961c9355794a1b1" + name = "golang.org/x/sync" + packages = [ + "errgroup", + "semaphore", + ] + pruneopts = "NUT" + revision = "1d60e4601c6fd243af51cc01ddf169918a5407ca" + +[[projects]] + branch = "master" + digest = "1:a801d3c417117b67a96353daad340b250619780b75c29b652ea13697c946553e" + name = "golang.org/x/sys" + packages = [ + "unix", + "windows", + ] + pruneopts = "NUT" + revision = "e072cadbbdc8dd3d3ffa82b8b4b9304c261d9311" + +[[projects]] + digest = "1:e7071ed636b5422cc51c0e3a6cebc229d6c9fffc528814b519a980641422d619" + name = "golang.org/x/text" + packages = [ + "collate", + "collate/build", + "internal/colltab", + "internal/gen", + "internal/tag", + "internal/triegen", + "internal/ucd", + "language", + "secure/bidirule", + "transform", + "unicode/bidi", + "unicode/cldr", + "unicode/norm", + "unicode/rangetable", + ] + pruneopts = "NUT" + revision = "f21a4dfb5e38f5895301dc265a8def02365cc3d0" + version = "v0.3.0" + +[[projects]] + digest = "1:d37b0ef2944431fe9e8ef35c6fffc8990d9e2ca300588df94a6890f3649ae365" + name = "golang.org/x/time" + packages = ["rate"] + pruneopts = "NUT" + revision = "f51c12702a4d776e4c1fa9b0fabab841babae631" + +[[projects]] + branch = "master" + digest = "1:e1c96c8c8ce0af57da9dccb008e540b3d13b55ea04b530fb4fceb81706082bdd" + name = "golang.org/x/tools" + packages = [ + "go/ast/astutil", + "imports", + "internal/fastwalk", + ] + pruneopts = "NUT" + revision = "bfb5194568d3c40db30de765edc44cae9fc94671" + +[[projects]] + branch = "master" + digest = "1:7689634b1a2940f3e725a37a7598b5462674a5b016b17d8ce22c8f71cacb0b34" + name = "google.golang.org/api" + packages = [ + "googleapi/transport", + "internal", + "iterator", + "option", + "support/bundler", + "transport", + "transport/grpc", + "transport/http", + "transport/http/internal/propagation", + ] + pruneopts = "NUT" + revision = "ce4acf611b3920b111e21272a15ddaea10c1fd2e" + +[[projects]] + digest = "1:898bf528e5c601c4a1111586f75ab9515467ebe7a41ae849d5a839720d4e2580" + name = "google.golang.org/appengine" + packages = [ + ".", + "internal", + "internal/app_identity", + "internal/base", + "internal/datastore", + "internal/log", + "internal/modules", + "internal/remote_api", + "internal/socket", + "internal/urlfetch", + "socket", + "urlfetch", + ] + pruneopts = "NUT" + revision = "e9657d882bb81064595ca3b56cbe2546bbabf7b1" + version = "v1.4.0" + +[[projects]] + branch = "master" + digest = "1:3689f4cc57cc55b4631efc4b778c47d2a888a7060b4108f42cf289a2033be5ba" + name = "google.golang.org/genproto" + packages = [ + "googleapis/api", + "googleapis/api/annotations", + "googleapis/api/distribution", + "googleapis/api/label", + "googleapis/api/metric", + "googleapis/api/monitoredres", + "googleapis/container/v1", + "googleapis/devtools/cloudtrace/v2", + "googleapis/monitoring/v3", + "googleapis/rpc/status", + "protobuf/field_mask", + ] + pruneopts = "NUT" + revision = "e7d98fc518a78c9f8b5ee77be7b0b317475d89e1" + +[[projects]] + digest = "1:40d377bfddee53c669db275071aa08b68d021941311580d902ab7c862d8741c1" + name = "google.golang.org/grpc" + packages = [ + ".", + "balancer", + "balancer/base", + "balancer/roundrobin", + "binarylog/grpc_binarylog_v1", + "codes", + "connectivity", + "credentials", + "credentials/internal", + "credentials/oauth", + "encoding", + "encoding/proto", + "grpclog", + "internal", + "internal/backoff", + "internal/binarylog", + "internal/channelz", + "internal/envconfig", + "internal/grpcrand", + "internal/grpcsync", + "internal/syscall", + "internal/transport", + "keepalive", + "metadata", + "naming", + "peer", + "resolver", + "resolver/dns", + "resolver/passthrough", + "stats", + "status", + "tap", + ] + pruneopts = "NUT" + revision = "df014850f6dee74ba2fc94874043a9f3f75fbfd8" + version = "v1.17.0" + +[[projects]] + digest = "1:2d1fbdc6777e5408cabeb02bf336305e724b925ff4546ded0fa8715a7267922a" + name = "gopkg.in/inf.v0" + packages = ["."] + pruneopts = "NUT" + revision = "d2d2541c53f18d2a059457998ce2876cc8e67cbf" + version = "v0.9.1" + +[[projects]] + digest = "1:18108594151654e9e696b27b181b953f9a90b16bf14d253dd1b397b025a1487f" + name = "gopkg.in/yaml.v2" + packages = ["."] + pruneopts = "NUT" + revision = "51d6538a90f86fe93ac480b35f37b2be17fef232" + version = "v2.2.2" + +[[projects]] + digest = "1:1d34342a53d8f8c625260d6c4c2e5c99442b1635bbf4208f426bd12aa210b870" + name = "k8s.io/api" + packages = [ + "admission/v1beta1", + "admissionregistration/v1alpha1", + "admissionregistration/v1beta1", + "apps/v1", + "apps/v1beta1", + "apps/v1beta2", + "authentication/v1", + "authentication/v1beta1", + "authorization/v1", + "authorization/v1beta1", + "autoscaling/v1", + "autoscaling/v2beta1", + "autoscaling/v2beta2", + "batch/v1", + "batch/v1beta1", + "batch/v2alpha1", + "certificates/v1beta1", + "coordination/v1beta1", + "core/v1", + "events/v1beta1", + "extensions/v1beta1", + "networking/v1", + "policy/v1beta1", + "rbac/v1", + "rbac/v1alpha1", + "rbac/v1beta1", + "scheduling/v1alpha1", + "scheduling/v1beta1", + "settings/v1alpha1", + "storage/v1", + "storage/v1alpha1", + "storage/v1beta1", + ] + pruneopts = "NUT" + revision = "145d52631d00cbfe68490d19ae4f0f501fd31a95" + version = "kubernetes-1.12.6" + +[[projects]] + digest = "1:119ae04ee44c5d179dcde1ee686f057cfe3fc54a7ee8484b920932a80309e88b" + name = "k8s.io/apimachinery" + packages = [ + "pkg/api/equality", + "pkg/api/errors", + "pkg/api/meta", + "pkg/api/resource", + "pkg/api/validation", + "pkg/apis/meta/internalversion", + "pkg/apis/meta/v1", + "pkg/apis/meta/v1/unstructured", + "pkg/apis/meta/v1/validation", + "pkg/apis/meta/v1beta1", + "pkg/conversion", + "pkg/conversion/queryparams", + "pkg/fields", + "pkg/labels", + "pkg/runtime", + "pkg/runtime/schema", + "pkg/runtime/serializer", + "pkg/runtime/serializer/json", + "pkg/runtime/serializer/protobuf", + "pkg/runtime/serializer/recognizer", + "pkg/runtime/serializer/streaming", + "pkg/runtime/serializer/versioning", + "pkg/selection", + "pkg/types", + "pkg/util/cache", + "pkg/util/clock", + "pkg/util/diff", + "pkg/util/errors", + "pkg/util/framer", + "pkg/util/intstr", + "pkg/util/json", + "pkg/util/mergepatch", + "pkg/util/naming", + "pkg/util/net", + "pkg/util/runtime", + "pkg/util/sets", + "pkg/util/sets/types", + "pkg/util/strategicpatch", + "pkg/util/validation", + "pkg/util/validation/field", + "pkg/util/wait", + "pkg/util/yaml", + "pkg/version", + "pkg/watch", + "third_party/forked/golang/json", + "third_party/forked/golang/reflect", + ] + pruneopts = "NUT" + revision = "01f179d85dbce0f2e0e4351a92394b38694b7cae" + version = "kubernetes-1.12.6" + +[[projects]] + digest = "1:07be043078c2dc2ee33e81278b264a84f364c6d711811d2932aa42212fc4f2ae" + name = "k8s.io/client-go" + packages = [ + "discovery", + "discovery/fake", + "dynamic", + "dynamic/fake", + "informers", + "informers/admissionregistration", + "informers/admissionregistration/v1alpha1", + "informers/admissionregistration/v1beta1", + "informers/apps", + "informers/apps/v1", + "informers/apps/v1beta1", + "informers/apps/v1beta2", + "informers/autoscaling", + "informers/autoscaling/v1", + "informers/autoscaling/v2beta1", + "informers/autoscaling/v2beta2", + "informers/batch", + "informers/batch/v1", + "informers/batch/v1beta1", + "informers/batch/v2alpha1", + "informers/certificates", + "informers/certificates/v1beta1", + "informers/coordination", + "informers/coordination/v1beta1", + "informers/core", + "informers/core/v1", + "informers/events", + "informers/events/v1beta1", + "informers/extensions", + "informers/extensions/v1beta1", + "informers/internalinterfaces", + "informers/networking", + "informers/networking/v1", + "informers/policy", + "informers/policy/v1beta1", + "informers/rbac", + "informers/rbac/v1", + "informers/rbac/v1alpha1", + "informers/rbac/v1beta1", + "informers/scheduling", + "informers/scheduling/v1alpha1", + "informers/scheduling/v1beta1", + "informers/settings", + "informers/settings/v1alpha1", + "informers/storage", + "informers/storage/v1", + "informers/storage/v1alpha1", + "informers/storage/v1beta1", + "kubernetes", + "kubernetes/fake", + "kubernetes/scheme", + "kubernetes/typed/admissionregistration/v1alpha1", + "kubernetes/typed/admissionregistration/v1alpha1/fake", + "kubernetes/typed/admissionregistration/v1beta1", + "kubernetes/typed/admissionregistration/v1beta1/fake", + "kubernetes/typed/apps/v1", + "kubernetes/typed/apps/v1/fake", + "kubernetes/typed/apps/v1beta1", + "kubernetes/typed/apps/v1beta1/fake", + "kubernetes/typed/apps/v1beta2", + "kubernetes/typed/apps/v1beta2/fake", + "kubernetes/typed/authentication/v1", + "kubernetes/typed/authentication/v1/fake", + "kubernetes/typed/authentication/v1beta1", + "kubernetes/typed/authentication/v1beta1/fake", + "kubernetes/typed/authorization/v1", + "kubernetes/typed/authorization/v1/fake", + "kubernetes/typed/authorization/v1beta1", + "kubernetes/typed/authorization/v1beta1/fake", + "kubernetes/typed/autoscaling/v1", + "kubernetes/typed/autoscaling/v1/fake", + "kubernetes/typed/autoscaling/v2beta1", + "kubernetes/typed/autoscaling/v2beta1/fake", + "kubernetes/typed/autoscaling/v2beta2", + "kubernetes/typed/autoscaling/v2beta2/fake", + "kubernetes/typed/batch/v1", + "kubernetes/typed/batch/v1/fake", + "kubernetes/typed/batch/v1beta1", + "kubernetes/typed/batch/v1beta1/fake", + "kubernetes/typed/batch/v2alpha1", + "kubernetes/typed/batch/v2alpha1/fake", + "kubernetes/typed/certificates/v1beta1", + "kubernetes/typed/certificates/v1beta1/fake", + "kubernetes/typed/coordination/v1beta1", + "kubernetes/typed/coordination/v1beta1/fake", + "kubernetes/typed/core/v1", + "kubernetes/typed/core/v1/fake", + "kubernetes/typed/events/v1beta1", + "kubernetes/typed/events/v1beta1/fake", + "kubernetes/typed/extensions/v1beta1", + "kubernetes/typed/extensions/v1beta1/fake", + "kubernetes/typed/networking/v1", + "kubernetes/typed/networking/v1/fake", + "kubernetes/typed/policy/v1beta1", + "kubernetes/typed/policy/v1beta1/fake", + "kubernetes/typed/rbac/v1", + "kubernetes/typed/rbac/v1/fake", + "kubernetes/typed/rbac/v1alpha1", + "kubernetes/typed/rbac/v1alpha1/fake", + "kubernetes/typed/rbac/v1beta1", + "kubernetes/typed/rbac/v1beta1/fake", + "kubernetes/typed/scheduling/v1alpha1", + "kubernetes/typed/scheduling/v1alpha1/fake", + "kubernetes/typed/scheduling/v1beta1", + "kubernetes/typed/scheduling/v1beta1/fake", + "kubernetes/typed/settings/v1alpha1", + "kubernetes/typed/settings/v1alpha1/fake", + "kubernetes/typed/storage/v1", + "kubernetes/typed/storage/v1/fake", + "kubernetes/typed/storage/v1alpha1", + "kubernetes/typed/storage/v1alpha1/fake", + "kubernetes/typed/storage/v1beta1", + "kubernetes/typed/storage/v1beta1/fake", + "listers/admissionregistration/v1alpha1", + "listers/admissionregistration/v1beta1", + "listers/apps/v1", + "listers/apps/v1beta1", + "listers/apps/v1beta2", + "listers/autoscaling/v1", + "listers/autoscaling/v2beta1", + "listers/autoscaling/v2beta2", + "listers/batch/v1", + "listers/batch/v1beta1", + "listers/batch/v2alpha1", + "listers/certificates/v1beta1", + "listers/coordination/v1beta1", + "listers/core/v1", + "listers/events/v1beta1", + "listers/extensions/v1beta1", + "listers/networking/v1", + "listers/policy/v1beta1", + "listers/rbac/v1", + "listers/rbac/v1alpha1", + "listers/rbac/v1beta1", + "listers/scheduling/v1alpha1", + "listers/scheduling/v1beta1", + "listers/settings/v1alpha1", + "listers/storage/v1", + "listers/storage/v1alpha1", + "listers/storage/v1beta1", + "pkg/apis/clientauthentication", + "pkg/apis/clientauthentication/v1alpha1", + "pkg/apis/clientauthentication/v1beta1", + "pkg/version", + "plugin/pkg/client/auth/exec", + "plugin/pkg/client/auth/gcp", + "rest", + "rest/watch", + "testing", + "third_party/forked/golang/template", + "tools/auth", + "tools/cache", + "tools/clientcmd", + "tools/clientcmd/api", + "tools/clientcmd/api/latest", + "tools/clientcmd/api/v1", + "tools/metrics", + "tools/pager", + "tools/record", + "tools/reference", + "transport", + "util/buffer", + "util/cert", + "util/connrotation", + "util/flowcontrol", + "util/homedir", + "util/integer", + "util/jsonpath", + "util/retry", + "util/workqueue", + ] + pruneopts = "NUT" + revision = "78295b709ec6fa5be12e35892477a326dea2b5d3" + version = "kubernetes-1.12.6" + +[[projects]] + digest = "1:26b81b5e76e3f84ea5140da4f74649576e470f79091d2ef8e0d1b5000bc636ca" + name = "k8s.io/code-generator" + packages = [ + "cmd/client-gen", + "cmd/client-gen/args", + "cmd/client-gen/generators", + "cmd/client-gen/generators/fake", + "cmd/client-gen/generators/scheme", + "cmd/client-gen/generators/util", + "cmd/client-gen/path", + "cmd/client-gen/types", + "cmd/deepcopy-gen", + "cmd/deepcopy-gen/args", + "cmd/defaulter-gen", + "cmd/defaulter-gen/args", + "cmd/informer-gen", + "cmd/informer-gen/args", + "cmd/informer-gen/generators", + "cmd/lister-gen", + "cmd/lister-gen/args", + "cmd/lister-gen/generators", + "pkg/util", + ] + pruneopts = "T" + revision = "b1289fc74931d4b6b04bd1a259acfc88a2cb0a66" + version = "kubernetes-1.12.6" + +[[projects]] + branch = "master" + digest = "1:39912eb5f8eaf46486faae0839586c27c93423e552f76875defa048f52c15c15" + name = "k8s.io/gengo" + packages = [ + "args", + "examples/deepcopy-gen/generators", + "examples/defaulter-gen/generators", + "examples/set-gen/sets", + "generator", + "namer", + "parser", + "types", + ] + pruneopts = "NUT" + revision = "e17681d19d3ac4837a019ece36c2a0ec31ffe985" + +[[projects]] + digest = "1:c263611800c3a97991dbcf9d3bc4de390f6224aaa8ca0a7226a9d734f65a416a" + name = "k8s.io/klog" + packages = ["."] + pruneopts = "NUT" + revision = "71442cd4037d612096940ceb0f3fec3f7fff66e0" + version = "v0.2.0" + +[[projects]] + branch = "master" + digest = "1:a2c842a1e0aed96fd732b535514556323a6f5edfded3b63e5e0ab1bce188aa54" + name = "k8s.io/kube-openapi" + packages = ["pkg/util/proto"] + pruneopts = "NUT" + revision = "e3762e86a74c878ffed47484592986685639c2cd" + +[solve-meta] + analyzer-name = "dep" + analyzer-version = 1 + input-imports = [ + "cloud.google.com/go/compute/metadata", + "contrib.go.opencensus.io/exporter/stackdriver", + "contrib.go.opencensus.io/exporter/stackdriver/monitoredresource", + "github.com/davecgh/go-spew/spew", + "github.com/evanphx/json-patch", + "github.com/ghodss/yaml", + "github.com/golang/glog", + "github.com/google/go-cmp/cmp", + "github.com/google/go-cmp/cmp/cmpopts", + "github.com/google/uuid", + "github.com/gorilla/websocket", + "github.com/knative/test-infra/scripts", + "github.com/knative/test-infra/tools/dep-collector", + "github.com/markbates/inflect", + "github.com/mattbaird/jsonpatch", + "github.com/openzipkin/zipkin-go", + "github.com/openzipkin/zipkin-go/model", + "github.com/openzipkin/zipkin-go/reporter", + "github.com/openzipkin/zipkin-go/reporter/http", + "github.com/openzipkin/zipkin-go/reporter/recorder", + "github.com/pkg/errors", + "github.com/rogpeppe/go-internal/semver", + "github.com/spf13/pflag", + "go.opencensus.io/exporter/prometheus", + "go.opencensus.io/exporter/zipkin", + "go.opencensus.io/plugin/ochttp", + "go.opencensus.io/plugin/ochttp/propagation/b3", + "go.opencensus.io/stats", + "go.opencensus.io/stats/view", + "go.opencensus.io/tag", + "go.opencensus.io/trace", + "go.uber.org/zap", + "go.uber.org/zap/zapcore", + "go.uber.org/zap/zaptest", + "golang.org/x/sync/errgroup", + "k8s.io/api/admission/v1beta1", + "k8s.io/api/admissionregistration/v1beta1", + "k8s.io/api/apps/v1", + "k8s.io/api/authentication/v1", + "k8s.io/api/batch/v1", + "k8s.io/api/core/v1", + "k8s.io/api/rbac/v1", + "k8s.io/apimachinery/pkg/api/equality", + "k8s.io/apimachinery/pkg/api/errors", + "k8s.io/apimachinery/pkg/api/meta", + "k8s.io/apimachinery/pkg/api/resource", + "k8s.io/apimachinery/pkg/api/validation", + "k8s.io/apimachinery/pkg/apis/meta/v1", + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured", + "k8s.io/apimachinery/pkg/labels", + "k8s.io/apimachinery/pkg/runtime", + "k8s.io/apimachinery/pkg/runtime/schema", + "k8s.io/apimachinery/pkg/runtime/serializer", + "k8s.io/apimachinery/pkg/selection", + "k8s.io/apimachinery/pkg/types", + "k8s.io/apimachinery/pkg/util/runtime", + "k8s.io/apimachinery/pkg/util/sets", + "k8s.io/apimachinery/pkg/util/sets/types", + "k8s.io/apimachinery/pkg/util/validation", + "k8s.io/apimachinery/pkg/util/wait", + "k8s.io/apimachinery/pkg/version", + "k8s.io/apimachinery/pkg/watch", + "k8s.io/client-go/discovery", + "k8s.io/client-go/discovery/fake", + "k8s.io/client-go/dynamic", + "k8s.io/client-go/dynamic/fake", + "k8s.io/client-go/informers", + "k8s.io/client-go/informers/apps/v1", + "k8s.io/client-go/informers/autoscaling/v1", + "k8s.io/client-go/informers/autoscaling/v2beta1", + "k8s.io/client-go/informers/core/v1", + "k8s.io/client-go/kubernetes", + "k8s.io/client-go/kubernetes/fake", + "k8s.io/client-go/kubernetes/typed/admissionregistration/v1beta1", + "k8s.io/client-go/kubernetes/typed/core/v1", + "k8s.io/client-go/plugin/pkg/client/auth/gcp", + "k8s.io/client-go/rest", + "k8s.io/client-go/testing", + "k8s.io/client-go/tools/cache", + "k8s.io/client-go/tools/clientcmd", + "k8s.io/client-go/tools/record", + "k8s.io/client-go/util/flowcontrol", + "k8s.io/client-go/util/workqueue", + "k8s.io/code-generator/cmd/client-gen", + "k8s.io/code-generator/cmd/client-gen/generators/util", + "k8s.io/code-generator/cmd/client-gen/types", + "k8s.io/code-generator/cmd/deepcopy-gen", + "k8s.io/code-generator/cmd/defaulter-gen", + "k8s.io/code-generator/cmd/informer-gen", + "k8s.io/code-generator/cmd/lister-gen", + "k8s.io/code-generator/pkg/util", + "k8s.io/gengo/args", + "k8s.io/gengo/generator", + "k8s.io/gengo/namer", + "k8s.io/gengo/types", + "k8s.io/klog", + ] + solver-name = "gps-cdcl" + solver-version = 1 diff --git a/vendor/github.com/knative/pkg/Gopkg.toml b/vendor/github.com/knative/pkg/Gopkg.toml new file mode 100644 index 0000000000..e7e231148c --- /dev/null +++ b/vendor/github.com/knative/pkg/Gopkg.toml @@ -0,0 +1,74 @@ +# Refer to https://golang.github.io/dep/docs/Gopkg.toml.html +# for detailed Gopkg.toml documentation. + +required = [ + "k8s.io/apimachinery/pkg/util/sets/types", + "k8s.io/code-generator/cmd/deepcopy-gen", + "k8s.io/code-generator/cmd/defaulter-gen", + "k8s.io/code-generator/cmd/client-gen", + "k8s.io/code-generator/cmd/lister-gen", + "k8s.io/code-generator/cmd/informer-gen", + "github.com/evanphx/json-patch", + "github.com/knative/test-infra/scripts", + "github.com/knative/test-infra/tools/dep-collector", + "github.com/pkg/errors", +] + +[[constraint]] + name = "k8s.io/api" + version = "kubernetes-1.12.6" + +[[constraint]] + name = "k8s.io/apimachinery" + version = "kubernetes-1.12.6" + +[[constraint]] + name = "k8s.io/client-go" + version = "kubernetes-1.12.6" + +[[constraint]] + name = "k8s.io/code-generator" + version = "kubernetes-1.12.6" + +[[override]] + name = "github.com/json-iterator/go" + # This is the commit at which k8s depends on this in 1.11 + # It seems to be broken at HEAD. + revision = "f2b4162afba35581b6d4a50d3b8f34e33c144682" + +[[override]] + name = "go.uber.org/zap" + revision = "67bc79d13d155c02fd008f721863ff8cc5f30659" + +[[constraint]] + name = "github.com/google/go-cmp" + # HEAD as of 2019-04-09 + revision = "6f77996f0c42f7b84e5a2b252227263f93432e9b" + +[[override]] + name = "github.com/rogpeppe/go-internal" + # HEAD as of 2019-01-09 + # Needed because release 1.0.0 does not contain a LICENSE file + revision = "4bbc89b6501cca7dd6b5557d78d70c8d2c6e8b97" + +[[constraint]] + name = "contrib.go.opencensus.io/exporter/stackdriver" + version = "0.9.2" + +[[constraint]] + name = "github.com/knative/test-infra" + branch = "master" + +[prune] + go-tests = true + unused-packages = true + non-go = true + +[[prune.project]] + name = "k8s.io/code-generator" + unused-packages = false + non-go = false + +[[prune.project]] + name = "github.com/knative/test-infra" + non-go = false diff --git a/vendor/github.com/knative/pkg/OWNERS b/vendor/github.com/knative/pkg/OWNERS new file mode 100644 index 0000000000..030df98f78 --- /dev/null +++ b/vendor/github.com/knative/pkg/OWNERS @@ -0,0 +1,4 @@ +# The OWNERS file is used by prow to automatically merge approved PRs. + +approvers: +- pkg-approvers diff --git a/vendor/github.com/knative/pkg/OWNERS_ALIASES b/vendor/github.com/knative/pkg/OWNERS_ALIASES new file mode 100644 index 0000000000..beee78a4f4 --- /dev/null +++ b/vendor/github.com/knative/pkg/OWNERS_ALIASES @@ -0,0 +1,65 @@ +aliases: + pkg-approvers: + - evankanderson + - mattmoor + - vaikas-google + + apis-approvers: + - mattmoor + - vaikas-google + - n3wscott + + apis-istio-approvers: + - tcnghia + + apis-duck-approvers: + - mattmoor + - vaikas-google + + cloudevents-approvers: + - n3wscott + - vaikas-google + + configmap-approvers: + - mattmoor + - mdemirhan + + controller-approvers: + - mattmoor + - grantr + - tcnghia + + kmeta-approvers: + - mattmoor + - jonjohnsonjr + + logging-approvers: + - mdemirhan + - n3wscott + - yanweiguo + + metrics-approvers: + - mdemirhan + - yanweiguo + + productivity-approvers: + - adrcunha + - chaodaiG + - srinivashegde86 + productivity-reviewers: + - adrcunha + - chaodaiG + - coryrc + - dushyanthsc + - ericKlawitter + - Fredy-Z + - nbarthwal + - srinivashegde86 + - steuhs + - yt3liu + + webhook-approvers: + - mattmoor + - grantr + - tcnghia + diff --git a/vendor/github.com/knative/pkg/README.md b/vendor/github.com/knative/pkg/README.md new file mode 100644 index 0000000000..b0098ca9c7 --- /dev/null +++ b/vendor/github.com/knative/pkg/README.md @@ -0,0 +1,13 @@ +# Knative Common Packages + +[![GoDoc](https://godoc.org/github.com/knative/pkg?status.svg)](https://godoc.org/github.com/knative/pkg) +[![Go Report Card](https://goreportcard.com/badge/knative/pkg)](https://goreportcard.com/report/knative/pkg) + +Knative `pkg` provides a place for sharing common Knative packages across the +Knative repos. + +To learn more about Knative, please visit our +[Knative docs](https://github.com/knative/docs) repository. + +If you are interested in contributing, see [CONTRIBUTING.md](./CONTRIBUTING.md) +and [DEVELOPMENT.md](./DEVELOPMENT.md). diff --git a/vendor/github.com/knative/pkg/apis/OWNERS b/vendor/github.com/knative/pkg/apis/OWNERS new file mode 100644 index 0000000000..a25420ebc0 --- /dev/null +++ b/vendor/github.com/knative/pkg/apis/OWNERS @@ -0,0 +1,4 @@ +# The OWNERS file is used by prow to automatically merge approved PRs. + +approvers: +- apis-approvers diff --git a/vendor/github.com/knative/pkg/apis/contexts.go b/vendor/github.com/knative/pkg/apis/contexts.go index 466b89809f..287761e16c 100644 --- a/vendor/github.com/knative/pkg/apis/contexts.go +++ b/vendor/github.com/knative/pkg/apis/contexts.go @@ -42,10 +42,26 @@ func IsInCreate(ctx context.Context) bool { // the receiver being validated is being updated. type inUpdateKey struct{} +type updatePayload struct { + base interface{} + subresource string +} + // WithinUpdate is used to note that the webhook is calling within // the context of a Update operation. func WithinUpdate(ctx context.Context, base interface{}) context.Context { - return context.WithValue(ctx, inUpdateKey{}, base) + return context.WithValue(ctx, inUpdateKey{}, &updatePayload{ + base: base, + }) +} + +// WithinSubResourceUpdate is used to note that the webhook is calling within +// the context of a Update operation on a subresource. +func WithinSubResourceUpdate(ctx context.Context, base interface{}, sr string) context.Context { + return context.WithValue(ctx, inUpdateKey{}, &updatePayload{ + base: base, + subresource: sr, + }) } // IsInUpdate checks whether the context is an Update. @@ -53,10 +69,24 @@ func IsInUpdate(ctx context.Context) bool { return ctx.Value(inUpdateKey{}) != nil } +// IsInStatusUpdate checks whether the context is an Update. +func IsInStatusUpdate(ctx context.Context) bool { + value := ctx.Value(inUpdateKey{}) + if value == nil { + return false + } + up := value.(*updatePayload) + return up.subresource == "status" +} + // GetBaseline returns the baseline of the update, or nil when we // are not within an update context. func GetBaseline(ctx context.Context) interface{} { - return ctx.Value(inUpdateKey{}) + value := ctx.Value(inUpdateKey{}) + if value == nil { + return nil + } + return value.(*updatePayload).base } // This is attached to contexts passed to webhook interfaces when diff --git a/vendor/github.com/knative/pkg/apis/duck/OWNERS b/vendor/github.com/knative/pkg/apis/duck/OWNERS new file mode 100644 index 0000000000..ad4d83c51e --- /dev/null +++ b/vendor/github.com/knative/pkg/apis/duck/OWNERS @@ -0,0 +1,4 @@ +# The OWNERS file is used by prow to automatically merge approved PRs. + +approvers: +- apis-duck-approvers diff --git a/vendor/github.com/knative/pkg/apis/istio/OWNERS b/vendor/github.com/knative/pkg/apis/istio/OWNERS new file mode 100644 index 0000000000..c09668f13f --- /dev/null +++ b/vendor/github.com/knative/pkg/apis/istio/OWNERS @@ -0,0 +1,4 @@ +# The OWNERS file is used by prow to automatically merge approved PRs. + +approvers: +- apis-istio-approvers diff --git a/vendor/github.com/knative/pkg/apis/istio/v1alpha3/README.md b/vendor/github.com/knative/pkg/apis/istio/v1alpha3/README.md new file mode 100644 index 0000000000..bc1fb65a5a --- /dev/null +++ b/vendor/github.com/knative/pkg/apis/istio/v1alpha3/README.md @@ -0,0 +1,17 @@ +# What are these files? + +These are Go structs for Istio CRD. We translated them from proto files in +https://github.com/istio/api/tree/master/networking/v1alpha3 . + +# Why do we hand-translate from proto? i.e Why can't we vendor these? + +Istio needs to run on many platforms and as a reason they represent their +objects internally as proto. On Kubernetes, their API take in JSON objects and +convert to proto before processing them. + +So they have nothing we can vendor, except for the Go files that are generated +by the proto compiler, which is not compatible with K8s API code-generator at +all. + +We may be able to donate our translation so they can maintain it themselves. See +https://github.com/istio/istio/issues/6084. diff --git a/vendor/github.com/knative/pkg/apis/testing/conditions.go b/vendor/github.com/knative/pkg/apis/testing/conditions.go new file mode 100644 index 0000000000..5aee8880c8 --- /dev/null +++ b/vendor/github.com/knative/pkg/apis/testing/conditions.go @@ -0,0 +1,61 @@ +/* +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 testing + +import ( + "fmt" + "testing" + + "github.com/knative/pkg/apis" + duckv1b1 "github.com/knative/pkg/apis/duck/v1beta1" + corev1 "k8s.io/api/core/v1" +) + +// CheckCondition checks if condition `c` on `cc` has value `cs`. +func CheckCondition(s *duckv1b1.Status, c apis.ConditionType, cs corev1.ConditionStatus) error { + cond := s.GetCondition(c) + if cond == nil { + return fmt.Errorf("condition %v is nil", c) + } + if cond.Status != cs { + return fmt.Errorf("condition(%v) = %v, wanted: %v", c, cond, cs) + } + return nil +} + +// CheckConditionOngoing checks if the condition is in state `Unknown`. +func CheckConditionOngoing(s *duckv1b1.Status, c apis.ConditionType, t *testing.T) { + t.Helper() + if err := CheckCondition(s, c, corev1.ConditionUnknown); err != nil { + t.Error(err) + } +} + +// CheckConditionFailed checks if the condition is in state `False`. +func CheckConditionFailed(s *duckv1b1.Status, c apis.ConditionType, t *testing.T) { + t.Helper() + if err := CheckCondition(s, c, corev1.ConditionFalse); err != nil { + t.Error(err) + } +} + +// CheckConditionSucceeded checks if the condition is in state `True`. +func CheckConditionSucceeded(s *duckv1b1.Status, c apis.ConditionType, t *testing.T) { + t.Helper() + if err := CheckCondition(s, c, corev1.ConditionTrue); err != nil { + t.Error(err) + } +} diff --git a/vendor/github.com/knative/pkg/changeset/testdata/HEAD b/vendor/github.com/knative/pkg/changeset/testdata/HEAD new file mode 100644 index 0000000000..58b38ebaed --- /dev/null +++ b/vendor/github.com/knative/pkg/changeset/testdata/HEAD @@ -0,0 +1 @@ +a2d1bdfe929516d7da141aef68631a7ee6941b2d diff --git a/vendor/github.com/knative/pkg/changeset/testdata/noncommitted/HEAD b/vendor/github.com/knative/pkg/changeset/testdata/noncommitted/HEAD new file mode 100644 index 0000000000..89fe2d3567 --- /dev/null +++ b/vendor/github.com/knative/pkg/changeset/testdata/noncommitted/HEAD @@ -0,0 +1 @@ +ref: refs/heads/non_committed_branch diff --git a/vendor/github.com/knative/pkg/client/informers/externalversions/authentication/interface.go b/vendor/github.com/knative/pkg/client/informers/externalversions/authentication/interface.go new file mode 100644 index 0000000000..2c0a8ce89a --- /dev/null +++ b/vendor/github.com/knative/pkg/client/informers/externalversions/authentication/interface.go @@ -0,0 +1,46 @@ +/* +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. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package authentication + +import ( + v1alpha1 "github.com/knative/pkg/client/informers/externalversions/authentication/v1alpha1" + internalinterfaces "github.com/knative/pkg/client/informers/externalversions/internalinterfaces" +) + +// Interface provides access to each of this group's versions. +type Interface interface { + // V1alpha1 provides access to shared informers for resources in V1alpha1. + V1alpha1() v1alpha1.Interface +} + +type group struct { + factory internalinterfaces.SharedInformerFactory + namespace string + tweakListOptions internalinterfaces.TweakListOptionsFunc +} + +// New returns a new Interface. +func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface { + return &group{factory: f, namespace: namespace, tweakListOptions: tweakListOptions} +} + +// V1alpha1 returns a new v1alpha1.Interface. +func (g *group) V1alpha1() v1alpha1.Interface { + return v1alpha1.New(g.factory, g.namespace, g.tweakListOptions) +} diff --git a/vendor/github.com/knative/pkg/client/informers/externalversions/authentication/v1alpha1/interface.go b/vendor/github.com/knative/pkg/client/informers/externalversions/authentication/v1alpha1/interface.go new file mode 100644 index 0000000000..a46940a968 --- /dev/null +++ b/vendor/github.com/knative/pkg/client/informers/externalversions/authentication/v1alpha1/interface.go @@ -0,0 +1,45 @@ +/* +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. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + internalinterfaces "github.com/knative/pkg/client/informers/externalversions/internalinterfaces" +) + +// Interface provides access to all the informers in this group version. +type Interface interface { + // Policies returns a PolicyInformer. + Policies() PolicyInformer +} + +type version struct { + factory internalinterfaces.SharedInformerFactory + namespace string + tweakListOptions internalinterfaces.TweakListOptionsFunc +} + +// New returns a new Interface. +func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface { + return &version{factory: f, namespace: namespace, tweakListOptions: tweakListOptions} +} + +// Policies returns a PolicyInformer. +func (v *version) Policies() PolicyInformer { + return &policyInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} +} diff --git a/vendor/github.com/knative/pkg/client/informers/externalversions/authentication/v1alpha1/policy.go b/vendor/github.com/knative/pkg/client/informers/externalversions/authentication/v1alpha1/policy.go new file mode 100644 index 0000000000..912860c948 --- /dev/null +++ b/vendor/github.com/knative/pkg/client/informers/externalversions/authentication/v1alpha1/policy.go @@ -0,0 +1,89 @@ +/* +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. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + time "time" + + authenticationv1alpha1 "github.com/knative/pkg/apis/istio/authentication/v1alpha1" + versioned "github.com/knative/pkg/client/clientset/versioned" + internalinterfaces "github.com/knative/pkg/client/informers/externalversions/internalinterfaces" + v1alpha1 "github.com/knative/pkg/client/listers/authentication/v1alpha1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + watch "k8s.io/apimachinery/pkg/watch" + cache "k8s.io/client-go/tools/cache" +) + +// PolicyInformer provides access to a shared informer and lister for +// Policies. +type PolicyInformer interface { + Informer() cache.SharedIndexInformer + Lister() v1alpha1.PolicyLister +} + +type policyInformer struct { + factory internalinterfaces.SharedInformerFactory + tweakListOptions internalinterfaces.TweakListOptionsFunc + namespace string +} + +// NewPolicyInformer constructs a new informer for Policy type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewPolicyInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { + return NewFilteredPolicyInformer(client, namespace, resyncPeriod, indexers, nil) +} + +// NewFilteredPolicyInformer constructs a new informer for Policy type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewFilteredPolicyInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer { + return cache.NewSharedIndexInformer( + &cache.ListWatch{ + ListFunc: func(options v1.ListOptions) (runtime.Object, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.AuthenticationV1alpha1().Policies(namespace).List(options) + }, + WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.AuthenticationV1alpha1().Policies(namespace).Watch(options) + }, + }, + &authenticationv1alpha1.Policy{}, + resyncPeriod, + indexers, + ) +} + +func (f *policyInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { + return NewFilteredPolicyInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) +} + +func (f *policyInformer) Informer() cache.SharedIndexInformer { + return f.factory.InformerFor(&authenticationv1alpha1.Policy{}, f.defaultInformer) +} + +func (f *policyInformer) Lister() v1alpha1.PolicyLister { + return v1alpha1.NewPolicyLister(f.Informer().GetIndexer()) +} diff --git a/vendor/github.com/knative/pkg/client/informers/externalversions/factory.go b/vendor/github.com/knative/pkg/client/informers/externalversions/factory.go new file mode 100644 index 0000000000..a8e88a5b7a --- /dev/null +++ b/vendor/github.com/knative/pkg/client/informers/externalversions/factory.go @@ -0,0 +1,186 @@ +/* +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. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package externalversions + +import ( + reflect "reflect" + sync "sync" + time "time" + + versioned "github.com/knative/pkg/client/clientset/versioned" + authentication "github.com/knative/pkg/client/informers/externalversions/authentication" + internalinterfaces "github.com/knative/pkg/client/informers/externalversions/internalinterfaces" + istio "github.com/knative/pkg/client/informers/externalversions/istio" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + schema "k8s.io/apimachinery/pkg/runtime/schema" + cache "k8s.io/client-go/tools/cache" +) + +// SharedInformerOption defines the functional option type for SharedInformerFactory. +type SharedInformerOption func(*sharedInformerFactory) *sharedInformerFactory + +type sharedInformerFactory struct { + client versioned.Interface + namespace string + tweakListOptions internalinterfaces.TweakListOptionsFunc + lock sync.Mutex + defaultResync time.Duration + customResync map[reflect.Type]time.Duration + + informers map[reflect.Type]cache.SharedIndexInformer + // startedInformers is used for tracking which informers have been started. + // This allows Start() to be called multiple times safely. + startedInformers map[reflect.Type]bool +} + +// WithCustomResyncConfig sets a custom resync period for the specified informer types. +func WithCustomResyncConfig(resyncConfig map[v1.Object]time.Duration) SharedInformerOption { + return func(factory *sharedInformerFactory) *sharedInformerFactory { + for k, v := range resyncConfig { + factory.customResync[reflect.TypeOf(k)] = v + } + return factory + } +} + +// WithTweakListOptions sets a custom filter on all listers of the configured SharedInformerFactory. +func WithTweakListOptions(tweakListOptions internalinterfaces.TweakListOptionsFunc) SharedInformerOption { + return func(factory *sharedInformerFactory) *sharedInformerFactory { + factory.tweakListOptions = tweakListOptions + return factory + } +} + +// WithNamespace limits the SharedInformerFactory to the specified namespace. +func WithNamespace(namespace string) SharedInformerOption { + return func(factory *sharedInformerFactory) *sharedInformerFactory { + factory.namespace = namespace + return factory + } +} + +// NewSharedInformerFactory constructs a new instance of sharedInformerFactory for all namespaces. +func NewSharedInformerFactory(client versioned.Interface, defaultResync time.Duration) SharedInformerFactory { + return NewSharedInformerFactoryWithOptions(client, defaultResync) +} + +// NewFilteredSharedInformerFactory constructs a new instance of sharedInformerFactory. +// Listers obtained via this SharedInformerFactory will be subject to the same filters +// as specified here. +// Deprecated: Please use NewSharedInformerFactoryWithOptions instead +func NewFilteredSharedInformerFactory(client versioned.Interface, defaultResync time.Duration, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) SharedInformerFactory { + return NewSharedInformerFactoryWithOptions(client, defaultResync, WithNamespace(namespace), WithTweakListOptions(tweakListOptions)) +} + +// NewSharedInformerFactoryWithOptions constructs a new instance of a SharedInformerFactory with additional options. +func NewSharedInformerFactoryWithOptions(client versioned.Interface, defaultResync time.Duration, options ...SharedInformerOption) SharedInformerFactory { + factory := &sharedInformerFactory{ + client: client, + namespace: v1.NamespaceAll, + defaultResync: defaultResync, + informers: make(map[reflect.Type]cache.SharedIndexInformer), + startedInformers: make(map[reflect.Type]bool), + customResync: make(map[reflect.Type]time.Duration), + } + + // Apply all options + for _, opt := range options { + factory = opt(factory) + } + + return factory +} + +// Start initializes all requested informers. +func (f *sharedInformerFactory) Start(stopCh <-chan struct{}) { + f.lock.Lock() + defer f.lock.Unlock() + + for informerType, informer := range f.informers { + if !f.startedInformers[informerType] { + go informer.Run(stopCh) + f.startedInformers[informerType] = true + } + } +} + +// WaitForCacheSync waits for all started informers' cache were synced. +func (f *sharedInformerFactory) WaitForCacheSync(stopCh <-chan struct{}) map[reflect.Type]bool { + informers := func() map[reflect.Type]cache.SharedIndexInformer { + f.lock.Lock() + defer f.lock.Unlock() + + informers := map[reflect.Type]cache.SharedIndexInformer{} + for informerType, informer := range f.informers { + if f.startedInformers[informerType] { + informers[informerType] = informer + } + } + return informers + }() + + res := map[reflect.Type]bool{} + for informType, informer := range informers { + res[informType] = cache.WaitForCacheSync(stopCh, informer.HasSynced) + } + return res +} + +// InternalInformerFor returns the SharedIndexInformer for obj using an internal +// client. +func (f *sharedInformerFactory) InformerFor(obj runtime.Object, newFunc internalinterfaces.NewInformerFunc) cache.SharedIndexInformer { + f.lock.Lock() + defer f.lock.Unlock() + + informerType := reflect.TypeOf(obj) + informer, exists := f.informers[informerType] + if exists { + return informer + } + + resyncPeriod, exists := f.customResync[informerType] + if !exists { + resyncPeriod = f.defaultResync + } + + informer = newFunc(f.client, resyncPeriod) + f.informers[informerType] = informer + + return informer +} + +// SharedInformerFactory provides shared informers for resources in all known +// API group versions. +type SharedInformerFactory interface { + internalinterfaces.SharedInformerFactory + ForResource(resource schema.GroupVersionResource) (GenericInformer, error) + WaitForCacheSync(stopCh <-chan struct{}) map[reflect.Type]bool + + Authentication() authentication.Interface + Networking() istio.Interface +} + +func (f *sharedInformerFactory) Authentication() authentication.Interface { + return authentication.New(f, f.namespace, f.tweakListOptions) +} + +func (f *sharedInformerFactory) Networking() istio.Interface { + return istio.New(f, f.namespace, f.tweakListOptions) +} diff --git a/vendor/github.com/knative/pkg/client/informers/externalversions/generic.go b/vendor/github.com/knative/pkg/client/informers/externalversions/generic.go new file mode 100644 index 0000000000..2a15246108 --- /dev/null +++ b/vendor/github.com/knative/pkg/client/informers/externalversions/generic.go @@ -0,0 +1,71 @@ +/* +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. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package externalversions + +import ( + "fmt" + + v1alpha1 "github.com/knative/pkg/apis/istio/authentication/v1alpha1" + v1alpha3 "github.com/knative/pkg/apis/istio/v1alpha3" + schema "k8s.io/apimachinery/pkg/runtime/schema" + cache "k8s.io/client-go/tools/cache" +) + +// GenericInformer is type of SharedIndexInformer which will locate and delegate to other +// sharedInformers based on type +type GenericInformer interface { + Informer() cache.SharedIndexInformer + Lister() cache.GenericLister +} + +type genericInformer struct { + informer cache.SharedIndexInformer + resource schema.GroupResource +} + +// Informer returns the SharedIndexInformer. +func (f *genericInformer) Informer() cache.SharedIndexInformer { + return f.informer +} + +// Lister returns the GenericLister. +func (f *genericInformer) Lister() cache.GenericLister { + return cache.NewGenericLister(f.Informer().GetIndexer(), f.resource) +} + +// ForResource gives generic access to a shared informer of the matching type +// TODO extend this to unknown resources with a client pool +func (f *sharedInformerFactory) ForResource(resource schema.GroupVersionResource) (GenericInformer, error) { + switch resource { + // Group=authentication.istio.io, Version=v1alpha1 + case v1alpha1.SchemeGroupVersion.WithResource("policies"): + return &genericInformer{resource: resource.GroupResource(), informer: f.Authentication().V1alpha1().Policies().Informer()}, nil + + // Group=networking.istio.io, Version=v1alpha3 + case v1alpha3.SchemeGroupVersion.WithResource("destinationrules"): + return &genericInformer{resource: resource.GroupResource(), informer: f.Networking().V1alpha3().DestinationRules().Informer()}, nil + case v1alpha3.SchemeGroupVersion.WithResource("gateways"): + return &genericInformer{resource: resource.GroupResource(), informer: f.Networking().V1alpha3().Gateways().Informer()}, nil + case v1alpha3.SchemeGroupVersion.WithResource("virtualservices"): + return &genericInformer{resource: resource.GroupResource(), informer: f.Networking().V1alpha3().VirtualServices().Informer()}, nil + + } + + return nil, fmt.Errorf("no informer found for %v", resource) +} diff --git a/vendor/github.com/knative/pkg/client/informers/externalversions/internalinterfaces/factory_interfaces.go b/vendor/github.com/knative/pkg/client/informers/externalversions/internalinterfaces/factory_interfaces.go new file mode 100644 index 0000000000..3cd3cb329c --- /dev/null +++ b/vendor/github.com/knative/pkg/client/informers/externalversions/internalinterfaces/factory_interfaces.go @@ -0,0 +1,38 @@ +/* +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. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package internalinterfaces + +import ( + time "time" + + versioned "github.com/knative/pkg/client/clientset/versioned" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + cache "k8s.io/client-go/tools/cache" +) + +type NewInformerFunc func(versioned.Interface, time.Duration) cache.SharedIndexInformer + +// SharedInformerFactory a small interface to allow for adding an informer without an import cycle +type SharedInformerFactory interface { + Start(stopCh <-chan struct{}) + InformerFor(obj runtime.Object, newFunc NewInformerFunc) cache.SharedIndexInformer +} + +type TweakListOptionsFunc func(*v1.ListOptions) diff --git a/vendor/github.com/knative/pkg/client/informers/externalversions/istio/interface.go b/vendor/github.com/knative/pkg/client/informers/externalversions/istio/interface.go new file mode 100644 index 0000000000..d7db9d27a9 --- /dev/null +++ b/vendor/github.com/knative/pkg/client/informers/externalversions/istio/interface.go @@ -0,0 +1,46 @@ +/* +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. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package networking + +import ( + internalinterfaces "github.com/knative/pkg/client/informers/externalversions/internalinterfaces" + v1alpha3 "github.com/knative/pkg/client/informers/externalversions/istio/v1alpha3" +) + +// Interface provides access to each of this group's versions. +type Interface interface { + // V1alpha3 provides access to shared informers for resources in V1alpha3. + V1alpha3() v1alpha3.Interface +} + +type group struct { + factory internalinterfaces.SharedInformerFactory + namespace string + tweakListOptions internalinterfaces.TweakListOptionsFunc +} + +// New returns a new Interface. +func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface { + return &group{factory: f, namespace: namespace, tweakListOptions: tweakListOptions} +} + +// V1alpha3 returns a new v1alpha3.Interface. +func (g *group) V1alpha3() v1alpha3.Interface { + return v1alpha3.New(g.factory, g.namespace, g.tweakListOptions) +} diff --git a/vendor/github.com/knative/pkg/client/informers/externalversions/istio/v1alpha3/destinationrule.go b/vendor/github.com/knative/pkg/client/informers/externalversions/istio/v1alpha3/destinationrule.go new file mode 100644 index 0000000000..d4a035b6e4 --- /dev/null +++ b/vendor/github.com/knative/pkg/client/informers/externalversions/istio/v1alpha3/destinationrule.go @@ -0,0 +1,89 @@ +/* +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. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package v1alpha3 + +import ( + time "time" + + istiov1alpha3 "github.com/knative/pkg/apis/istio/v1alpha3" + versioned "github.com/knative/pkg/client/clientset/versioned" + internalinterfaces "github.com/knative/pkg/client/informers/externalversions/internalinterfaces" + v1alpha3 "github.com/knative/pkg/client/listers/istio/v1alpha3" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + watch "k8s.io/apimachinery/pkg/watch" + cache "k8s.io/client-go/tools/cache" +) + +// DestinationRuleInformer provides access to a shared informer and lister for +// DestinationRules. +type DestinationRuleInformer interface { + Informer() cache.SharedIndexInformer + Lister() v1alpha3.DestinationRuleLister +} + +type destinationRuleInformer struct { + factory internalinterfaces.SharedInformerFactory + tweakListOptions internalinterfaces.TweakListOptionsFunc + namespace string +} + +// NewDestinationRuleInformer constructs a new informer for DestinationRule type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewDestinationRuleInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { + return NewFilteredDestinationRuleInformer(client, namespace, resyncPeriod, indexers, nil) +} + +// NewFilteredDestinationRuleInformer constructs a new informer for DestinationRule type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewFilteredDestinationRuleInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer { + return cache.NewSharedIndexInformer( + &cache.ListWatch{ + ListFunc: func(options v1.ListOptions) (runtime.Object, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.NetworkingV1alpha3().DestinationRules(namespace).List(options) + }, + WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.NetworkingV1alpha3().DestinationRules(namespace).Watch(options) + }, + }, + &istiov1alpha3.DestinationRule{}, + resyncPeriod, + indexers, + ) +} + +func (f *destinationRuleInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { + return NewFilteredDestinationRuleInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) +} + +func (f *destinationRuleInformer) Informer() cache.SharedIndexInformer { + return f.factory.InformerFor(&istiov1alpha3.DestinationRule{}, f.defaultInformer) +} + +func (f *destinationRuleInformer) Lister() v1alpha3.DestinationRuleLister { + return v1alpha3.NewDestinationRuleLister(f.Informer().GetIndexer()) +} diff --git a/vendor/github.com/knative/pkg/client/informers/externalversions/istio/v1alpha3/gateway.go b/vendor/github.com/knative/pkg/client/informers/externalversions/istio/v1alpha3/gateway.go new file mode 100644 index 0000000000..844704d993 --- /dev/null +++ b/vendor/github.com/knative/pkg/client/informers/externalversions/istio/v1alpha3/gateway.go @@ -0,0 +1,89 @@ +/* +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. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package v1alpha3 + +import ( + time "time" + + istiov1alpha3 "github.com/knative/pkg/apis/istio/v1alpha3" + versioned "github.com/knative/pkg/client/clientset/versioned" + internalinterfaces "github.com/knative/pkg/client/informers/externalversions/internalinterfaces" + v1alpha3 "github.com/knative/pkg/client/listers/istio/v1alpha3" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + watch "k8s.io/apimachinery/pkg/watch" + cache "k8s.io/client-go/tools/cache" +) + +// GatewayInformer provides access to a shared informer and lister for +// Gateways. +type GatewayInformer interface { + Informer() cache.SharedIndexInformer + Lister() v1alpha3.GatewayLister +} + +type gatewayInformer struct { + factory internalinterfaces.SharedInformerFactory + tweakListOptions internalinterfaces.TweakListOptionsFunc + namespace string +} + +// NewGatewayInformer constructs a new informer for Gateway type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewGatewayInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { + return NewFilteredGatewayInformer(client, namespace, resyncPeriod, indexers, nil) +} + +// NewFilteredGatewayInformer constructs a new informer for Gateway type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewFilteredGatewayInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer { + return cache.NewSharedIndexInformer( + &cache.ListWatch{ + ListFunc: func(options v1.ListOptions) (runtime.Object, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.NetworkingV1alpha3().Gateways(namespace).List(options) + }, + WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.NetworkingV1alpha3().Gateways(namespace).Watch(options) + }, + }, + &istiov1alpha3.Gateway{}, + resyncPeriod, + indexers, + ) +} + +func (f *gatewayInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { + return NewFilteredGatewayInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) +} + +func (f *gatewayInformer) Informer() cache.SharedIndexInformer { + return f.factory.InformerFor(&istiov1alpha3.Gateway{}, f.defaultInformer) +} + +func (f *gatewayInformer) Lister() v1alpha3.GatewayLister { + return v1alpha3.NewGatewayLister(f.Informer().GetIndexer()) +} diff --git a/vendor/github.com/knative/pkg/client/informers/externalversions/istio/v1alpha3/interface.go b/vendor/github.com/knative/pkg/client/informers/externalversions/istio/v1alpha3/interface.go new file mode 100644 index 0000000000..bd4808d711 --- /dev/null +++ b/vendor/github.com/knative/pkg/client/informers/externalversions/istio/v1alpha3/interface.go @@ -0,0 +1,59 @@ +/* +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. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package v1alpha3 + +import ( + internalinterfaces "github.com/knative/pkg/client/informers/externalversions/internalinterfaces" +) + +// Interface provides access to all the informers in this group version. +type Interface interface { + // DestinationRules returns a DestinationRuleInformer. + DestinationRules() DestinationRuleInformer + // Gateways returns a GatewayInformer. + Gateways() GatewayInformer + // VirtualServices returns a VirtualServiceInformer. + VirtualServices() VirtualServiceInformer +} + +type version struct { + factory internalinterfaces.SharedInformerFactory + namespace string + tweakListOptions internalinterfaces.TweakListOptionsFunc +} + +// New returns a new Interface. +func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface { + return &version{factory: f, namespace: namespace, tweakListOptions: tweakListOptions} +} + +// DestinationRules returns a DestinationRuleInformer. +func (v *version) DestinationRules() DestinationRuleInformer { + return &destinationRuleInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} +} + +// Gateways returns a GatewayInformer. +func (v *version) Gateways() GatewayInformer { + return &gatewayInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} +} + +// VirtualServices returns a VirtualServiceInformer. +func (v *version) VirtualServices() VirtualServiceInformer { + return &virtualServiceInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} +} diff --git a/vendor/github.com/knative/pkg/client/informers/externalversions/istio/v1alpha3/virtualservice.go b/vendor/github.com/knative/pkg/client/informers/externalversions/istio/v1alpha3/virtualservice.go new file mode 100644 index 0000000000..cecb442eef --- /dev/null +++ b/vendor/github.com/knative/pkg/client/informers/externalversions/istio/v1alpha3/virtualservice.go @@ -0,0 +1,89 @@ +/* +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. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package v1alpha3 + +import ( + time "time" + + istiov1alpha3 "github.com/knative/pkg/apis/istio/v1alpha3" + versioned "github.com/knative/pkg/client/clientset/versioned" + internalinterfaces "github.com/knative/pkg/client/informers/externalversions/internalinterfaces" + v1alpha3 "github.com/knative/pkg/client/listers/istio/v1alpha3" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + watch "k8s.io/apimachinery/pkg/watch" + cache "k8s.io/client-go/tools/cache" +) + +// VirtualServiceInformer provides access to a shared informer and lister for +// VirtualServices. +type VirtualServiceInformer interface { + Informer() cache.SharedIndexInformer + Lister() v1alpha3.VirtualServiceLister +} + +type virtualServiceInformer struct { + factory internalinterfaces.SharedInformerFactory + tweakListOptions internalinterfaces.TweakListOptionsFunc + namespace string +} + +// NewVirtualServiceInformer constructs a new informer for VirtualService type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewVirtualServiceInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { + return NewFilteredVirtualServiceInformer(client, namespace, resyncPeriod, indexers, nil) +} + +// NewFilteredVirtualServiceInformer constructs a new informer for VirtualService type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewFilteredVirtualServiceInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer { + return cache.NewSharedIndexInformer( + &cache.ListWatch{ + ListFunc: func(options v1.ListOptions) (runtime.Object, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.NetworkingV1alpha3().VirtualServices(namespace).List(options) + }, + WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.NetworkingV1alpha3().VirtualServices(namespace).Watch(options) + }, + }, + &istiov1alpha3.VirtualService{}, + resyncPeriod, + indexers, + ) +} + +func (f *virtualServiceInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { + return NewFilteredVirtualServiceInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) +} + +func (f *virtualServiceInformer) Informer() cache.SharedIndexInformer { + return f.factory.InformerFor(&istiov1alpha3.VirtualService{}, f.defaultInformer) +} + +func (f *virtualServiceInformer) Lister() v1alpha3.VirtualServiceLister { + return v1alpha3.NewVirtualServiceLister(f.Informer().GetIndexer()) +} diff --git a/vendor/github.com/knative/pkg/client/injection/client/client.go b/vendor/github.com/knative/pkg/client/injection/client/client.go new file mode 100644 index 0000000000..0eb124722a --- /dev/null +++ b/vendor/github.com/knative/pkg/client/injection/client/client.go @@ -0,0 +1,49 @@ +/* +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. +*/ + +// Code generated by injection-gen. DO NOT EDIT. + +package client + +import ( + "context" + + versioned "github.com/knative/pkg/client/clientset/versioned" + injection "github.com/knative/pkg/injection" + logging "github.com/knative/pkg/logging" + rest "k8s.io/client-go/rest" +) + +func init() { + injection.Default.RegisterClient(withClient) +} + +// Key is used as the key for associating information with a context.Context. +type Key struct{} + +func withClient(ctx context.Context, cfg *rest.Config) context.Context { + return context.WithValue(ctx, Key{}, versioned.NewForConfigOrDie(cfg)) +} + +// Get extracts the versioned.Interface client from the context. +func Get(ctx context.Context) versioned.Interface { + untyped := ctx.Value(Key{}) + if untyped == nil { + logging.FromContext(ctx).Fatalf( + "Unable to fetch %T from context.", (versioned.Interface)(nil)) + } + return untyped.(versioned.Interface) +} diff --git a/vendor/github.com/knative/pkg/client/injection/client/fake/fake.go b/vendor/github.com/knative/pkg/client/injection/client/fake/fake.go new file mode 100644 index 0000000000..ae36889095 --- /dev/null +++ b/vendor/github.com/knative/pkg/client/injection/client/fake/fake.go @@ -0,0 +1,54 @@ +/* +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. +*/ + +// Code generated by injection-gen. DO NOT EDIT. + +package fake + +import ( + "context" + + fake "github.com/knative/pkg/client/clientset/versioned/fake" + client "github.com/knative/pkg/client/injection/client" + injection "github.com/knative/pkg/injection" + logging "github.com/knative/pkg/logging" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/client-go/rest" +) + +func init() { + injection.Fake.RegisterClient(withClient) +} + +func withClient(ctx context.Context, cfg *rest.Config) context.Context { + ctx, _ = With(ctx) + return ctx +} + +func With(ctx context.Context, objects ...runtime.Object) (context.Context, *fake.Clientset) { + cs := fake.NewSimpleClientset(objects...) + return context.WithValue(ctx, client.Key{}, cs), cs +} + +// Get extracts the Kubernetes client from the context. +func Get(ctx context.Context) *fake.Clientset { + untyped := ctx.Value(client.Key{}) + if untyped == nil { + logging.FromContext(ctx).Fatalf( + "Unable to fetch %T from context.", (*fake.Clientset)(nil)) + } + return untyped.(*fake.Clientset) +} diff --git a/vendor/github.com/knative/pkg/client/injection/informers/authentication/factory/authenticationfactory.go b/vendor/github.com/knative/pkg/client/injection/informers/authentication/factory/authenticationfactory.go new file mode 100644 index 0000000000..2be38ccaaa --- /dev/null +++ b/vendor/github.com/knative/pkg/client/injection/informers/authentication/factory/authenticationfactory.go @@ -0,0 +1,52 @@ +/* +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. +*/ + +// Code generated by injection-gen. DO NOT EDIT. + +package authenticationfactory + +import ( + "context" + + externalversions "github.com/knative/pkg/client/informers/externalversions" + client "github.com/knative/pkg/client/injection/client" + controller "github.com/knative/pkg/controller" + injection "github.com/knative/pkg/injection" + logging "github.com/knative/pkg/logging" +) + +func init() { + injection.Default.RegisterInformerFactory(withInformerFactory) +} + +// Key is used as the key for associating information with a context.Context. +type Key struct{} + +func withInformerFactory(ctx context.Context) context.Context { + c := client.Get(ctx) + return context.WithValue(ctx, Key{}, + externalversions.NewSharedInformerFactory(c, controller.GetResyncPeriod(ctx))) +} + +// Get extracts the InformerFactory from the context. +func Get(ctx context.Context) externalversions.SharedInformerFactory { + untyped := ctx.Value(Key{}) + if untyped == nil { + logging.FromContext(ctx).Fatalf( + "Unable to fetch %T from context.", (externalversions.SharedInformerFactory)(nil)) + } + return untyped.(externalversions.SharedInformerFactory) +} diff --git a/vendor/github.com/knative/pkg/client/injection/informers/authentication/factory/fake/fake.go b/vendor/github.com/knative/pkg/client/injection/informers/authentication/factory/fake/fake.go new file mode 100644 index 0000000000..813706b958 --- /dev/null +++ b/vendor/github.com/knative/pkg/client/injection/informers/authentication/factory/fake/fake.go @@ -0,0 +1,41 @@ +/* +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. +*/ + +// Code generated by injection-gen. DO NOT EDIT. + +package fake + +import ( + "context" + + externalversions "github.com/knative/pkg/client/informers/externalversions" + fake "github.com/knative/pkg/client/injection/client/fake" + factory "github.com/knative/pkg/client/injection/informers/authentication/factory" + controller "github.com/knative/pkg/controller" + injection "github.com/knative/pkg/injection" +) + +var Get = factory.Get + +func init() { + injection.Fake.RegisterInformerFactory(withInformerFactory) +} + +func withInformerFactory(ctx context.Context) context.Context { + c := fake.Get(ctx) + return context.WithValue(ctx, factory.Key{}, + externalversions.NewSharedInformerFactory(c, controller.GetResyncPeriod(ctx))) +} diff --git a/vendor/github.com/knative/pkg/client/injection/informers/authentication/v1alpha1/policy/fake/fake.go b/vendor/github.com/knative/pkg/client/injection/informers/authentication/v1alpha1/policy/fake/fake.go new file mode 100644 index 0000000000..bd8c1e9742 --- /dev/null +++ b/vendor/github.com/knative/pkg/client/injection/informers/authentication/v1alpha1/policy/fake/fake.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. +*/ + +// Code generated by injection-gen. DO NOT EDIT. + +package fake + +import ( + "context" + + fake "github.com/knative/pkg/client/injection/informers/authentication/factory/fake" + policy "github.com/knative/pkg/client/injection/informers/authentication/v1alpha1/policy" + controller "github.com/knative/pkg/controller" + injection "github.com/knative/pkg/injection" +) + +var Get = policy.Get + +func init() { + injection.Fake.RegisterInformer(withInformer) +} + +func withInformer(ctx context.Context) (context.Context, controller.Informer) { + f := fake.Get(ctx) + inf := f.Authentication().V1alpha1().Policies() + return context.WithValue(ctx, policy.Key{}, inf), inf.Informer() +} diff --git a/vendor/github.com/knative/pkg/client/injection/informers/authentication/v1alpha1/policy/policy.go b/vendor/github.com/knative/pkg/client/injection/informers/authentication/v1alpha1/policy/policy.go new file mode 100644 index 0000000000..449afb5442 --- /dev/null +++ b/vendor/github.com/knative/pkg/client/injection/informers/authentication/v1alpha1/policy/policy.go @@ -0,0 +1,52 @@ +/* +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. +*/ + +// Code generated by injection-gen. DO NOT EDIT. + +package policy + +import ( + "context" + + v1alpha1 "github.com/knative/pkg/client/informers/externalversions/authentication/v1alpha1" + factory "github.com/knative/pkg/client/injection/informers/authentication/factory" + controller "github.com/knative/pkg/controller" + injection "github.com/knative/pkg/injection" + logging "github.com/knative/pkg/logging" +) + +func init() { + injection.Default.RegisterInformer(withInformer) +} + +// Key is used for associating the Informer inside the context.Context. +type Key struct{} + +func withInformer(ctx context.Context) (context.Context, controller.Informer) { + f := factory.Get(ctx) + inf := f.Authentication().V1alpha1().Policies() + return context.WithValue(ctx, Key{}, inf), inf.Informer() +} + +// Get extracts the typed informer from the context. +func Get(ctx context.Context) v1alpha1.PolicyInformer { + untyped := ctx.Value(Key{}) + if untyped == nil { + logging.FromContext(ctx).Fatalf( + "Unable to fetch %T from context.", (v1alpha1.PolicyInformer)(nil)) + } + return untyped.(v1alpha1.PolicyInformer) +} diff --git a/vendor/github.com/knative/pkg/client/injection/informers/istio/factory/fake/fake.go b/vendor/github.com/knative/pkg/client/injection/informers/istio/factory/fake/fake.go new file mode 100644 index 0000000000..8180c2e584 --- /dev/null +++ b/vendor/github.com/knative/pkg/client/injection/informers/istio/factory/fake/fake.go @@ -0,0 +1,41 @@ +/* +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. +*/ + +// Code generated by injection-gen. DO NOT EDIT. + +package fake + +import ( + "context" + + externalversions "github.com/knative/pkg/client/informers/externalversions" + fake "github.com/knative/pkg/client/injection/client/fake" + factory "github.com/knative/pkg/client/injection/informers/istio/factory" + controller "github.com/knative/pkg/controller" + injection "github.com/knative/pkg/injection" +) + +var Get = factory.Get + +func init() { + injection.Fake.RegisterInformerFactory(withInformerFactory) +} + +func withInformerFactory(ctx context.Context) context.Context { + c := fake.Get(ctx) + return context.WithValue(ctx, factory.Key{}, + externalversions.NewSharedInformerFactory(c, controller.GetResyncPeriod(ctx))) +} diff --git a/vendor/github.com/knative/pkg/client/injection/informers/istio/factory/istiofactory.go b/vendor/github.com/knative/pkg/client/injection/informers/istio/factory/istiofactory.go new file mode 100644 index 0000000000..3dde0a3b80 --- /dev/null +++ b/vendor/github.com/knative/pkg/client/injection/informers/istio/factory/istiofactory.go @@ -0,0 +1,52 @@ +/* +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. +*/ + +// Code generated by injection-gen. DO NOT EDIT. + +package istiofactory + +import ( + "context" + + externalversions "github.com/knative/pkg/client/informers/externalversions" + client "github.com/knative/pkg/client/injection/client" + controller "github.com/knative/pkg/controller" + injection "github.com/knative/pkg/injection" + logging "github.com/knative/pkg/logging" +) + +func init() { + injection.Default.RegisterInformerFactory(withInformerFactory) +} + +// Key is used as the key for associating information with a context.Context. +type Key struct{} + +func withInformerFactory(ctx context.Context) context.Context { + c := client.Get(ctx) + return context.WithValue(ctx, Key{}, + externalversions.NewSharedInformerFactory(c, controller.GetResyncPeriod(ctx))) +} + +// Get extracts the InformerFactory from the context. +func Get(ctx context.Context) externalversions.SharedInformerFactory { + untyped := ctx.Value(Key{}) + if untyped == nil { + logging.FromContext(ctx).Fatalf( + "Unable to fetch %T from context.", (externalversions.SharedInformerFactory)(nil)) + } + return untyped.(externalversions.SharedInformerFactory) +} diff --git a/vendor/github.com/knative/pkg/client/injection/informers/istio/v1alpha3/destinationrule/destinationrule.go b/vendor/github.com/knative/pkg/client/injection/informers/istio/v1alpha3/destinationrule/destinationrule.go new file mode 100644 index 0000000000..eca63acd58 --- /dev/null +++ b/vendor/github.com/knative/pkg/client/injection/informers/istio/v1alpha3/destinationrule/destinationrule.go @@ -0,0 +1,52 @@ +/* +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. +*/ + +// Code generated by injection-gen. DO NOT EDIT. + +package destinationrule + +import ( + "context" + + v1alpha3 "github.com/knative/pkg/client/informers/externalversions/istio/v1alpha3" + factory "github.com/knative/pkg/client/injection/informers/istio/factory" + controller "github.com/knative/pkg/controller" + injection "github.com/knative/pkg/injection" + logging "github.com/knative/pkg/logging" +) + +func init() { + injection.Default.RegisterInformer(withInformer) +} + +// Key is used for associating the Informer inside the context.Context. +type Key struct{} + +func withInformer(ctx context.Context) (context.Context, controller.Informer) { + f := factory.Get(ctx) + inf := f.Networking().V1alpha3().DestinationRules() + return context.WithValue(ctx, Key{}, inf), inf.Informer() +} + +// Get extracts the typed informer from the context. +func Get(ctx context.Context) v1alpha3.DestinationRuleInformer { + untyped := ctx.Value(Key{}) + if untyped == nil { + logging.FromContext(ctx).Fatalf( + "Unable to fetch %T from context.", (v1alpha3.DestinationRuleInformer)(nil)) + } + return untyped.(v1alpha3.DestinationRuleInformer) +} diff --git a/vendor/github.com/knative/pkg/client/injection/informers/istio/v1alpha3/destinationrule/fake/fake.go b/vendor/github.com/knative/pkg/client/injection/informers/istio/v1alpha3/destinationrule/fake/fake.go new file mode 100644 index 0000000000..2df358ca42 --- /dev/null +++ b/vendor/github.com/knative/pkg/client/injection/informers/istio/v1alpha3/destinationrule/fake/fake.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. +*/ + +// Code generated by injection-gen. DO NOT EDIT. + +package fake + +import ( + "context" + + fake "github.com/knative/pkg/client/injection/informers/istio/factory/fake" + destinationrule "github.com/knative/pkg/client/injection/informers/istio/v1alpha3/destinationrule" + controller "github.com/knative/pkg/controller" + injection "github.com/knative/pkg/injection" +) + +var Get = destinationrule.Get + +func init() { + injection.Fake.RegisterInformer(withInformer) +} + +func withInformer(ctx context.Context) (context.Context, controller.Informer) { + f := fake.Get(ctx) + inf := f.Networking().V1alpha3().DestinationRules() + return context.WithValue(ctx, destinationrule.Key{}, inf), inf.Informer() +} diff --git a/vendor/github.com/knative/pkg/client/injection/informers/istio/v1alpha3/gateway/fake/fake.go b/vendor/github.com/knative/pkg/client/injection/informers/istio/v1alpha3/gateway/fake/fake.go new file mode 100644 index 0000000000..b7ba4e9b2a --- /dev/null +++ b/vendor/github.com/knative/pkg/client/injection/informers/istio/v1alpha3/gateway/fake/fake.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. +*/ + +// Code generated by injection-gen. DO NOT EDIT. + +package fake + +import ( + "context" + + fake "github.com/knative/pkg/client/injection/informers/istio/factory/fake" + gateway "github.com/knative/pkg/client/injection/informers/istio/v1alpha3/gateway" + controller "github.com/knative/pkg/controller" + injection "github.com/knative/pkg/injection" +) + +var Get = gateway.Get + +func init() { + injection.Fake.RegisterInformer(withInformer) +} + +func withInformer(ctx context.Context) (context.Context, controller.Informer) { + f := fake.Get(ctx) + inf := f.Networking().V1alpha3().Gateways() + return context.WithValue(ctx, gateway.Key{}, inf), inf.Informer() +} diff --git a/vendor/github.com/knative/pkg/client/injection/informers/istio/v1alpha3/gateway/gateway.go b/vendor/github.com/knative/pkg/client/injection/informers/istio/v1alpha3/gateway/gateway.go new file mode 100644 index 0000000000..b2400e2dd3 --- /dev/null +++ b/vendor/github.com/knative/pkg/client/injection/informers/istio/v1alpha3/gateway/gateway.go @@ -0,0 +1,52 @@ +/* +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. +*/ + +// Code generated by injection-gen. DO NOT EDIT. + +package gateway + +import ( + "context" + + v1alpha3 "github.com/knative/pkg/client/informers/externalversions/istio/v1alpha3" + factory "github.com/knative/pkg/client/injection/informers/istio/factory" + controller "github.com/knative/pkg/controller" + injection "github.com/knative/pkg/injection" + logging "github.com/knative/pkg/logging" +) + +func init() { + injection.Default.RegisterInformer(withInformer) +} + +// Key is used for associating the Informer inside the context.Context. +type Key struct{} + +func withInformer(ctx context.Context) (context.Context, controller.Informer) { + f := factory.Get(ctx) + inf := f.Networking().V1alpha3().Gateways() + return context.WithValue(ctx, Key{}, inf), inf.Informer() +} + +// Get extracts the typed informer from the context. +func Get(ctx context.Context) v1alpha3.GatewayInformer { + untyped := ctx.Value(Key{}) + if untyped == nil { + logging.FromContext(ctx).Fatalf( + "Unable to fetch %T from context.", (v1alpha3.GatewayInformer)(nil)) + } + return untyped.(v1alpha3.GatewayInformer) +} diff --git a/vendor/github.com/knative/pkg/client/injection/informers/istio/v1alpha3/virtualservice/fake/fake.go b/vendor/github.com/knative/pkg/client/injection/informers/istio/v1alpha3/virtualservice/fake/fake.go new file mode 100644 index 0000000000..7ad5cb3410 --- /dev/null +++ b/vendor/github.com/knative/pkg/client/injection/informers/istio/v1alpha3/virtualservice/fake/fake.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. +*/ + +// Code generated by injection-gen. DO NOT EDIT. + +package fake + +import ( + "context" + + fake "github.com/knative/pkg/client/injection/informers/istio/factory/fake" + virtualservice "github.com/knative/pkg/client/injection/informers/istio/v1alpha3/virtualservice" + controller "github.com/knative/pkg/controller" + injection "github.com/knative/pkg/injection" +) + +var Get = virtualservice.Get + +func init() { + injection.Fake.RegisterInformer(withInformer) +} + +func withInformer(ctx context.Context) (context.Context, controller.Informer) { + f := fake.Get(ctx) + inf := f.Networking().V1alpha3().VirtualServices() + return context.WithValue(ctx, virtualservice.Key{}, inf), inf.Informer() +} diff --git a/vendor/github.com/knative/pkg/client/injection/informers/istio/v1alpha3/virtualservice/virtualservice.go b/vendor/github.com/knative/pkg/client/injection/informers/istio/v1alpha3/virtualservice/virtualservice.go new file mode 100644 index 0000000000..7206062f94 --- /dev/null +++ b/vendor/github.com/knative/pkg/client/injection/informers/istio/v1alpha3/virtualservice/virtualservice.go @@ -0,0 +1,52 @@ +/* +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. +*/ + +// Code generated by injection-gen. DO NOT EDIT. + +package virtualservice + +import ( + "context" + + v1alpha3 "github.com/knative/pkg/client/informers/externalversions/istio/v1alpha3" + factory "github.com/knative/pkg/client/injection/informers/istio/factory" + controller "github.com/knative/pkg/controller" + injection "github.com/knative/pkg/injection" + logging "github.com/knative/pkg/logging" +) + +func init() { + injection.Default.RegisterInformer(withInformer) +} + +// Key is used for associating the Informer inside the context.Context. +type Key struct{} + +func withInformer(ctx context.Context) (context.Context, controller.Informer) { + f := factory.Get(ctx) + inf := f.Networking().V1alpha3().VirtualServices() + return context.WithValue(ctx, Key{}, inf), inf.Informer() +} + +// Get extracts the typed informer from the context. +func Get(ctx context.Context) v1alpha3.VirtualServiceInformer { + untyped := ctx.Value(Key{}) + if untyped == nil { + logging.FromContext(ctx).Fatalf( + "Unable to fetch %T from context.", (v1alpha3.VirtualServiceInformer)(nil)) + } + return untyped.(v1alpha3.VirtualServiceInformer) +} diff --git a/vendor/github.com/knative/pkg/client/listers/authentication/v1alpha1/expansion_generated.go b/vendor/github.com/knative/pkg/client/listers/authentication/v1alpha1/expansion_generated.go new file mode 100644 index 0000000000..f62cb91a70 --- /dev/null +++ b/vendor/github.com/knative/pkg/client/listers/authentication/v1alpha1/expansion_generated.go @@ -0,0 +1,27 @@ +/* +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. +*/ + +// Code generated by lister-gen. DO NOT EDIT. + +package v1alpha1 + +// PolicyListerExpansion allows custom methods to be added to +// PolicyLister. +type PolicyListerExpansion interface{} + +// PolicyNamespaceListerExpansion allows custom methods to be added to +// PolicyNamespaceLister. +type PolicyNamespaceListerExpansion interface{} diff --git a/vendor/github.com/knative/pkg/client/listers/authentication/v1alpha1/policy.go b/vendor/github.com/knative/pkg/client/listers/authentication/v1alpha1/policy.go new file mode 100644 index 0000000000..a8581d3e9f --- /dev/null +++ b/vendor/github.com/knative/pkg/client/listers/authentication/v1alpha1/policy.go @@ -0,0 +1,94 @@ +/* +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. +*/ + +// Code generated by lister-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + v1alpha1 "github.com/knative/pkg/apis/istio/authentication/v1alpha1" + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/client-go/tools/cache" +) + +// PolicyLister helps list Policies. +type PolicyLister interface { + // List lists all Policies in the indexer. + List(selector labels.Selector) (ret []*v1alpha1.Policy, err error) + // Policies returns an object that can list and get Policies. + Policies(namespace string) PolicyNamespaceLister + PolicyListerExpansion +} + +// policyLister implements the PolicyLister interface. +type policyLister struct { + indexer cache.Indexer +} + +// NewPolicyLister returns a new PolicyLister. +func NewPolicyLister(indexer cache.Indexer) PolicyLister { + return &policyLister{indexer: indexer} +} + +// List lists all Policies in the indexer. +func (s *policyLister) List(selector labels.Selector) (ret []*v1alpha1.Policy, err error) { + err = cache.ListAll(s.indexer, selector, func(m interface{}) { + ret = append(ret, m.(*v1alpha1.Policy)) + }) + return ret, err +} + +// Policies returns an object that can list and get Policies. +func (s *policyLister) Policies(namespace string) PolicyNamespaceLister { + return policyNamespaceLister{indexer: s.indexer, namespace: namespace} +} + +// PolicyNamespaceLister helps list and get Policies. +type PolicyNamespaceLister interface { + // List lists all Policies in the indexer for a given namespace. + List(selector labels.Selector) (ret []*v1alpha1.Policy, err error) + // Get retrieves the Policy from the indexer for a given namespace and name. + Get(name string) (*v1alpha1.Policy, error) + PolicyNamespaceListerExpansion +} + +// policyNamespaceLister implements the PolicyNamespaceLister +// interface. +type policyNamespaceLister struct { + indexer cache.Indexer + namespace string +} + +// List lists all Policies in the indexer for a given namespace. +func (s policyNamespaceLister) List(selector labels.Selector) (ret []*v1alpha1.Policy, err error) { + err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) { + ret = append(ret, m.(*v1alpha1.Policy)) + }) + return ret, err +} + +// Get retrieves the Policy from the indexer for a given namespace and name. +func (s policyNamespaceLister) Get(name string) (*v1alpha1.Policy, error) { + obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name) + if err != nil { + return nil, err + } + if !exists { + return nil, errors.NewNotFound(v1alpha1.Resource("policy"), name) + } + return obj.(*v1alpha1.Policy), nil +} diff --git a/vendor/github.com/knative/pkg/client/listers/istio/v1alpha3/destinationrule.go b/vendor/github.com/knative/pkg/client/listers/istio/v1alpha3/destinationrule.go new file mode 100644 index 0000000000..ec1ff75565 --- /dev/null +++ b/vendor/github.com/knative/pkg/client/listers/istio/v1alpha3/destinationrule.go @@ -0,0 +1,94 @@ +/* +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. +*/ + +// Code generated by lister-gen. DO NOT EDIT. + +package v1alpha3 + +import ( + v1alpha3 "github.com/knative/pkg/apis/istio/v1alpha3" + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/client-go/tools/cache" +) + +// DestinationRuleLister helps list DestinationRules. +type DestinationRuleLister interface { + // List lists all DestinationRules in the indexer. + List(selector labels.Selector) (ret []*v1alpha3.DestinationRule, err error) + // DestinationRules returns an object that can list and get DestinationRules. + DestinationRules(namespace string) DestinationRuleNamespaceLister + DestinationRuleListerExpansion +} + +// destinationRuleLister implements the DestinationRuleLister interface. +type destinationRuleLister struct { + indexer cache.Indexer +} + +// NewDestinationRuleLister returns a new DestinationRuleLister. +func NewDestinationRuleLister(indexer cache.Indexer) DestinationRuleLister { + return &destinationRuleLister{indexer: indexer} +} + +// List lists all DestinationRules in the indexer. +func (s *destinationRuleLister) List(selector labels.Selector) (ret []*v1alpha3.DestinationRule, err error) { + err = cache.ListAll(s.indexer, selector, func(m interface{}) { + ret = append(ret, m.(*v1alpha3.DestinationRule)) + }) + return ret, err +} + +// DestinationRules returns an object that can list and get DestinationRules. +func (s *destinationRuleLister) DestinationRules(namespace string) DestinationRuleNamespaceLister { + return destinationRuleNamespaceLister{indexer: s.indexer, namespace: namespace} +} + +// DestinationRuleNamespaceLister helps list and get DestinationRules. +type DestinationRuleNamespaceLister interface { + // List lists all DestinationRules in the indexer for a given namespace. + List(selector labels.Selector) (ret []*v1alpha3.DestinationRule, err error) + // Get retrieves the DestinationRule from the indexer for a given namespace and name. + Get(name string) (*v1alpha3.DestinationRule, error) + DestinationRuleNamespaceListerExpansion +} + +// destinationRuleNamespaceLister implements the DestinationRuleNamespaceLister +// interface. +type destinationRuleNamespaceLister struct { + indexer cache.Indexer + namespace string +} + +// List lists all DestinationRules in the indexer for a given namespace. +func (s destinationRuleNamespaceLister) List(selector labels.Selector) (ret []*v1alpha3.DestinationRule, err error) { + err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) { + ret = append(ret, m.(*v1alpha3.DestinationRule)) + }) + return ret, err +} + +// Get retrieves the DestinationRule from the indexer for a given namespace and name. +func (s destinationRuleNamespaceLister) Get(name string) (*v1alpha3.DestinationRule, error) { + obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name) + if err != nil { + return nil, err + } + if !exists { + return nil, errors.NewNotFound(v1alpha3.Resource("destinationrule"), name) + } + return obj.(*v1alpha3.DestinationRule), nil +} diff --git a/vendor/github.com/knative/pkg/client/listers/istio/v1alpha3/expansion_generated.go b/vendor/github.com/knative/pkg/client/listers/istio/v1alpha3/expansion_generated.go new file mode 100644 index 0000000000..f3e2ec937f --- /dev/null +++ b/vendor/github.com/knative/pkg/client/listers/istio/v1alpha3/expansion_generated.go @@ -0,0 +1,43 @@ +/* +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. +*/ + +// Code generated by lister-gen. DO NOT EDIT. + +package v1alpha3 + +// DestinationRuleListerExpansion allows custom methods to be added to +// DestinationRuleLister. +type DestinationRuleListerExpansion interface{} + +// DestinationRuleNamespaceListerExpansion allows custom methods to be added to +// DestinationRuleNamespaceLister. +type DestinationRuleNamespaceListerExpansion interface{} + +// GatewayListerExpansion allows custom methods to be added to +// GatewayLister. +type GatewayListerExpansion interface{} + +// GatewayNamespaceListerExpansion allows custom methods to be added to +// GatewayNamespaceLister. +type GatewayNamespaceListerExpansion interface{} + +// VirtualServiceListerExpansion allows custom methods to be added to +// VirtualServiceLister. +type VirtualServiceListerExpansion interface{} + +// VirtualServiceNamespaceListerExpansion allows custom methods to be added to +// VirtualServiceNamespaceLister. +type VirtualServiceNamespaceListerExpansion interface{} diff --git a/vendor/github.com/knative/pkg/client/listers/istio/v1alpha3/gateway.go b/vendor/github.com/knative/pkg/client/listers/istio/v1alpha3/gateway.go new file mode 100644 index 0000000000..62a78893a6 --- /dev/null +++ b/vendor/github.com/knative/pkg/client/listers/istio/v1alpha3/gateway.go @@ -0,0 +1,94 @@ +/* +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. +*/ + +// Code generated by lister-gen. DO NOT EDIT. + +package v1alpha3 + +import ( + v1alpha3 "github.com/knative/pkg/apis/istio/v1alpha3" + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/client-go/tools/cache" +) + +// GatewayLister helps list Gateways. +type GatewayLister interface { + // List lists all Gateways in the indexer. + List(selector labels.Selector) (ret []*v1alpha3.Gateway, err error) + // Gateways returns an object that can list and get Gateways. + Gateways(namespace string) GatewayNamespaceLister + GatewayListerExpansion +} + +// gatewayLister implements the GatewayLister interface. +type gatewayLister struct { + indexer cache.Indexer +} + +// NewGatewayLister returns a new GatewayLister. +func NewGatewayLister(indexer cache.Indexer) GatewayLister { + return &gatewayLister{indexer: indexer} +} + +// List lists all Gateways in the indexer. +func (s *gatewayLister) List(selector labels.Selector) (ret []*v1alpha3.Gateway, err error) { + err = cache.ListAll(s.indexer, selector, func(m interface{}) { + ret = append(ret, m.(*v1alpha3.Gateway)) + }) + return ret, err +} + +// Gateways returns an object that can list and get Gateways. +func (s *gatewayLister) Gateways(namespace string) GatewayNamespaceLister { + return gatewayNamespaceLister{indexer: s.indexer, namespace: namespace} +} + +// GatewayNamespaceLister helps list and get Gateways. +type GatewayNamespaceLister interface { + // List lists all Gateways in the indexer for a given namespace. + List(selector labels.Selector) (ret []*v1alpha3.Gateway, err error) + // Get retrieves the Gateway from the indexer for a given namespace and name. + Get(name string) (*v1alpha3.Gateway, error) + GatewayNamespaceListerExpansion +} + +// gatewayNamespaceLister implements the GatewayNamespaceLister +// interface. +type gatewayNamespaceLister struct { + indexer cache.Indexer + namespace string +} + +// List lists all Gateways in the indexer for a given namespace. +func (s gatewayNamespaceLister) List(selector labels.Selector) (ret []*v1alpha3.Gateway, err error) { + err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) { + ret = append(ret, m.(*v1alpha3.Gateway)) + }) + return ret, err +} + +// Get retrieves the Gateway from the indexer for a given namespace and name. +func (s gatewayNamespaceLister) Get(name string) (*v1alpha3.Gateway, error) { + obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name) + if err != nil { + return nil, err + } + if !exists { + return nil, errors.NewNotFound(v1alpha3.Resource("gateway"), name) + } + return obj.(*v1alpha3.Gateway), nil +} diff --git a/vendor/github.com/knative/pkg/client/listers/istio/v1alpha3/virtualservice.go b/vendor/github.com/knative/pkg/client/listers/istio/v1alpha3/virtualservice.go new file mode 100644 index 0000000000..3284cda81b --- /dev/null +++ b/vendor/github.com/knative/pkg/client/listers/istio/v1alpha3/virtualservice.go @@ -0,0 +1,94 @@ +/* +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. +*/ + +// Code generated by lister-gen. DO NOT EDIT. + +package v1alpha3 + +import ( + v1alpha3 "github.com/knative/pkg/apis/istio/v1alpha3" + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/client-go/tools/cache" +) + +// VirtualServiceLister helps list VirtualServices. +type VirtualServiceLister interface { + // List lists all VirtualServices in the indexer. + List(selector labels.Selector) (ret []*v1alpha3.VirtualService, err error) + // VirtualServices returns an object that can list and get VirtualServices. + VirtualServices(namespace string) VirtualServiceNamespaceLister + VirtualServiceListerExpansion +} + +// virtualServiceLister implements the VirtualServiceLister interface. +type virtualServiceLister struct { + indexer cache.Indexer +} + +// NewVirtualServiceLister returns a new VirtualServiceLister. +func NewVirtualServiceLister(indexer cache.Indexer) VirtualServiceLister { + return &virtualServiceLister{indexer: indexer} +} + +// List lists all VirtualServices in the indexer. +func (s *virtualServiceLister) List(selector labels.Selector) (ret []*v1alpha3.VirtualService, err error) { + err = cache.ListAll(s.indexer, selector, func(m interface{}) { + ret = append(ret, m.(*v1alpha3.VirtualService)) + }) + return ret, err +} + +// VirtualServices returns an object that can list and get VirtualServices. +func (s *virtualServiceLister) VirtualServices(namespace string) VirtualServiceNamespaceLister { + return virtualServiceNamespaceLister{indexer: s.indexer, namespace: namespace} +} + +// VirtualServiceNamespaceLister helps list and get VirtualServices. +type VirtualServiceNamespaceLister interface { + // List lists all VirtualServices in the indexer for a given namespace. + List(selector labels.Selector) (ret []*v1alpha3.VirtualService, err error) + // Get retrieves the VirtualService from the indexer for a given namespace and name. + Get(name string) (*v1alpha3.VirtualService, error) + VirtualServiceNamespaceListerExpansion +} + +// virtualServiceNamespaceLister implements the VirtualServiceNamespaceLister +// interface. +type virtualServiceNamespaceLister struct { + indexer cache.Indexer + namespace string +} + +// List lists all VirtualServices in the indexer for a given namespace. +func (s virtualServiceNamespaceLister) List(selector labels.Selector) (ret []*v1alpha3.VirtualService, err error) { + err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) { + ret = append(ret, m.(*v1alpha3.VirtualService)) + }) + return ret, err +} + +// Get retrieves the VirtualService from the indexer for a given namespace and name. +func (s virtualServiceNamespaceLister) Get(name string) (*v1alpha3.VirtualService, error) { + obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name) + if err != nil { + return nil, err + } + if !exists { + return nil, errors.NewNotFound(v1alpha3.Resource("virtualservice"), name) + } + return obj.(*v1alpha3.VirtualService), nil +} diff --git a/vendor/github.com/knative/pkg/cloudevents/OWNERS b/vendor/github.com/knative/pkg/cloudevents/OWNERS new file mode 100644 index 0000000000..27343aba0a --- /dev/null +++ b/vendor/github.com/knative/pkg/cloudevents/OWNERS @@ -0,0 +1,4 @@ +# The OWNERS file is used by prow to automatically merge approved PRs. + +approvers: +- cloudevents-approvers diff --git a/vendor/github.com/knative/pkg/cloudevents/README.md b/vendor/github.com/knative/pkg/cloudevents/README.md new file mode 100644 index 0000000000..8e3e541f4c --- /dev/null +++ b/vendor/github.com/knative/pkg/cloudevents/README.md @@ -0,0 +1,151 @@ +# Knative CloudEvents SDK + +This library produces CloudEvents in version 0.1 compatible form. To learn more +about CloudEvents, see the [Specification](https://github.com/cloudevents/spec). + +There are two roles the SDK fulfills: the [producer](#producer) and the +[consumer](#consumer). The producer creates a cloud event in either +[Binary](#binary) or [Structured](#structured) request format. The producer +assembles and sends the event through an HTTP endpoint. The consumer will +inspect the incoming HTTP request and select the correct decode format. + +This SDK should be wire-compatible with any other producer or consumer of the +supported versions of CloudEvents. + +## Getting Started + +CloudEvents acts as the envelope in which to send a custom object. Define a +CloudEvent type for the events you will be producing. + +Example CloudEvent Type: `dev.knative.cloudevent.example` + +Select a source to identify the originator of this CloudEvent. It should be a +valid URI which represents the subject which created the CloudEvent (cloud +bucket, git repo, etc). + +Example CloudEvent Source: `https://github.com/knative/pkg#cloudevents-example` + +And finally, create a struct that will be the data inside the CloudEvent, +example: + +```go + +type Example struct { + Sequence int `json:"id"` + Message string `json:"message"` +} + +``` + +### Producer + +The producer creates a new `cloudevent.Client,` and then sends 10 `Example` +events to `"http://localhost:8080"`. + +```go + +package main + +import ( + "github.com/knative/pkg/cloudevents" + "log" +) + +type Example struct { + Sequence int `json:"id"` + Message string `json:"message"` +} + +func main() { + c := cloudevents.NewClient( + "http://localhost:8080", + cloudevents.Builder{ + Source: "https://github.com/knative/pkg#cloudevents-example", + EventType: "dev.knative.cloudevent.example", + }, + ) + for i := 0; i < 10; i++ { + data := Example{ + Message: "hello, world!", + Sequence: i, + } + if err := c.Send(data); err != nil { + log.Printf("error sending: %v", err) + } + } +} + +``` + +### Consumer + +The consumer will listen for a post and then inspect the headers to understand +how to decode the request. + +```go + +package main + +import ( + "context" + "log" + "net/http" + "time" + + "github.com/knative/pkg/cloudevents" +) + +type Example struct { + Sequence int `json:"id"` + Message string `json:"message"` +} + +func handler(ctx context.Context, data *Example) { + metadata := cloudevents.FromContext(ctx) + log.Printf("[%s] %s %s: %d, %q", metadata.EventTime.Format(time.RFC3339), metadata.ContentType, metadata.Source, data.Sequence, data.Message) +} + +func main() { + log.Print("listening on port 8080") + log.Fatal(http.ListenAndServe(":8080", cloudevents.Handler(handler))) +} + +``` + +## Request Formats + +### CloudEvents Version 0.1 + +#### Binary + +This is default, but to leverage binary request format: + +```go + + c := cloudevents.NewClient( + "http://localhost:8080", + cloudevents.Builder{ + Source: "https://github.com/knative/pkg#cloudevents-example", + EventType: "dev.knative.cloudevent.example", + Encoding: cloudevents.BinaryV01, + }, + ) + +``` + +#### Structured + +To leverage structured request format: + +```go + + c := cloudevents.NewClient( + "http://localhost:8080", + cloudevents.Builder{ + Source: "https://github.com/knative/pkg#cloudevents-example", + EventType: "dev.knative.cloudevent.example", + Encoding: cloudevents.StructuredV01, + }, + ) + +``` diff --git a/vendor/github.com/knative/pkg/cloudevents/builder.go b/vendor/github.com/knative/pkg/cloudevents/builder.go new file mode 100644 index 0000000000..4cf3706d96 --- /dev/null +++ b/vendor/github.com/knative/pkg/cloudevents/builder.go @@ -0,0 +1,135 @@ +/* +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 cloudevents + +import ( + "fmt" + "net/http" + "time" + + "github.com/google/uuid" +) + +// CloudEventEncoding is used to tell the builder which encoding to select. +// the default is Binary. +type CloudEventEncoding int + +const ( + // Binary v0.1 + BinaryV01 CloudEventEncoding = iota + // Structured v0.1 + StructuredV01 +) + +// Builder holds settings that do not change over CloudEvents. It is intended +// to represent a builder of only a single CloudEvent type. +type Builder struct { + // A URI describing the event producer. + Source string + // Type of occurrence which has happened. + EventType string + // The version of the `eventType`; this is producer-specific. + EventTypeVersion string + // A link to the schema that the `data` attribute adheres to. + SchemaURL string + // Additional metadata without a well-defined structure. + Extensions map[string]interface{} + + // Encoding specifies the requested output encoding of the CloudEvent. + Encoding CloudEventEncoding +} + +// Build produces a http request with the constant data embedded in the builder +// merged with the new data provided in the build function. The request will +// send a pre-assembled cloud event to the given target. The target is assumed +// to be a URL with a scheme, ie: "http://localhost:8080" +func (b *Builder) Build(target string, data interface{}, overrides ...SendContext) (*http.Request, error) { + if len(overrides) > 1 { + return nil, fmt.Errorf("Build was called with more than one override") + } + + var overridesV01 *V01EventContext + if len(overrides) == 1 { + switch t := overrides[0].(type) { + case V01EventContext: + o := overrides[0].(V01EventContext) + overridesV01 = &o + default: + return nil, fmt.Errorf("Build was called with unknown override type %v", t) + } + } + // TODO: when V02 is supported this will have to shuffle a little. + ctx := b.cloudEventsContextV01(overridesV01) + + if ctx.Source == "" { + return nil, fmt.Errorf("ctx.Source resolved empty") + } + if ctx.EventType == "" { + return nil, fmt.Errorf("ctx.EventType resolved empty") + } + + switch b.Encoding { + case BinaryV01: + return Binary.NewRequest(target, data, ctx) + case StructuredV01: + return Structured.NewRequest(target, data, ctx) + default: + return nil, fmt.Errorf("unsupported encoding: %v", b.Encoding) + } +} + +// cloudEventsContext creates a CloudEvent context object, assumes +// application/json as the content type. +func (b *Builder) cloudEventsContextV01(overrides *V01EventContext) V01EventContext { + ctx := V01EventContext{ + CloudEventsVersion: CloudEventsVersion, + EventType: b.EventType, + EventID: uuid.New().String(), + EventTypeVersion: b.EventTypeVersion, + SchemaURL: b.SchemaURL, + Source: b.Source, + ContentType: "application/json", + EventTime: time.Now(), + Extensions: b.Extensions, + } + if overrides != nil { + if overrides.Source != "" { + ctx.Source = overrides.Source + } + if overrides.EventID != "" { + ctx.EventID = overrides.EventID + } + if overrides.EventType != "" { + ctx.EventType = overrides.EventType + } + if !overrides.EventTime.IsZero() { + ctx.EventTime = overrides.EventTime + } + if overrides.ContentType != "" { + ctx.ContentType = overrides.ContentType + } + if len(overrides.Extensions) > 0 { + if ctx.Extensions == nil { + ctx.Extensions = make(map[string]interface{}) + } + for k, v := range overrides.Extensions { + ctx.Extensions[k] = v + } + } + } + return ctx +} diff --git a/vendor/github.com/knative/pkg/cloudevents/client.go b/vendor/github.com/knative/pkg/cloudevents/client.go new file mode 100644 index 0000000000..9846edf1da --- /dev/null +++ b/vendor/github.com/knative/pkg/cloudevents/client.go @@ -0,0 +1,81 @@ +/* +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 cloudevents + +import ( + "fmt" + "io/ioutil" + "net/http" +) + +// Client wraps Builder, and is intended to be configured for a single event +// type and target +type Client struct { + builder Builder + Target string +} + +// NewClient returns a CloudEvent Client used to send CloudEvents. It is +// intended that a user would create a new client for each tuple of eventType +// and target. This is an optional helper method to avoid the tricky creation +// of the embedded Builder struct. +func NewClient(target string, builder Builder) *Client { + c := &Client{ + builder: builder, + Target: target, + } + return c +} + +// Send creates a request based on the client's settings and sends the data +// struct to the target set for this client. It returns error if there was an +// issue sending the event, otherwise nil means the event was accepted. +func (c *Client) Send(data interface{}, overrides ...SendContext) error { + req, err := c.builder.Build(c.Target, data, overrides...) + if err != nil { + return err + } + client := &http.Client{} + resp, err := client.Do(req) + if err != nil { + return err + } + defer resp.Body.Close() + if accepted(resp) { + return nil + } + return fmt.Errorf("error sending cloudevent: %s", status(resp)) +} + +// accepted is a helper method to understand if the response from the target +// accepted the CloudEvent. +func accepted(resp *http.Response) bool { + if resp.StatusCode >= 200 && resp.StatusCode < 300 { + return true + } + return false +} + +// status is a helper method to read the response of the target. +func status(resp *http.Response) string { + status := resp.Status + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + return fmt.Sprintf("Status[%s] error reading response body: %v", status, err) + } + return fmt.Sprintf("Status[%s] %s", status, body) +} diff --git a/vendor/github.com/knative/pkg/cloudevents/doc.go b/vendor/github.com/knative/pkg/cloudevents/doc.go new file mode 100644 index 0000000000..62bc3b02ce --- /dev/null +++ b/vendor/github.com/knative/pkg/cloudevents/doc.go @@ -0,0 +1,22 @@ +/* +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 cloudevents implements utilities for handling CloudEvents. +// For information on the spec, see +// https://github.com/cloudevents/spec/blob/v0.1/http-transport-binding.md +// and +// https://github.com/cloudevents/spec/blob/v0.1/spec.md +package cloudevents diff --git a/vendor/github.com/knative/pkg/cloudevents/encoding_binary.go b/vendor/github.com/knative/pkg/cloudevents/encoding_binary.go new file mode 100644 index 0000000000..8ed4fbfaad --- /dev/null +++ b/vendor/github.com/knative/pkg/cloudevents/encoding_binary.go @@ -0,0 +1,125 @@ +/* +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 cloudevents + +// TODO(inlined): must add header encoding/decoding + +import ( + "bytes" + "fmt" + "io/ioutil" + "net/http" + "net/url" +) + +const ( + // HeaderCloudEventsVersion is the header for the version of Cloud Events + // used. + HeaderCloudEventsVersion = "CE-CloudEventsVersion" + + // HeaderEventID is the header for the unique ID of this event. + HeaderEventID = "CE-EventID" + + // HeaderEventTime is the OPTIONAL header for the time at which an event + // occurred. + HeaderEventTime = "CE-EventTime" + + // HeaderEventType is the header for type of event represented. Value SHOULD + // be in reverse-dns form. + HeaderEventType = "CE-EventType" + + // HeaderEventTypeVersion is the OPTIONAL header for the version of the + // scheme for the event type. + HeaderEventTypeVersion = "CE-EventTypeVersion" + + // HeaderSchemaURL is the OPTIONAL header for the schema of the event data. + HeaderSchemaURL = "CE-SchemaURL" + + // HeaderSource is the header for the source which emitted this event. + HeaderSource = "CE-Source" + + // HeaderExtensionsPrefix is the OPTIONAL header prefix for CloudEvents extensions + HeaderExtensionsPrefix = "CE-X-" + + // Binary implements Binary encoding/decoding + Binary binary = 0 +) + +type binary int + +// BinarySender implements an interface for sending an EventContext as +// (possibly one of several versions) as a binary encoding HTTP request. +type BinarySender interface { + // AsHeaders converts this EventContext to a set of HTTP headers. + AsHeaders() (http.Header, error) +} + +// BinaryLoader implements an interface for translating a binary encoding HTTP +// request or response to a an EventContext (possibly one of several versions). +type BinaryLoader interface { + // FromHeaders copies data from the supplied HTTP headers into the object. + // Values will be defaulted if necessary. + FromHeaders(in http.Header) error +} + +// FromRequest parses event data and context from an HTTP request. +func (binary) FromRequest(data interface{}, r *http.Request) (LoadContext, error) { + var ec LoadContext + switch { + case r.Header.Get("CE-SpecVersion") == V02CloudEventsVersion: + ec = &V02EventContext{} + case r.Header.Get("CE-CloudEventsVersion") == V01CloudEventsVersion: + ec = &V01EventContext{} + default: + return nil, fmt.Errorf("Could not determine Cloud Events version from header: %+v", r.Header) + } + + if err := ec.FromHeaders(r.Header); err != nil { + return nil, err + } + + if err := unmarshalEventData(ec.DataContentType(), r.Body, data); err != nil { + return nil, err + } + + return ec, nil +} + +// NewRequest creates an HTTP request for Binary content encoding. +func (t binary) NewRequest(urlString string, data interface{}, context SendContext) (*http.Request, error) { + url, err := url.Parse(urlString) + if err != nil { + return nil, err + } + + h, err := context.AsHeaders() + if err != nil { + return nil, err + } + + b, err := marshalEventData(h.Get("Content-Type"), data) + if err != nil { + return nil, err + } + + return &http.Request{ + Method: http.MethodPost, + URL: url, + Header: h, + Body: ioutil.NopCloser(bytes.NewReader(b)), + }, nil +} diff --git a/vendor/github.com/knative/pkg/cloudevents/encoding_structured.go b/vendor/github.com/knative/pkg/cloudevents/encoding_structured.go new file mode 100644 index 0000000000..8670241d38 --- /dev/null +++ b/vendor/github.com/knative/pkg/cloudevents/encoding_structured.go @@ -0,0 +1,143 @@ +/* +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 cloudevents + +import ( + "bytes" + "encoding/json" + "fmt" + "io" + "io/ioutil" + "net/http" + "net/url" + "strings" +) + +const ( + // Structured implements the JSON structured encoding/decoding + Structured structured = 0 +) + +type structured int + +// StructuredSender implements an interface for translating an EventContext +// (possibly one of severals versions) to a structured encoding HTTP request. +type StructuredSender interface { + // AsJSON encodes the object into a map from string to JSON data, which + // allows additional keys to be encoded later. + AsJSON() (map[string]json.RawMessage, error) +} + +// StructuredLoader implements an interface for translating a structured +// encoding HTTP request or response to a an EventContext (possibly one of +// several versions). +type StructuredLoader interface { + // FromJSON assumes that the object has already been decoded into a raw map + // from string to json.RawMessage, because this is needed to extract the + // CloudEvents version. + FromJSON(map[string]json.RawMessage) error +} + +// FromRequest parses a CloudEvent from structured content encoding. +func (structured) FromRequest(data interface{}, r *http.Request) (LoadContext, error) { + raw := make(map[string]json.RawMessage) + if err := json.NewDecoder(r.Body).Decode(&raw); err != nil { + return nil, err + } + + rawData := raw["data"] + delete(raw, "data") + + var ec LoadContext + v := "" + if err := json.Unmarshal(raw["specversion"], &v); err == nil && v == V02CloudEventsVersion { + ec = &V02EventContext{} + } else if err := json.Unmarshal(raw["cloudEventsVersion"], &v); err == nil && v == V01CloudEventsVersion { + ec = &V01EventContext{} + } else { + return nil, fmt.Errorf("Could not determine Cloud Events version from payload: %q", data) + } + + if err := ec.FromJSON(raw); err != nil { + return nil, err + } + + contentType := ec.DataContentType() + if contentType == "" { + contentType = contentTypeJSON + } + var reader io.Reader + if !isJSONEncoding(contentType) { + var jsonDecoded string + if err := json.Unmarshal(rawData, &jsonDecoded); err != nil { + return nil, fmt.Errorf("Could not JSON decode %q value %q", contentType, rawData) + } + reader = strings.NewReader(jsonDecoded) + } else { + reader = bytes.NewReader(rawData) + } + if err := unmarshalEventData(contentType, reader, data); err != nil { + return nil, err + } + return ec, nil +} + +// NewRequest creates an HTTP request for Structured content encoding. +func (structured) NewRequest(urlString string, data interface{}, context SendContext) (*http.Request, error) { + url, err := url.Parse(urlString) + if err != nil { + return nil, err + } + + fields, err := context.AsJSON() + if err != nil { + return nil, err + } + + // TODO: remove this defaulting? + contentType := context.DataContentType() + if contentType == "" { + contentType = contentTypeJSON + } + + dataBytes, err := marshalEventData(contentType, data) + if err != nil { + return nil, err + } + if isJSONEncoding(contentType) { + fields["data"] = json.RawMessage(dataBytes) + } else { + fields["data"], err = json.Marshal(string(dataBytes)) + if err != nil { + return nil, err + } + } + + b, err := json.Marshal(fields) + if err != nil { + return nil, err + } + + h := http.Header{} + h.Set(HeaderContentType, ContentTypeStructuredJSON) + return &http.Request{ + Method: http.MethodPost, + URL: url, + Header: h, + Body: ioutil.NopCloser(bytes.NewReader(b)), + }, nil +} diff --git a/vendor/github.com/knative/pkg/cloudevents/event.go b/vendor/github.com/knative/pkg/cloudevents/event.go new file mode 100644 index 0000000000..478c1cfe3f --- /dev/null +++ b/vendor/github.com/knative/pkg/cloudevents/event.go @@ -0,0 +1,212 @@ +/* +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 cloudevents + +import ( + "context" + "encoding/json" + "encoding/xml" + "fmt" + "io" + "net/http" + "reflect" +) + +const ( + // ContentTypeStructuredJSON is the content-type for "Structured" encoding + // where an event envelope is written in JSON and the body is arbitrary + // data which might be an alternate encoding. + ContentTypeStructuredJSON = "application/cloudevents+json" + + // ContentTypeBinaryJSON is the content-type for "Binary" encoding where + // the event context is in HTTP headers and the body is a JSON event data. + ContentTypeBinaryJSON = "application/json" + + // TODO(inlined) what about charset additions? + contentTypeJSON = "application/json" + contentTypeXML = "application/xml" + + // HeaderContentType is the standard HTTP header "Content-Type" + HeaderContentType = "Content-Type" + + // CloudEventsVersion is a legacy alias of V01CloudEventsVersion, for compatibility. + CloudEventsVersion = V01CloudEventsVersion +) + +// EventContext is a legacy un-versioned alias, from when we thought that field names would stay the same. +type EventContext = V01EventContext + +// HTTPMarshaller implements a scheme for decoding CloudEvents over HTTP. +// Implementations are Binary, Structured, and Any +type HTTPMarshaller interface { + FromRequest(data interface{}, r *http.Request) (LoadContext, error) + NewRequest(urlString string, data interface{}, context SendContext) (*http.Request, error) +} + +// ContextTranslator provides a set of translation methods between the +// different versions of the CloudEvents spec, which allows programs to +// interoperate with different versions of the CloudEvents spec by +// converting EventContexts to their preferred version. +type ContextTranslator interface { + // AsV01 provides a translation from whatever the "native" encoding of the + // CloudEvent was to the equivalent in v0.1 field names, moving fields to or + // from extensions as necessary. + AsV01() V01EventContext + + // AsV02 provides a translation from whatever the "native" encoding of the + // CloudEvent was to the equivalent in v0.2 field names, moving fields to or + // from extensions as necessary. + AsV02() V02EventContext + + // DataContentType returns the MIME content type for encoding data, which is + // needed by both encoding and decoding. + DataContentType() string +} + +// SendContext provides an interface for extracting information from an +// EventContext (the set of non-data event attributes of a CloudEvent). +type SendContext interface { + ContextTranslator + + StructuredSender + BinarySender +} + +// LoadContext provides an interface for extracting information from an +// EventContext (the set of non-data event attributes of a CloudEvent). +type LoadContext interface { + ContextTranslator + + StructuredLoader + BinaryLoader +} + +// ContextType is a unified interface for both sending and loading the +// CloudEvent data across versions. +type ContextType interface { + ContextTranslator + + StructuredSender + BinarySender + + StructuredLoader + BinaryLoader +} + +func anyError(errs ...error) error { + for _, err := range errs { + if err != nil { + return err + } + } + return nil +} + +func require(name string, value string) error { + if len(value) == 0 { + return fmt.Errorf("missing required field %q", name) + } + return nil +} + +// The Cloud-Events spec allows two forms of JSON encoding: +// 1. The overall message (Structured JSON encoding) +// 2. Just the event data, where the context will be in HTTP headers instead +// +// Case #1 actually includes case #2. In structured binary encoding the JSON +// HTTP body itself allows for cross-encoding of the "data" field. +// This method is only intended for checking that inner JSON encoding type. +func isJSONEncoding(encoding string) bool { + return encoding == contentTypeJSON || encoding == "text/json" +} + +func isXMLEncoding(encoding string) bool { + return encoding == contentTypeXML || encoding == "text/xml" +} + +func unmarshalEventData(encoding string, reader io.Reader, data interface{}) error { + // The Handler tools allow developers to not ask for event data; + // in this case, just don't unmarshal anything + if data == nil { + return nil + } + + // If someone tried to marshal an event into an io.Reader, just assign our existing reader. + // (This is used by event.Mux to determine which type to unmarshal as) + readerPtrType := reflect.TypeOf((*io.Reader)(nil)) + if reflect.TypeOf(data).ConvertibleTo(readerPtrType) { + reflect.ValueOf(data).Elem().Set(reflect.ValueOf(reader)) + return nil + } + if isJSONEncoding(encoding) || encoding == "" { + return json.NewDecoder(reader).Decode(&data) + } + + if isXMLEncoding(encoding) { + return xml.NewDecoder(reader).Decode(&data) + } + + return fmt.Errorf("Cannot decode content type %q", encoding) +} + +func marshalEventData(encoding string, data interface{}) ([]byte, error) { + var b []byte + var err error + + if isJSONEncoding(encoding) { + b, err = json.Marshal(data) + } else if isXMLEncoding(encoding) { + b, err = xml.Marshal(data) + } else { + err = fmt.Errorf("Cannot encode content type %q", encoding) + } + + if err != nil { + return nil, err + } + return b, nil +} + +// FromRequest parses a CloudEvent from any known encoding. +func FromRequest(data interface{}, r *http.Request) (LoadContext, error) { + switch r.Header.Get(HeaderContentType) { + case ContentTypeStructuredJSON: + return Structured.FromRequest(data, r) + case ContentTypeBinaryJSON: + return Binary.FromRequest(data, r) + default: + // TODO: assume binary content mode + // (https://github.com/cloudevents/spec/blob/v0.1/http-transport-binding.md#3-http-message-mapping) + // and that data is ??? (io.Reader?, byte array?) + return nil, fmt.Errorf("Cannot handle encoding %q", r.Header.Get("Content-Type")) + } +} + +// NewRequest craetes an HTTP request for Structured content encoding. +func NewRequest(urlString string, data interface{}, context SendContext) (*http.Request, error) { + return Structured.NewRequest(urlString, data, context) +} + +// Opaque key type used to store V01EventContexts in a context.Context +type contextKeyType struct{} + +var contextKey = contextKeyType{} + +// FromContext loads an V01EventContext from a normal context.Context +func FromContext(ctx context.Context) LoadContext { + return ctx.Value(contextKey).(LoadContext) +} diff --git a/vendor/github.com/knative/pkg/cloudevents/event_v01.go b/vendor/github.com/knative/pkg/cloudevents/event_v01.go new file mode 100644 index 0000000000..2ba67ca0c0 --- /dev/null +++ b/vendor/github.com/knative/pkg/cloudevents/event_v01.go @@ -0,0 +1,236 @@ +/* +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 cloudevents + +import ( + "encoding/json" + "fmt" + "net/http" + "strings" + "time" +) + +const ( + // V01CloudEventsVersion is the version of the CloudEvents spec targeted + // by this library. + V01CloudEventsVersion = "0.1" + + // v0.1 field names + fieldCloudEventsVersion = "CloudEventsVersion" + fieldEventID = "EventID" + fieldEventType = "EventType" +) + +// V01EventContext holds standard metadata about an event. See +// https://github.com/cloudevents/spec/blob/v0.1/spec.md#context-attributes for +// details on these fields. +type V01EventContext struct { + // The version of the CloudEvents specification used by the event. + CloudEventsVersion string `json:"cloudEventsVersion,omitempty"` + // ID of the event; must be non-empty and unique within the scope of the producer. + EventID string `json:"eventID"` + // Timestamp when the event happened. + EventTime time.Time `json:"eventTime,omitempty"` + // Type of occurrence which has happened. + EventType string `json:"eventType"` + // The version of the `eventType`; this is producer-specific. + EventTypeVersion string `json:"eventTypeVersion,omitempty"` + // A link to the schema that the `data` attribute adheres to. + SchemaURL string `json:"schemaURL,omitempty"` + // A MIME (RFC 2046) string describing the media type of `data`. + // TODO: Should an empty string assume `application/json`, or auto-detect the content? + ContentType string `json:"contentType,omitempty"` + // A URI describing the event producer. + Source string `json:"source"` + // Additional metadata without a well-defined structure. + Extensions map[string]interface{} `json:"extensions,omitempty"` +} + +// AsV01 implements the ContextTranslator interface. +func (ec V01EventContext) AsV01() V01EventContext { + return ec +} + +// AsV02 implements the ContextTranslator interface. +func (ec V01EventContext) AsV02() V02EventContext { + ret := V02EventContext{ + SpecVersion: V02CloudEventsVersion, + Type: ec.EventType, + Source: ec.Source, + ID: ec.EventID, + Time: ec.EventTime, + SchemaURL: ec.SchemaURL, + ContentType: ec.ContentType, + Extensions: make(map[string]interface{}), + } + // eventTypeVersion was retired in v0.2, so put it in an extension. + if ec.EventTypeVersion != "" { + ret.Extensions["eventtypeversion"] = ec.EventTypeVersion + } + for k, v := range ec.Extensions { + ret.Extensions[k] = v + } + return ret +} + +// AsHeaders implements the BinarySender interface. +func (ec V01EventContext) AsHeaders() (http.Header, error) { + h := http.Header{} + h.Set("CE-CloudEventsVersion", ec.CloudEventsVersion) + h.Set("CE-EventID", ec.EventID) + h.Set("CE-EventType", ec.EventType) + h.Set("CE-Source", ec.Source) + if ec.CloudEventsVersion == "" { + h.Set("CE-CloudEventsVersion", V01CloudEventsVersion) + } + if !ec.EventTime.IsZero() { + h.Set("CE-EventTime", ec.EventTime.Format(time.RFC3339Nano)) + } + if ec.EventTypeVersion != "" { + h.Set("CE-EventTypeVersion", ec.EventTypeVersion) + } + if ec.SchemaURL != "" { + h.Set("CE-SchemaUrl", ec.SchemaURL) + } + if ec.ContentType != "" { + h.Set("Content-Type", ec.ContentType) + } + for k, v := range ec.Extensions { + encoded, err := json.Marshal(v) + if err != nil { + return nil, err + } + // Preserve case in v0.1, even though HTTP headers are case-insensitive. + h["CE-X-"+k] = []string{string(encoded)} + } + return h, nil +} + +// FromHeaders implements the BinaryLoader interface. +func (ec *V01EventContext) FromHeaders(in http.Header) error { + missingField := func(name string) error { + if in.Get("CE-"+name) == "" { + return fmt.Errorf("Missing field %q in %v: %q", "CE-"+name, in, in.Get("CE-"+name)) + } + return nil + } + if err := anyError( + missingField("CloudEventsVersion"), + missingField("EventID"), + missingField("EventType"), + missingField("Source")); err != nil { + return err + } + data := V01EventContext{ + CloudEventsVersion: in.Get("CE-CloudEventsVersion"), + EventID: in.Get("CE-EventID"), + EventType: in.Get("CE-EventType"), + EventTypeVersion: in.Get("CE-EventTypeVersion"), + SchemaURL: in.Get("CE-SchemaURL"), + ContentType: in.Get("Content-Type"), + Source: in.Get("CE-Source"), + Extensions: make(map[string]interface{}), + } + if timeStr := in.Get("CE-EventTime"); timeStr != "" { + var err error + if data.EventTime, err = time.Parse(time.RFC3339Nano, timeStr); err != nil { + return err + } + } + for k, v := range in { + if strings.EqualFold(k[:len("CE-X-")], "CE-X-") { + key := k[len("CE-X-"):] + var tmp interface{} + if err := json.Unmarshal([]byte(v[0]), &tmp); err == nil { + data.Extensions[key] = tmp + } else { + // If we can't unmarshal the data, treat it as a string. + data.Extensions[key] = v[0] + } + } + } + *ec = data + return nil +} + +// AsJSON implements the StructuredSender interface. +func (ec V01EventContext) AsJSON() (map[string]json.RawMessage, error) { + ret := make(map[string]json.RawMessage) + err := anyError( + encodeKey(ret, "cloudEventsVersion", ec.CloudEventsVersion), + encodeKey(ret, "eventID", ec.EventID), + encodeKey(ret, "eventTime", ec.EventTime), + encodeKey(ret, "eventType", ec.EventType), + encodeKey(ret, "eventTypeVersion", ec.EventTypeVersion), + encodeKey(ret, "schemaURL", ec.SchemaURL), + encodeKey(ret, "contentType", ec.ContentType), + encodeKey(ret, "source", ec.Source), + encodeKey(ret, "extensions", ec.Extensions)) + return ret, err +} + +// DataContentType implements the StructuredSender interface. +func (ec V01EventContext) DataContentType() string { + return ec.ContentType +} + +// FromJSON implements the StructuredLoader interface. +func (ec *V01EventContext) FromJSON(in map[string]json.RawMessage) error { + data := V01EventContext{ + CloudEventsVersion: extractKey(in, "cloudEventsVersion"), + EventID: extractKey(in, "eventID"), + EventType: extractKey(in, "eventType"), + Source: extractKey(in, "source"), + } + var err error + if timeStr := extractKey(in, "eventTime"); timeStr != "" { + if data.EventTime, err = time.Parse(time.RFC3339Nano, timeStr); err != nil { + return err + } + } + extractKeyTo(in, "eventTypeVersion", &data.EventTypeVersion) + extractKeyTo(in, "schemaURL", &data.SchemaURL) + extractKeyTo(in, "contentType", &data.ContentType) + if len(in["extensions"]) == 0 { + in["extensions"] = []byte("{}") + } + if err = json.Unmarshal(in["extensions"], &data.Extensions); err != nil { + return err + } + *ec = data + return nil +} + +func encodeKey(out map[string]json.RawMessage, key string, value interface{}) (err error) { + if s, ok := value.(string); ok && s == "" { + // Skip empty strings. + return nil + } + out[key], err = json.Marshal(value) + return +} + +func extractKey(in map[string]json.RawMessage, key string) (s string) { + extractKeyTo(in, key, &s) + return +} + +func extractKeyTo(in map[string]json.RawMessage, key string, out *string) error { + tmp := in[key] + delete(in, key) + return json.Unmarshal(tmp, out) +} diff --git a/vendor/github.com/knative/pkg/cloudevents/event_v02.go b/vendor/github.com/knative/pkg/cloudevents/event_v02.go new file mode 100644 index 0000000000..dc64767cc5 --- /dev/null +++ b/vendor/github.com/knative/pkg/cloudevents/event_v02.go @@ -0,0 +1,261 @@ +/* +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 cloudevents + +import ( + "encoding/json" + "fmt" + "net/http" + "strings" + "time" +) + +const ( + // V02CloudEventsVersion is the version of the CloudEvents spec targeted + // by this library. + V02CloudEventsVersion = "0.2" + + // required attributes + fieldSpecVersion = "specversion" + fieldID = "id" + fieldType = "type" + fieldSource = "source" + fieldTime = "time" + fieldSchemaURL = "schemaurl" + fieldContentType = "contenttype" + headerContentType = "Content-Type" +) + +// V02EventContext represents the non-data attributes of a CloudEvents v0.2 +// event. +type V02EventContext struct { + // The version of the CloudEvents specification used by the event. + SpecVersion string `json:"specversion"` + // The type of the occurrence which has happened. + Type string `json:"type"` + // A URI describing the event producer. + Source string `json:"source"` + // ID of the event; must be non-empty and unique within the scope of the producer. + ID string `json:"id"` + // Timestamp when the event happened. + Time time.Time `json:"time,omitempty"` + // A link to the schema that the `data` attribute adheres to. + SchemaURL string `json:"schemaurl,omitempty"` + // A MIME (RFC2046) string describing the media type of `data`. + // TODO: Should an empty string assume `application/json`, `application/octet-stream`, or auto-detect the content? + ContentType string `json:"contenttype,omitempty"` + // Additional extension metadata beyond the base spec. + Extensions map[string]interface{} `json:"-,omitempty"` +} + +// AsV01 implements the ContextTranslator interface. +func (ec V02EventContext) AsV01() V01EventContext { + ret := V01EventContext{ + CloudEventsVersion: V01CloudEventsVersion, + EventID: ec.ID, + EventTime: ec.Time, + EventType: ec.Type, + SchemaURL: ec.SchemaURL, + ContentType: ec.ContentType, + Source: ec.Source, + Extensions: make(map[string]interface{}), + } + for k, v := range ec.Extensions { + // eventTypeVersion was retired in v0.2 + if strings.EqualFold(k, "eventTypeVersion") { + etv, ok := v.(string) + if ok { + ret.EventTypeVersion = etv + } + continue + } + ret.Extensions[k] = v + } + return ret +} + +// AsV02 implements the ContextTranslator interface. +func (ec V02EventContext) AsV02() V02EventContext { + return ec +} + +// AsHeaders implements the BinarySender interface. +func (ec V02EventContext) AsHeaders() (http.Header, error) { + h := http.Header{} + h.Set("CE-"+fieldSpecVersion, ec.SpecVersion) + h.Set("CE-"+fieldType, ec.Type) + h.Set("CE-"+fieldSource, ec.Source) + h.Set("CE-"+fieldID, ec.ID) + if ec.SpecVersion == "" { + h.Set("CE-"+fieldSpecVersion, V02CloudEventsVersion) + } + if !ec.Time.IsZero() { + h.Set("CE-"+fieldTime, ec.Time.Format(time.RFC3339Nano)) + } + if ec.SchemaURL != "" { + h.Set("CE-"+fieldSchemaURL, ec.SchemaURL) + } + if ec.ContentType != "" { + h.Set(headerContentType, ec.ContentType) + } + for k, v := range ec.Extensions { + // Per spec, map-valued extensions are converted to a list of headers as: + // CE-attrib-key + if mapVal, ok := v.(map[string]interface{}); ok { + for subkey, subval := range mapVal { + encoded, err := json.Marshal(subval) + if err != nil { + return nil, err + } + h.Set("CE-"+k+"-"+subkey, string(encoded)) + } + continue + } + encoded, err := json.Marshal(v) + if err != nil { + return nil, err + } + h.Set("CE-"+k, string(encoded)) + } + + return h, nil +} + +// FromHeaders implements the BinaryLoader interface. +func (ec *V02EventContext) FromHeaders(in http.Header) error { + missingField := func(name string) error { + if in.Get("CE-"+name) == "" { + return fmt.Errorf("Missing field %q in %v: %q", "CE-"+name, in, in.Get("CE-"+name)) + } + return nil + } + err := anyError( + missingField(fieldSpecVersion), + missingField(fieldID), + missingField(fieldType), + missingField(fieldSource), + ) + if err != nil { + return err + } + data := V02EventContext{ + ContentType: in.Get(headerContentType), + Extensions: make(map[string]interface{}), + } + // Extensions and top-level fields are mixed under "CE-" headers. + // Extract them all here rather than trying to clear fields in headers. + for k, v := range in { + if strings.EqualFold(k[:len("CE-")], "CE-") { + key, value := strings.ToLower(string(k[len("CE-"):])), v[0] + switch key { + case fieldSpecVersion: + data.SpecVersion = value + case fieldType: + data.Type = value + case fieldSource: + data.Source = value + case fieldID: + data.ID = value + case fieldSchemaURL: + data.SchemaURL = value + case fieldTime: + if data.Time, err = time.Parse(time.RFC3339Nano, value); err != nil { + return err + } + default: + var tmp interface{} + if err = json.Unmarshal([]byte(value), &tmp); err != nil { + tmp = value + } + // Per spec, map-valued extensions are converted to a list of headers as: + // CE-attrib-key. This is where things get a bit crazy... see + // https://github.com/cloudevents/spec/issues/367 for additional notes. + if strings.Contains(key, "-") { + items := strings.SplitN(key, "-", 2) + key, subkey := items[0], items[1] + if _, ok := data.Extensions[key]; !ok { + data.Extensions[key] = make(map[string]interface{}) + } + if submap, ok := data.Extensions[key].(map[string]interface{}); ok { + submap[subkey] = tmp + } + } else { + data.Extensions[key] = tmp + } + } + } + } + *ec = data + return nil +} + +// AsJSON implementsn the StructuredSender interface. +func (ec V02EventContext) AsJSON() (map[string]json.RawMessage, error) { + ret := make(map[string]json.RawMessage) + err := anyError( + encodeKey(ret, fieldSpecVersion, ec.SpecVersion), + encodeKey(ret, fieldType, ec.Type), + encodeKey(ret, fieldSource, ec.Source), + encodeKey(ret, fieldID, ec.ID), + encodeKey(ret, fieldTime, ec.Time), + encodeKey(ret, fieldSchemaURL, ec.SchemaURL), + encodeKey(ret, fieldContentType, ec.ContentType), + ) + if err != nil { + return nil, err + } + for k, v := range ec.Extensions { + if err = encodeKey(ret, k, v); err != nil { + return nil, err + } + } + return ret, nil +} + +// DataContentType implements the StructuredSender interface. +func (ec V02EventContext) DataContentType() string { + return ec.ContentType +} + +// FromJSON implements the StructuredLoader interface. +func (ec *V02EventContext) FromJSON(in map[string]json.RawMessage) error { + data := V02EventContext{ + SpecVersion: extractKey(in, fieldSpecVersion), + Type: extractKey(in, fieldType), + Source: extractKey(in, fieldSource), + ID: extractKey(in, fieldID), + Extensions: make(map[string]interface{}), + } + var err error + if timeStr := extractKey(in, fieldTime); timeStr != "" { + if data.Time, err = time.Parse(time.RFC3339Nano, timeStr); err != nil { + return err + } + } + extractKeyTo(in, fieldSchemaURL, &data.SchemaURL) + extractKeyTo(in, fieldContentType, &data.ContentType) + // Extract the remaining items from in by converting to JSON and then + // unpacking into Extensions. This avoids having to do funny type + // checking/testing in the loop over values. + extensionsJSON, err := json.Marshal(in) + if err != nil { + return err + } + err = json.Unmarshal(extensionsJSON, &data.Extensions) + *ec = data + return err +} diff --git a/vendor/github.com/knative/pkg/cloudevents/handler.go b/vendor/github.com/knative/pkg/cloudevents/handler.go new file mode 100644 index 0000000000..3b8575a1cf --- /dev/null +++ b/vendor/github.com/knative/pkg/cloudevents/handler.go @@ -0,0 +1,401 @@ +/* +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 cloudevents + +import ( + "context" + "encoding/json" + "errors" + "fmt" + "io" + "log" + "net/http" + "reflect" + "strings" + + "github.com/davecgh/go-spew/spew" + "github.com/google/uuid" +) + +type handler struct { + numIn int + fnValue reflect.Value + dataType reflect.Type +} + +type failedHandler struct { + err error +} + +type errAndHandler interface { + http.Handler + error +} + +const ( + inParamUsage = "Expected a function taking either no parameters, a context.Context, or (context.Context, any)" + outParamUsage = "Expected a function returning either nothing, an error, (any, error), or (any, SendContext, error)" +) + +var ( + // FYI: Getting the type of an interface is a bit hard in Go because of nil is special: + // 1. Structs & pointers have concrete types, whereas interfaces are actually tuples of + // [implementation vtable, pointer]. + // 2. Literals (such as nil) can be cast to any relevant type. + // Because TypeOf takes an interface{}, a nil interface reference would cast lossily when + // it leaves this stack frame. The workaround is to pass a pointer to an interface and then + // get the type of its reference. + // For example, see: https://play.golang.org/p/_dxLvdkvqvg + contextType = reflect.TypeOf((*context.Context)(nil)).Elem() + errorType = reflect.TypeOf((*error)(nil)).Elem() + sendContextType = reflect.TypeOf((*SendContext)(nil)).Elem() +) + +// Verifies that the inputs to a function have a valid signature; panics otherwise. +// Valid input signatures: +// (), (context.Context), (context.Context, any) +func validateInParamSignature(fnType reflect.Type) error { + switch fnType.NumIn() { + case 2: + fallthrough + case 1: + if !fnType.In(0).ConvertibleTo(contextType) { + return fmt.Errorf("%s; cannot convert parameter 0 from %s to context.Context", inParamUsage, fnType.In(0)) + } + fallthrough + case 0: + return nil + default: + return fmt.Errorf("%s; function has too many parameters (%d)", inParamUsage, fnType.NumIn()) + } +} + +// Verifies that the outputs of a function have a valid signature; panics otherwise. +// Valid output signatures: +// (), (error), (any, error) +func validateOutParamSignature(fnType reflect.Type) error { + switch fnType.NumOut() { + case 3: + contextType := fnType.Out(1) + if !contextType.ConvertibleTo(sendContextType) { + return fmt.Errorf("%s; cannot convert return type 1 from %s to SendContext", outParamUsage, contextType) + } + fallthrough + case 2: + fallthrough + case 1: + paramNo := fnType.NumOut() - 1 + paramType := fnType.Out(paramNo) + if !paramType.ConvertibleTo(errorType) { + return fmt.Errorf("%s; cannot convert return type %d from %s to error", outParamUsage, paramNo, paramType) + } + fallthrough + case 0: + return nil + default: + return fmt.Errorf("%s; function has too many return types (%d)", outParamUsage, fnType.NumOut()) + } +} + +// Verifies that a function has the right number of in and out params and that they are +// of allowed types. If successful, returns the expected in-param type, otherwise panics. +func validateFunction(fnType reflect.Type) errAndHandler { + if fnType.Kind() != reflect.Func { + return &failedHandler{err: errors.New("must pass a function to handle events")} + } + err := anyError( + validateInParamSignature(fnType), + validateOutParamSignature(fnType)) + if err != nil { + return &failedHandler{err: err} + } + return nil +} + +// Alocates a new instance of type t and returns: +// asPtr is of type t if t is a pointer type and of type &t otherwise (used for unmarshalling) +// asValue is a Value of type t pointing to the same data as asPtr +func allocate(t reflect.Type) (asPtr interface{}, asValue reflect.Value) { + if t == nil { + return nil, reflect.Value{} + } + if t.Kind() == reflect.Ptr { + reflectPtr := reflect.New(t.Elem()) + asPtr = reflectPtr.Interface() + asValue = reflectPtr + } else { + reflectPtr := reflect.New(t) + asPtr = reflectPtr.Interface() + asValue = reflectPtr.Elem() + } + return +} + +func unwrapReturnValues(res []reflect.Value) (interface{}, SendContext, error) { + switch len(res) { + case 0: + return nil, nil, nil + case 1: + if res[0].IsNil() { + return nil, nil, nil + } + // Should be a safe cast due to assertEventHandler() + return nil, nil, res[0].Interface().(error) + case 2: + if res[1].IsNil() { + return res[0].Interface(), nil, nil + } + // Should be a safe cast due to assertEventHandler() + return nil, nil, res[1].Interface().(error) + case 3: + if res[2].IsNil() { + ec := res[1].Interface().(SendContext) + return res[0].Interface(), ec, nil + } + return nil, nil, res[2].Interface().(error) + default: + // Should never happen due to assertEventHandler() + panic("Cannot unmarshal more than 3 return values") + } +} + +// Accepts the results from a handler functions and translates them to an HTTP response +func respondHTTP(outparams []reflect.Value, fn reflect.Value, w http.ResponseWriter) { + res, ec, err := unwrapReturnValues(outparams) + + if err != nil { + log.Print("Failed to handle event: ", err) + w.WriteHeader(http.StatusInternalServerError) + w.Write([]byte(`Internal server error`)) + return + } + if ec == nil { + eventType := strings.Replace(fn.Type().PkgPath(), "/", ".", -1) + if eventType != "" { + eventType += "." + } + eventType += fn.Type().Name() + if eventType == "" { + eventType = "dev.knative.pkg.cloudevents.unknown" + } + ec = &V01EventContext{ + EventID: uuid.New().String(), + EventType: eventType, + Source: "unknown", // TODO: anything useful here, maybe incoming Host header? + } + } + + if res != nil { + json, err := json.Marshal(res) + if err != nil { + log.Printf("Failed to marshal return value %+v: %s", res, err) + w.WriteHeader(http.StatusInternalServerError) + w.Write([]byte(`Internal server error`)) + return + } + headers, err := ec.AsHeaders() + if err != nil { + log.Printf("Failed to marshal event context %+v: %s", res, err) + w.WriteHeader(http.StatusInternalServerError) + w.Write([]byte("Internal server error")) + return + } + for k, v := range headers { + w.Header()[k] = v + } + + w.Write(json) + return + } + + w.WriteHeader(http.StatusNoContent) +} + +// Handler creates an EventHandler that implements http.Handler +// If the fn parameter is not a valid type, will produce an http.Handler that also conforms +// to error and will respond to all HTTP requests with that error. Valid types of fn are: +// +// * func() +// * func() error +// * func() (anything, error) +// * func() (anything, EventContext, error) +// * func(context.Context) +// * func(context.Context) error +// * func(context.Context) (anything, error) +// * func(context.Context) (anything, EventContext, error) +// * func(context.Context, anything) +// * func(context.Context, anything) error +// * func(context.Context, anything) (anything, error) +// * func(context.Context, anything) (anything, EventContext, error) +// +// CloudEvent contexts are available from the context.Context parameter +// CloudEvent data will be deserialized into the "anything" parameter. +// The library supports native decoding with both XML and JSON encoding. +// To accept another advanced type, pass an io.Reader as the input parameter. +// +// HTTP responses are generated based on the return value of fn: +// * any error return value will cause a StatusInternalServerError response +// * a function with no return type or a function returning nil will cause a StatusNoContent response +// * a function that returns a value will cause a StatusOK and render the response as JSON, +// with headers from an EventContext, if appropriate +func Handler(fn interface{}) http.Handler { + fnType := reflect.TypeOf(fn) + err := validateFunction(fnType) + if err != nil { + return err + } + var dataType reflect.Type + if fnType.NumIn() == 2 { + dataType = fnType.In(1) + } + + return &handler{ + numIn: fnType.NumIn(), + dataType: dataType, + fnValue: reflect.ValueOf(fn), + } +} + +// ServeHTTP implements http.Handler +func (h *handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { + args := make([]reflect.Value, 0, 2) + + if h.numIn > 0 { + dataPtr, dataArg := allocate(h.dataType) + eventContext, err := FromRequest(dataPtr, r) + if err != nil { + log.Printf("Failed to handle request %s; error %s", spew.Sdump(r), err) + w.WriteHeader(http.StatusBadRequest) + w.Write([]byte(`Invalid request`)) + return + } + + ctx := r.Context() + ctx = context.WithValue(ctx, contextKey, eventContext) + args = append(args, reflect.ValueOf(ctx)) + + if h.numIn == 2 { + args = append(args, dataArg) + } + } + + res := h.fnValue.Call(args) + respondHTTP(res, h.fnValue, w) +} + +func (h failedHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { + log.Print("Failed to handle event: ", h.Error()) + w.WriteHeader(http.StatusNotImplemented) + w.Write([]byte(`Internal server error`)) +} + +func (h failedHandler) Error() string { + return h.err.Error() +} + +// Mux allows developers to handle logically related groups of +// functionality multiplexed based on the event type. +// TODO: Consider dropping Mux or figure out how to handle non-JSON encoding. +type Mux map[string]*handler + +// NewMux creates a new Mux +func NewMux() Mux { + return make(map[string]*handler) +} + +// Handle adds a new handler for a specific event type +// If the fn parameter is not a valid type, the endpoint will respond to all HTTP requests +// with that error. Valid types of fn are: +// +// * func() +// * func() error +// * func() (anything, error) +// * func(context.Context) +// * func(context.Context) error +// * func(context.Context) (anything, error) +// * func(context.Context, anything) +// * func(context.Context, anything) error +// * func(context.Context, anything) (anything, error) +// +// CloudEvent contexts are available from the context.Context parameter +// CloudEvent data will be deserialized into the "anything" parameter. +// The library supports native decoding with both XML and JSON encoding. +// To accept another advanced type, pass an io.Reader as the input parameter. +// +// HTTP responses are generated based on the return value of fn: +// * any error return value will cause a StatusInternalServerError response +// * a function with no return type or a function returning nil will cause a StatusNoContent response +// * a function that returns a value will cause a StatusOK and render the response as JSON +func (m Mux) Handle(eventType string, fn interface{}) error { + fnType := reflect.TypeOf(fn) + err := validateFunction(fnType) + if err != nil { + return err + } + var dataType reflect.Type + if fnType.NumIn() == 2 { + dataType = fnType.In(1) + } + m[eventType] = &handler{ + numIn: fnType.NumIn(), + dataType: dataType, + fnValue: reflect.ValueOf(fn), + } + return nil +} + +// ServeHTTP implements http.Handler +func (m Mux) ServeHTTP(w http.ResponseWriter, r *http.Request) { + var rawData io.Reader + eventContext, err := FromRequest(&rawData, r) + if err != nil { + log.Printf("Failed to handle request: %s %s", err, spew.Sdump(r)) + w.WriteHeader(http.StatusBadRequest) + w.Write([]byte(`Invalid request`)) + return + } + + c := eventContext.AsV01() + + h := m[c.EventType] + if h == nil { + log.Print("Cloud not find handler for event type", c.EventType) + w.WriteHeader(http.StatusInternalServerError) + w.Write([]byte(fmt.Sprintf("Event type %q is not supported", c.EventType))) + return + } + + args := make([]reflect.Value, 0, 2) + if h.numIn > 0 { + ctx := r.Context() + ctx = context.WithValue(ctx, contextKey, eventContext) + args = append(args, reflect.ValueOf(ctx)) + } + if h.numIn == 2 { + dataPtr, dataArg := allocate(h.dataType) + if err := unmarshalEventData(c.ContentType, rawData, dataPtr); err != nil { + log.Print("Failed to parse event data", err) + w.WriteHeader(http.StatusBadRequest) + w.Write([]byte(`Invalid request`)) + return + } + args = append(args, dataArg) + } + + res := h.fnValue.Call(args) + respondHTTP(res, h.fnValue, w) +} diff --git a/vendor/github.com/knative/pkg/code-of-conduct.md b/vendor/github.com/knative/pkg/code-of-conduct.md new file mode 100644 index 0000000000..5f04b3187c --- /dev/null +++ b/vendor/github.com/knative/pkg/code-of-conduct.md @@ -0,0 +1,75 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as +contributors and maintainers pledge to making participation in our project and +our community a harassment-free experience for everyone, regardless of age, body +size, disability, ethnicity, gender identity and expression, level of +experience, education, socio-economic status, nationality, personal appearance, +race, religion, or sexual identity and orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment +include: + +- Using welcoming and inclusive language +- Being respectful of differing viewpoints and experiences +- Gracefully accepting constructive criticism +- Focusing on what is best for the community +- Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +- The use of sexualized language or imagery and unwelcome sexual attention or + advances +- Trolling, insulting/derogatory comments, and personal or political attacks +- Public or private harassment +- Publishing others' private information, such as a physical or electronic + address, without explicit permission +- Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable +behavior and are expected to take appropriate and fair corrective action in +response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or reject +comments, commits, code, wiki edits, issues, and other contributions that are +not aligned to this Code of Conduct, or to ban temporarily or permanently any +contributor for other behaviors that they deem inappropriate, threatening, +offensive, or harmful. + +## Scope + +This Code of Conduct applies both within project spaces and in public spaces +when an individual is representing the project or its community. Examples of +representing a project or community include using an official project e-mail +address, posting via an official social media account, or acting as an appointed +representative at an online or offline event. Representation of a project may be +further defined and clarified by project maintainers. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported by contacting the project team at +knative-code-of-conduct@googlegroups.com. All complaints will be reviewed and +investigated and will result in a response that is deemed necessary and +appropriate to the circumstances. The project team is obligated to maintain +confidentiality with regard to the reporter of an incident. Further details of +specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good +faith may face temporary or permanent repercussions as determined by other +members of the project's leadership. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], +version 1.4, available at +https://www.contributor-covenant.org/version/1/4/code-of-conduct.html + +[homepage]: https://www.contributor-covenant.org diff --git a/vendor/github.com/knative/pkg/codegen/cmd/injection-gen/args/args.go b/vendor/github.com/knative/pkg/codegen/cmd/injection-gen/args/args.go new file mode 100644 index 0000000000..a1a1a5a9ec --- /dev/null +++ b/vendor/github.com/knative/pkg/codegen/cmd/injection-gen/args/args.go @@ -0,0 +1,61 @@ +/* +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 args + +import ( + "fmt" + + "github.com/spf13/pflag" + "k8s.io/gengo/args" +) + +// CustomArgs is used by the gengo framework to pass args specific to this generator. +type CustomArgs struct { + VersionedClientSetPackage string + ExternalVersionsInformersPackage string +} + +// NewDefaults returns default arguments for the generator. +func NewDefaults() (*args.GeneratorArgs, *CustomArgs) { + genericArgs := args.Default().WithoutDefaultFlagParsing() + customArgs := &CustomArgs{} + genericArgs.CustomArgs = customArgs + return genericArgs, customArgs +} + +// AddFlags add the generator flags to the flag set. +func (ca *CustomArgs) AddFlags(fs *pflag.FlagSet) { + fs.StringVar(&ca.VersionedClientSetPackage, "versioned-clientset-package", ca.VersionedClientSetPackage, "the full package name for the versioned injection clientset to use") + fs.StringVar(&ca.ExternalVersionsInformersPackage, "external-versions-informers-package", ca.ExternalVersionsInformersPackage, "the full package name for the external versions injection informer to use") +} + +// Validate checks the given arguments. +func Validate(genericArgs *args.GeneratorArgs) error { + customArgs := genericArgs.CustomArgs.(*CustomArgs) + + if len(genericArgs.OutputPackagePath) == 0 { + return fmt.Errorf("output package cannot be empty") + } + if len(customArgs.VersionedClientSetPackage) == 0 { + return fmt.Errorf("versioned clientset package cannot be empty") + } + if len(customArgs.ExternalVersionsInformersPackage) == 0 { + return fmt.Errorf("external versions informers package cannot be empty") + } + + return nil +} diff --git a/vendor/github.com/knative/pkg/codegen/cmd/injection-gen/generators/client.go b/vendor/github.com/knative/pkg/codegen/cmd/injection-gen/generators/client.go new file mode 100644 index 0000000000..c2f4914fdf --- /dev/null +++ b/vendor/github.com/knative/pkg/codegen/cmd/injection-gen/generators/client.go @@ -0,0 +1,101 @@ +/* +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 generators + +import ( + "io" + "k8s.io/gengo/generator" + "k8s.io/gengo/namer" + "k8s.io/gengo/types" + "k8s.io/klog" +) + +// clientGenerator produces a file of listers for a given GroupVersion and +// type. +type clientGenerator struct { + generator.DefaultGen + outputPackage string + imports namer.ImportTracker + clientSetPackage string + filtered bool +} + +var _ generator.Generator = (*clientGenerator)(nil) + +func (g *clientGenerator) Filter(c *generator.Context, t *types.Type) bool { + // We generate a single client, so return true once. + if !g.filtered { + g.filtered = true + return true + } + return false +} + +func (g *clientGenerator) Namers(c *generator.Context) namer.NameSystems { + return namer.NameSystems{ + "raw": namer.NewRawNamer(g.outputPackage, g.imports), + } +} + +func (g *clientGenerator) Imports(c *generator.Context) (imports []string) { + imports = append(imports, g.imports.ImportLines()...) + return +} + +func (g *clientGenerator) GenerateType(c *generator.Context, t *types.Type, w io.Writer) error { + sw := generator.NewSnippetWriter(w, c, "{{", "}}") + + klog.V(5).Infof("processing type %v", t) + + m := map[string]interface{}{ + "clientSetNewForConfigOrDie": c.Universe.Function(types.Name{Package: g.clientSetPackage, Name: "NewForConfigOrDie"}), + "clientSetInterface": c.Universe.Type(types.Name{Package: g.clientSetPackage, Name: "Interface"}), + "injectionRegisterClient": c.Universe.Function(types.Name{Package: "github.com/knative/pkg/injection", Name: "Default.RegisterClient"}), + "restConfig": c.Universe.Type(types.Name{Package: "k8s.io/client-go/rest", Name: "Config"}), + "loggingFromContext": c.Universe.Function(types.Name{ + Package: "github.com/knative/pkg/logging", + Name: "FromContext", + }), + } + + sw.Do(injectionClient, m) + + return sw.Error() +} + +var injectionClient = ` +func init() { + {{.injectionRegisterClient|raw}}(withClient) +} + +// Key is used as the key for associating information with a context.Context. +type Key struct{} + +func withClient(ctx context.Context, cfg *{{.restConfig|raw}}) context.Context { + return context.WithValue(ctx, Key{}, {{.clientSetNewForConfigOrDie|raw}}(cfg)) +} + +// Get extracts the {{.clientSetInterface|raw}} client from the context. +func Get(ctx context.Context) {{.clientSetInterface|raw}} { + untyped := ctx.Value(Key{}) + if untyped == nil { + {{.loggingFromContext|raw}}(ctx).Fatalf( + "Unable to fetch %T from context.", ({{.clientSetInterface|raw}})(nil)) + } + return untyped.({{.clientSetInterface|raw}}) +} +` diff --git a/vendor/github.com/knative/pkg/codegen/cmd/injection-gen/generators/factory.go b/vendor/github.com/knative/pkg/codegen/cmd/injection-gen/generators/factory.go new file mode 100644 index 0000000000..5256334062 --- /dev/null +++ b/vendor/github.com/knative/pkg/codegen/cmd/injection-gen/generators/factory.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 generators + +import ( + "io" + "k8s.io/gengo/generator" + "k8s.io/gengo/namer" + "k8s.io/gengo/types" + + "k8s.io/klog" +) + +// factoryTestGenerator produces a file of factory injection of a given type. +type factoryGenerator struct { + generator.DefaultGen + outputPackage string + imports namer.ImportTracker + cachingClientSetPackage string + sharedInformerFactoryPackage string + filtered bool +} + +var _ generator.Generator = (*factoryGenerator)(nil) + +func (g *factoryGenerator) Filter(c *generator.Context, t *types.Type) bool { + // We generate a single factory, so return true once. + if !g.filtered { + g.filtered = true + return true + } + return false +} + +func (g *factoryGenerator) Namers(c *generator.Context) namer.NameSystems { + return namer.NameSystems{ + "raw": namer.NewRawNamer(g.outputPackage, g.imports), + } +} + +func (g *factoryGenerator) Imports(c *generator.Context) (imports []string) { + imports = append(imports, g.imports.ImportLines()...) + return +} + +func (g *factoryGenerator) GenerateType(c *generator.Context, t *types.Type, w io.Writer) error { + sw := generator.NewSnippetWriter(w, c, "{{", "}}") + + klog.V(5).Infof("processing type %v", t) + + m := map[string]interface{}{ + "cachingClientGet": c.Universe.Type(types.Name{Package: g.cachingClientSetPackage, Name: "Get"}), + "informersNewSharedInformerFactory": c.Universe.Function(types.Name{Package: g.sharedInformerFactoryPackage, Name: "NewSharedInformerFactory"}), + "informersSharedInformerFactory": c.Universe.Function(types.Name{Package: g.sharedInformerFactoryPackage, Name: "SharedInformerFactory"}), + "injectionRegisterInformerFactory": c.Universe.Type(types.Name{Package: "github.com/knative/pkg/injection", Name: "Default.RegisterInformerFactory"}), + "controllerGetResyncPeriod": c.Universe.Type(types.Name{Package: "github.com/knative/pkg/controller", Name: "GetResyncPeriod"}), + "loggingFromContext": c.Universe.Function(types.Name{ + Package: "github.com/knative/pkg/logging", + Name: "FromContext", + }), + } + + sw.Do(injectionFactory, m) + + return sw.Error() +} + +var injectionFactory = ` +func init() { + {{.injectionRegisterInformerFactory|raw}}(withInformerFactory) +} + +// Key is used as the key for associating information with a context.Context. +type Key struct{} + +func withInformerFactory(ctx context.Context) context.Context { + c := {{.cachingClientGet|raw}}(ctx) + return context.WithValue(ctx, Key{}, + {{.informersNewSharedInformerFactory|raw}}(c, {{.controllerGetResyncPeriod|raw}}(ctx))) +} + +// Get extracts the InformerFactory from the context. +func Get(ctx context.Context) {{.informersSharedInformerFactory|raw}} { + untyped := ctx.Value(Key{}) + if untyped == nil { + {{.loggingFromContext|raw}}(ctx).Fatalf( + "Unable to fetch %T from context.", ({{.informersSharedInformerFactory|raw}})(nil)) + } + return untyped.({{.informersSharedInformerFactory|raw}}) +} +` diff --git a/vendor/github.com/knative/pkg/codegen/cmd/injection-gen/generators/fakeclient.go b/vendor/github.com/knative/pkg/codegen/cmd/injection-gen/generators/fakeclient.go new file mode 100644 index 0000000000..5ed5392551 --- /dev/null +++ b/vendor/github.com/knative/pkg/codegen/cmd/injection-gen/generators/fakeclient.go @@ -0,0 +1,108 @@ +/* +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 generators + +import ( + "io" + "k8s.io/gengo/generator" + "k8s.io/gengo/namer" + "k8s.io/gengo/types" + "k8s.io/klog" +) + +// fakeClientGenerator produces a file of listers for a given GroupVersion and +// type. +type fakeClientGenerator struct { + generator.DefaultGen + outputPackage string + imports namer.ImportTracker + filtered bool + + fakeClientPkg string + clientInjectionPkg string +} + +var _ generator.Generator = (*fakeClientGenerator)(nil) + +func (g *fakeClientGenerator) Filter(c *generator.Context, t *types.Type) bool { + // We generate a single client, so return true once. + if !g.filtered { + g.filtered = true + return true + } + return false +} + +func (g *fakeClientGenerator) Namers(c *generator.Context) namer.NameSystems { + return namer.NameSystems{ + "raw": namer.NewRawNamer(g.outputPackage, g.imports), + } +} + +func (g *fakeClientGenerator) Imports(c *generator.Context) (imports []string) { + imports = append(imports, g.imports.ImportLines()...) + return +} + +func (g *fakeClientGenerator) GenerateType(c *generator.Context, t *types.Type, w io.Writer) error { + sw := generator.NewSnippetWriter(w, c, "{{", "}}") + + klog.V(5).Infof("processing type %v", t) + + m := map[string]interface{}{ + "clientKey": c.Universe.Type(types.Name{Package: g.clientInjectionPkg, Name: "Key"}), + "fakeClient": c.Universe.Type(types.Name{Package: g.fakeClientPkg, Name: "Clientset"}), + "injectionRegisterClient": c.Universe.Function(types.Name{ + Package: "github.com/knative/pkg/injection", + Name: "Fake.RegisterClient", + }), + "loggingFromContext": c.Universe.Function(types.Name{ + Package: "github.com/knative/pkg/logging", + Name: "FromContext", + }), + } + + sw.Do(injectionFakeClient, m) + + return sw.Error() +} + +var injectionFakeClient = ` +func init() { + {{.injectionRegisterClient|raw}}(withClient) +} + +func withClient(ctx context.Context, cfg *rest.Config) context.Context { + ctx, _ = With(ctx) + return ctx +} + +func With(ctx context.Context, objects ...runtime.Object) (context.Context, *{{.fakeClient|raw}}) { + cs := fake.NewSimpleClientset(objects...) + return context.WithValue(ctx, {{.clientKey|raw}}{}, cs), cs +} + +// Get extracts the Kubernetes client from the context. +func Get(ctx context.Context) *{{.fakeClient|raw}} { + untyped := ctx.Value({{.clientKey|raw}}{}) + if untyped == nil { + {{.loggingFromContext|raw}}(ctx).Fatalf( + "Unable to fetch %T from context.", (*{{.fakeClient|raw}})(nil)) + } + return untyped.(*fake.Clientset) +} +` diff --git a/vendor/github.com/knative/pkg/codegen/cmd/injection-gen/generators/fakefactory.go b/vendor/github.com/knative/pkg/codegen/cmd/injection-gen/generators/fakefactory.go new file mode 100644 index 0000000000..5b131dae34 --- /dev/null +++ b/vendor/github.com/knative/pkg/codegen/cmd/injection-gen/generators/fakefactory.go @@ -0,0 +1,96 @@ +/* +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 generators + +import ( + "io" + "k8s.io/gengo/generator" + "k8s.io/gengo/namer" + "k8s.io/gengo/types" + "k8s.io/klog" +) + +// fakeFactoryGenerator produces a file of listers for a given GroupVersion and +// type. +type fakeFactoryGenerator struct { + generator.DefaultGen + outputPackage string + imports namer.ImportTracker + filtered bool + + factoryInjectionPkg string + fakeClientInjectionPkg string + sharedInformerFactoryPackage string +} + +var _ generator.Generator = (*fakeFactoryGenerator)(nil) + +func (g *fakeFactoryGenerator) Filter(c *generator.Context, t *types.Type) bool { + // We generate a single factory, so return true once. + if !g.filtered { + g.filtered = true + return true + } + return false +} + +func (g *fakeFactoryGenerator) Namers(c *generator.Context) namer.NameSystems { + return namer.NameSystems{ + "raw": namer.NewRawNamer(g.outputPackage, g.imports), + } +} + +func (g *fakeFactoryGenerator) Imports(c *generator.Context) (imports []string) { + imports = append(imports, g.imports.ImportLines()...) + return +} + +func (g *fakeFactoryGenerator) GenerateType(c *generator.Context, t *types.Type, w io.Writer) error { + sw := generator.NewSnippetWriter(w, c, "{{", "}}") + + klog.V(5).Infof("processing type %v", t) + + m := map[string]interface{}{ + "factoryKey": c.Universe.Type(types.Name{Package: g.factoryInjectionPkg, Name: "Key"}), + "factoryGet": c.Universe.Function(types.Name{Package: g.factoryInjectionPkg, Name: "Get"}), + "clientGet": c.Universe.Function(types.Name{Package: g.fakeClientInjectionPkg, Name: "Get"}), + "informersNewSharedInformerFactory": c.Universe.Function(types.Name{Package: g.sharedInformerFactoryPackage, Name: "NewSharedInformerFactory"}), + "injectionRegisterInformerFactory": c.Universe.Function(types.Name{ + Package: "github.com/knative/pkg/injection", + Name: "Fake.RegisterInformerFactory", + }), + "controllerGetResyncPeriod": c.Universe.Type(types.Name{Package: "github.com/knative/pkg/controller", Name: "GetResyncPeriod"}), + } + + sw.Do(injectionFakeInformerFactory, m) + + return sw.Error() +} + +var injectionFakeInformerFactory = ` +var Get = {{.factoryGet|raw}} + +func init() { + {{.injectionRegisterInformerFactory|raw}}(withInformerFactory) +} + +func withInformerFactory(ctx context.Context) context.Context { + c := {{.clientGet|raw}}(ctx) + return context.WithValue(ctx, {{.factoryKey|raw}}{}, + {{.informersNewSharedInformerFactory|raw}}(c, {{.controllerGetResyncPeriod|raw}}(ctx))) +} +` diff --git a/vendor/github.com/knative/pkg/codegen/cmd/injection-gen/generators/fakeinformer.go b/vendor/github.com/knative/pkg/codegen/cmd/injection-gen/generators/fakeinformer.go new file mode 100644 index 0000000000..14af5a20fc --- /dev/null +++ b/vendor/github.com/knative/pkg/codegen/cmd/injection-gen/generators/fakeinformer.go @@ -0,0 +1,113 @@ +/* +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 generators + +import ( + "io" + clientgentypes "k8s.io/code-generator/cmd/client-gen/types" + "k8s.io/gengo/generator" + "k8s.io/gengo/namer" + "k8s.io/gengo/types" + "k8s.io/klog" +) + +// fakeInformerGenerator produces a file of listers for a given GroupVersion and +// type. +type fakeInformerGenerator struct { + generator.DefaultGen + outputPackage string + imports namer.ImportTracker + filtered bool + + typeToGenerate *types.Type + groupVersion clientgentypes.GroupVersion + groupGoName string + informerInjectionPkg string + fakeFactoryInjectionPkg string +} + +var _ generator.Generator = (*fakeInformerGenerator)(nil) + +func (g *fakeInformerGenerator) Filter(c *generator.Context, t *types.Type) bool { + // Only process the type for this informer generator. + return t == g.typeToGenerate +} + +func (g *fakeInformerGenerator) Namers(c *generator.Context) namer.NameSystems { + publicPluralNamer := &ExceptionNamer{ + Exceptions: map[string]string{ + // these exceptions are used to deconflict the generated code + // you can put your fully qualified package like + // to generate a name that doesn't conflict with your group. + // "k8s.io/apis/events/v1beta1.Event": "EventResource" + }, + KeyFunc: func(t *types.Type) string { + return t.Name.Package + "." + t.Name.Name + }, + Delegate: namer.NewPublicPluralNamer(map[string]string{ + "Endpoints": "Endpoints", + }), + } + + return namer.NameSystems{ + "raw": namer.NewRawNamer(g.outputPackage, g.imports), + "publicPlural": publicPluralNamer, + } +} + +func (g *fakeInformerGenerator) Imports(c *generator.Context) (imports []string) { + imports = append(imports, g.imports.ImportLines()...) + return +} + +func (g *fakeInformerGenerator) GenerateType(c *generator.Context, t *types.Type, w io.Writer) error { + sw := generator.NewSnippetWriter(w, c, "{{", "}}") + + klog.V(5).Infof("processing type %v", t) + + m := map[string]interface{}{ + "informerKey": c.Universe.Type(types.Name{Package: g.informerInjectionPkg, Name: "Key"}), + "informerGet": c.Universe.Function(types.Name{Package: g.informerInjectionPkg, Name: "Get"}), + "factoryGet": c.Universe.Function(types.Name{Package: g.fakeFactoryInjectionPkg, Name: "Get"}), + "group": namer.IC(g.groupGoName), + "type": t, + "version": namer.IC(g.groupVersion.Version.String()), + "controllerInformer": c.Universe.Type(types.Name{Package: "github.com/knative/pkg/controller", Name: "Informer"}), + "injectionRegisterInformer": c.Universe.Function(types.Name{ + Package: "github.com/knative/pkg/injection", + Name: "Fake.RegisterInformer", + }), + } + + sw.Do(injectionFakeInformer, m) + + return sw.Error() +} + +var injectionFakeInformer = ` +var Get = {{.informerGet|raw}} + +func init() { + {{.injectionRegisterInformer|raw}}(withInformer) +} + +func withInformer(ctx context.Context) (context.Context, {{.controllerInformer|raw}}) { + f := {{.factoryGet|raw}}(ctx) + inf := f.{{.group}}().{{.version}}().{{.type|publicPlural}}() + return context.WithValue(ctx, {{.informerKey|raw}}{}, inf), inf.Informer() +} +` diff --git a/vendor/github.com/knative/pkg/codegen/cmd/injection-gen/generators/informer.go b/vendor/github.com/knative/pkg/codegen/cmd/injection-gen/generators/informer.go new file mode 100644 index 0000000000..ca8d88a787 --- /dev/null +++ b/vendor/github.com/knative/pkg/codegen/cmd/injection-gen/generators/informer.go @@ -0,0 +1,122 @@ +/* +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 generators + +import ( + "io" + clientgentypes "k8s.io/code-generator/cmd/client-gen/types" + "k8s.io/gengo/generator" + "k8s.io/gengo/namer" + "k8s.io/gengo/types" + "k8s.io/klog" +) + +// injectionTestGenerator produces a file of listers for a given GroupVersion and +// type. +type injectionGenerator struct { + generator.DefaultGen + outputPackage string + groupVersion clientgentypes.GroupVersion + groupGoName string + typeToGenerate *types.Type + imports namer.ImportTracker + typedInformerPackage string + groupInformerFactoryPackage string +} + +var _ generator.Generator = (*injectionGenerator)(nil) + +func (g *injectionGenerator) Filter(c *generator.Context, t *types.Type) bool { + // Only process the type for this informer generator. + return t == g.typeToGenerate +} + +func (g *injectionGenerator) Namers(c *generator.Context) namer.NameSystems { + publicPluralNamer := &ExceptionNamer{ + Exceptions: map[string]string{ + // these exceptions are used to deconflict the generated code + // you can put your fully qualified package like + // to generate a name that doesn't conflict with your group. + // "k8s.io/apis/events/v1beta1.Event": "EventResource" + }, + KeyFunc: func(t *types.Type) string { + return t.Name.Package + "." + t.Name.Name + }, + Delegate: namer.NewPublicPluralNamer(map[string]string{ + "Endpoints": "Endpoints", + }), + } + + return namer.NameSystems{ + "raw": namer.NewRawNamer(g.outputPackage, g.imports), + "publicPlural": publicPluralNamer, + } +} + +func (g *injectionGenerator) Imports(c *generator.Context) (imports []string) { + imports = append(imports, g.imports.ImportLines()...) + return +} + +func (g *injectionGenerator) GenerateType(c *generator.Context, t *types.Type, w io.Writer) error { + sw := generator.NewSnippetWriter(w, c, "{{", "}}") + + klog.V(5).Infof("processing type %v", t) + + m := map[string]interface{}{ + "group": namer.IC(g.groupGoName), + "type": t, + "version": namer.IC(g.groupVersion.Version.String()), + "injectionRegisterInformer": c.Universe.Type(types.Name{Package: "github.com/knative/pkg/injection", Name: "Default.RegisterInformer"}), + "controllerInformer": c.Universe.Type(types.Name{Package: "github.com/knative/pkg/controller", Name: "Informer"}), + "informersTypedInformer": c.Universe.Type(types.Name{Package: g.typedInformerPackage, Name: t.Name.Name + "Informer"}), + "factoryGet": c.Universe.Type(types.Name{Package: g.groupInformerFactoryPackage, Name: "Get"}), + "loggingFromContext": c.Universe.Function(types.Name{ + Package: "github.com/knative/pkg/logging", + Name: "FromContext", + }), + } + + sw.Do(injectionInformer, m) + + return sw.Error() +} + +var injectionInformer = ` +func init() { + {{.injectionRegisterInformer|raw}}(withInformer) +} + +// Key is used for associating the Informer inside the context.Context. +type Key struct{} + +func withInformer(ctx context.Context) (context.Context, {{.controllerInformer|raw}}) { + f := {{.factoryGet|raw}}(ctx) + inf := f.{{.group}}().{{.version}}().{{.type|publicPlural}}() + return context.WithValue(ctx, Key{}, inf), inf.Informer() +} + +// Get extracts the typed informer from the context. +func Get(ctx context.Context) {{.informersTypedInformer|raw}} { + untyped := ctx.Value(Key{}) + if untyped == nil { + {{.loggingFromContext|raw}}(ctx).Fatalf( + "Unable to fetch %T from context.", ({{.informersTypedInformer|raw}})(nil)) + } + return untyped.({{.informersTypedInformer|raw}}) +} +` diff --git a/vendor/github.com/knative/pkg/codegen/cmd/injection-gen/generators/namesystems.go b/vendor/github.com/knative/pkg/codegen/cmd/injection-gen/generators/namesystems.go new file mode 100644 index 0000000000..19749529d7 --- /dev/null +++ b/vendor/github.com/knative/pkg/codegen/cmd/injection-gen/generators/namesystems.go @@ -0,0 +1,71 @@ +/* +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 generators + +import ( + "strings" + + "k8s.io/gengo/namer" + "k8s.io/gengo/types" +) + +// NameSystems returns the name system used by the generators in this package. +func NameSystems() namer.NameSystems { + pluralExceptions := map[string]string{ + "Endpoints": "Endpoints", + } + return namer.NameSystems{ + "public": namer.NewPublicNamer(0), + "private": namer.NewPrivateNamer(0), + "raw": namer.NewRawNamer("", nil), + "publicPlural": namer.NewPublicPluralNamer(pluralExceptions), + "allLowercasePlural": namer.NewAllLowercasePluralNamer(pluralExceptions), + "lowercaseSingular": &lowercaseSingularNamer{}, + } +} + +// lowercaseSingularNamer implements Namer +type lowercaseSingularNamer struct{} + +// Name returns t's name in all lowercase. +func (n *lowercaseSingularNamer) Name(t *types.Type) string { + return strings.ToLower(t.Name.Name) +} + +// DefaultNameSystem returns the default name system for ordering the types to be +// processed by the generators in this package. +func DefaultNameSystem() string { + return "public" +} + +// ExceptionNamer allows you specify exceptional cases with exact names. This allows you to have control +// for handling various conflicts, like group and resource names for instance. +type ExceptionNamer struct { + Exceptions map[string]string + KeyFunc func(*types.Type) string + + Delegate namer.Namer +} + +// Name provides the requested name for a type. +func (n *ExceptionNamer) Name(t *types.Type) string { + key := n.KeyFunc(t) + if exception, ok := n.Exceptions[key]; ok { + return exception + } + return n.Delegate.Name(t) +} diff --git a/vendor/github.com/knative/pkg/codegen/cmd/injection-gen/generators/packages.go b/vendor/github.com/knative/pkg/codegen/cmd/injection-gen/generators/packages.go new file mode 100644 index 0000000000..f8359af9b5 --- /dev/null +++ b/vendor/github.com/knative/pkg/codegen/cmd/injection-gen/generators/packages.go @@ -0,0 +1,360 @@ +/* +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 generators + +import ( + "fmt" + "path" + "path/filepath" + "strings" + + "k8s.io/code-generator/cmd/client-gen/generators/util" + clientgentypes "k8s.io/code-generator/cmd/client-gen/types" + "k8s.io/gengo/args" + "k8s.io/gengo/generator" + "k8s.io/gengo/namer" + "k8s.io/gengo/types" + "k8s.io/klog" + + informergenargs "github.com/knative/pkg/codegen/cmd/injection-gen/args" +) + +// Packages makes the client package definition. +func Packages(context *generator.Context, arguments *args.GeneratorArgs) generator.Packages { + boilerplate, err := arguments.LoadGoBoilerplate() + if err != nil { + klog.Fatalf("Failed loading boilerplate: %v", err) + } + + customArgs, ok := arguments.CustomArgs.(*informergenargs.CustomArgs) + if !ok { + klog.Fatalf("Wrong CustomArgs type: %T", arguments.CustomArgs) + } + + versionPackagePath := filepath.Join(arguments.OutputPackagePath) + + var packageList generator.Packages + typesForGroupVersion := make(map[clientgentypes.GroupVersion][]*types.Type) + + groupVersions := make(map[string]clientgentypes.GroupVersions) + groupGoNames := make(map[string]string) + for _, inputDir := range arguments.InputDirs { + p := context.Universe.Package(vendorless(inputDir)) + + objectMeta, _, err := objectMetaForPackage(p) // TODO: ignoring internal. + if err != nil { + klog.Fatal(err) + } + if objectMeta == nil { + // no types in this package had genclient + continue + } + + var gv clientgentypes.GroupVersion + var targetGroupVersions map[string]clientgentypes.GroupVersions + + parts := strings.Split(p.Path, "/") + gv.Group = clientgentypes.Group(parts[len(parts)-2]) + gv.Version = clientgentypes.Version(parts[len(parts)-1]) + targetGroupVersions = groupVersions + + groupPackageName := gv.Group.NonEmpty() + gvPackage := path.Clean(p.Path) + + // If there's a comment of the form "// +groupName=somegroup" or + // "// +groupName=somegroup.foo.bar.io", use the first field (somegroup) as the name of the + // group when generating. + if override := types.ExtractCommentTags("+", p.Comments)["groupName"]; override != nil { + gv.Group = clientgentypes.Group(override[0]) + } + + // If there's a comment of the form "// +groupGoName=SomeUniqueShortName", use that as + // the Go group identifier in CamelCase. It defaults + groupGoNames[groupPackageName] = namer.IC(strings.Split(gv.Group.NonEmpty(), ".")[0]) + if override := types.ExtractCommentTags("+", p.Comments)["groupGoName"]; override != nil { + groupGoNames[groupPackageName] = namer.IC(override[0]) + } + + var typesToGenerate []*types.Type + for _, t := range p.Types { + tags := util.MustParseClientGenTags(append(t.SecondClosestCommentLines, t.CommentLines...)) + if !tags.GenerateClient || tags.NoVerbs || !tags.HasVerb("list") || !tags.HasVerb("watch") { + continue + } + + typesToGenerate = append(typesToGenerate, t) + + if _, ok := typesForGroupVersion[gv]; !ok { + typesForGroupVersion[gv] = []*types.Type{} + } + typesForGroupVersion[gv] = append(typesForGroupVersion[gv], t) + } + if len(typesToGenerate) == 0 { + continue + } + + groupVersionsEntry, ok := targetGroupVersions[groupPackageName] + if !ok { + groupVersionsEntry = clientgentypes.GroupVersions{ + PackageName: groupPackageName, + Group: gv.Group, + } + } + groupVersionsEntry.Versions = append(groupVersionsEntry.Versions, clientgentypes.PackageVersion{Version: gv.Version, Package: gvPackage}) + targetGroupVersions[groupPackageName] = groupVersionsEntry + + orderer := namer.Orderer{Namer: namer.NewPrivateNamer(0)} + typesToGenerate = orderer.OrderTypes(typesToGenerate) + + // Generate the client and fake. + packageList = append(packageList, versionClientsPackages(versionPackagePath, groupPackageName, gv, groupGoNames[groupPackageName], boilerplate, typesToGenerate, customArgs)...) + + // Generate the informer factory and fake. + packageList = append(packageList, versionFactoryPackages(versionPackagePath, groupPackageName, gv, groupGoNames[groupPackageName], boilerplate, typesToGenerate, customArgs)...) + + // Generate the informer and fake, for each type. + packageList = append(packageList, versionInformerPackages(versionPackagePath, groupPackageName, gv, groupGoNames[groupPackageName], boilerplate, typesToGenerate, customArgs)...) + } + + return packageList +} + +// objectMetaForPackage returns the type of ObjectMeta used by package p. +func objectMetaForPackage(p *types.Package) (*types.Type, bool, error) { + generatingForPackage := false + for _, t := range p.Types { + if !util.MustParseClientGenTags(append(t.SecondClosestCommentLines, t.CommentLines...)).GenerateClient { + continue + } + generatingForPackage = true + for _, member := range t.Members { + if member.Name == "ObjectMeta" { + return member.Type, isInternal(member), nil + } + } + } + if generatingForPackage { + return nil, false, fmt.Errorf("unable to find ObjectMeta for any types in package %s", p.Path) + } + return nil, false, nil +} + +// isInternal returns true if the tags for a member do not contain a json tag +func isInternal(m types.Member) bool { + return !strings.Contains(m.Tags, "json") +} + +func vendorless(p string) string { + if pos := strings.LastIndex(p, "/vendor/"); pos != -1 { + return p[pos+len("/vendor/"):] + } + return p +} + +func typedInformerPackage(groupPkgName string, gv clientgentypes.GroupVersion, externalVersionsInformersPackage string) string { + return filepath.Join(externalVersionsInformersPackage, groupPkgName, gv.Version.String()) +} + +func versionClientsPackages(basePackage string, groupPkgName string, gv clientgentypes.GroupVersion, groupGoName string, boilerplate []byte, typesToGenerate []*types.Type, customArgs *informergenargs.CustomArgs) []generator.Package { + packagePath := filepath.Join(basePackage, "client") + + vers := make([]generator.Package, 0, 2) + + // Impl + vers = append(vers, &generator.DefaultPackage{ + PackageName: "client", + PackagePath: packagePath, + HeaderText: boilerplate, + GeneratorFunc: func(c *generator.Context) (generators []generator.Generator) { + // Impl + generators = append(generators, &clientGenerator{ + DefaultGen: generator.DefaultGen{ + OptionalName: "client", + }, + outputPackage: packagePath, + imports: generator.NewImportTracker(), + clientSetPackage: customArgs.VersionedClientSetPackage, + }) + + return generators + }, + FilterFunc: func(c *generator.Context, t *types.Type) bool { + tags := util.MustParseClientGenTags(append(t.SecondClosestCommentLines, t.CommentLines...)) + return tags.GenerateClient && tags.HasVerb("list") && tags.HasVerb("watch") + }, + }) + + // Fake + vers = append(vers, &generator.DefaultPackage{ + PackageName: "fake", + PackagePath: packagePath + "/fake", + HeaderText: boilerplate, + GeneratorFunc: func(c *generator.Context) (generators []generator.Generator) { + + // Impl + generators = append(generators, &fakeClientGenerator{ + DefaultGen: generator.DefaultGen{ + OptionalName: "fake", + }, + outputPackage: packagePath + "/fake", + imports: generator.NewImportTracker(), + fakeClientPkg: customArgs.VersionedClientSetPackage + "/fake", + clientInjectionPkg: packagePath, + }) + + return generators + }, + FilterFunc: func(c *generator.Context, t *types.Type) bool { + tags := util.MustParseClientGenTags(append(t.SecondClosestCommentLines, t.CommentLines...)) + return tags.GenerateClient && tags.HasVerb("list") && tags.HasVerb("watch") + }, + }) + + return vers +} + +func versionFactoryPackages(basePackage string, groupPkgName string, gv clientgentypes.GroupVersion, groupGoName string, boilerplate []byte, typesToGenerate []*types.Type, customArgs *informergenargs.CustomArgs) []generator.Package { + packagePath := filepath.Join(basePackage, "informers", groupPkgName, "factory") + + vers := make([]generator.Package, 0, 2) + + // Impl + vers = append(vers, &generator.DefaultPackage{ + PackageName: strings.ToLower(groupPkgName + "factory"), + PackagePath: packagePath, + HeaderText: boilerplate, + GeneratorFunc: func(c *generator.Context) (generators []generator.Generator) { + // Impl + generators = append(generators, &factoryGenerator{ + DefaultGen: generator.DefaultGen{ + OptionalName: groupPkgName + "factory", + }, + outputPackage: packagePath, + cachingClientSetPackage: fmt.Sprintf("%s/client", basePackage), + sharedInformerFactoryPackage: customArgs.ExternalVersionsInformersPackage, + imports: generator.NewImportTracker(), + }) + + return generators + }, + FilterFunc: func(c *generator.Context, t *types.Type) bool { + tags := util.MustParseClientGenTags(append(t.SecondClosestCommentLines, t.CommentLines...)) + return tags.GenerateClient && tags.HasVerb("list") && tags.HasVerb("watch") + }, + }) + + // Fake + vers = append(vers, &generator.DefaultPackage{ + PackageName: "fake", + PackagePath: packagePath + "/fake", + HeaderText: boilerplate, + GeneratorFunc: func(c *generator.Context) (generators []generator.Generator) { + + // Impl + generators = append(generators, &fakeFactoryGenerator{ + DefaultGen: generator.DefaultGen{ + OptionalName: "fake", + }, + outputPackage: packagePath + "/fake", + factoryInjectionPkg: packagePath, + fakeClientInjectionPkg: fmt.Sprintf("%s/client/fake", basePackage), + sharedInformerFactoryPackage: customArgs.ExternalVersionsInformersPackage, + imports: generator.NewImportTracker(), + }) + + return generators + }, + FilterFunc: func(c *generator.Context, t *types.Type) bool { + tags := util.MustParseClientGenTags(append(t.SecondClosestCommentLines, t.CommentLines...)) + return tags.GenerateClient && tags.HasVerb("list") && tags.HasVerb("watch") + }, + }) + + return vers +} + +func versionInformerPackages(basePackage string, groupPkgName string, gv clientgentypes.GroupVersion, groupGoName string, boilerplate []byte, typesToGenerate []*types.Type, customArgs *informergenargs.CustomArgs) []generator.Package { + factoryPackagePath := filepath.Join(basePackage, "informers", groupPkgName, "factory") + packagePath := filepath.Join(basePackage, "informers", groupPkgName, strings.ToLower(gv.Version.NonEmpty())) + + vers := make([]generator.Package, 0, len(typesToGenerate)) + + for _, t := range typesToGenerate { + // Fix for golang iterator bug. + t := t + + packagePath := packagePath + "/" + strings.ToLower(t.Name.Name) + typedInformerPackage := typedInformerPackage(groupPkgName, gv, customArgs.ExternalVersionsInformersPackage) + + // Impl + vers = append(vers, &generator.DefaultPackage{ + PackageName: strings.ToLower(t.Name.Name), + PackagePath: packagePath, + HeaderText: boilerplate, + GeneratorFunc: func(c *generator.Context) (generators []generator.Generator) { + // Impl + generators = append(generators, &injectionGenerator{ + DefaultGen: generator.DefaultGen{ + OptionalName: strings.ToLower(t.Name.Name), + }, + outputPackage: packagePath, + groupVersion: gv, + groupGoName: groupGoName, + typeToGenerate: t, + imports: generator.NewImportTracker(), + typedInformerPackage: typedInformerPackage, + groupInformerFactoryPackage: factoryPackagePath, + }) + + return generators + }, + FilterFunc: func(c *generator.Context, t *types.Type) bool { + tags := util.MustParseClientGenTags(append(t.SecondClosestCommentLines, t.CommentLines...)) + return tags.GenerateClient && tags.HasVerb("list") && tags.HasVerb("watch") + }, + }) + + // Fake + vers = append(vers, &generator.DefaultPackage{ + PackageName: "fake", + PackagePath: packagePath + "/fake", + HeaderText: boilerplate, + GeneratorFunc: func(c *generator.Context) (generators []generator.Generator) { + // Impl + generators = append(generators, &fakeInformerGenerator{ + DefaultGen: generator.DefaultGen{ + OptionalName: "fake", + }, + outputPackage: packagePath + "/fake", + imports: generator.NewImportTracker(), + typeToGenerate: t, + groupVersion: gv, + groupGoName: groupGoName, + informerInjectionPkg: packagePath, + fakeFactoryInjectionPkg: factoryPackagePath + "/fake", + }) + + return generators + }, + FilterFunc: func(c *generator.Context, t *types.Type) bool { + tags := util.MustParseClientGenTags(append(t.SecondClosestCommentLines, t.CommentLines...)) + return tags.GenerateClient && tags.HasVerb("list") && tags.HasVerb("watch") + }, + }) + } + return vers +} diff --git a/vendor/github.com/knative/pkg/codegen/cmd/injection-gen/main.go b/vendor/github.com/knative/pkg/codegen/cmd/injection-gen/main.go new file mode 100644 index 0000000000..4120d65cc9 --- /dev/null +++ b/vendor/github.com/knative/pkg/codegen/cmd/injection-gen/main.go @@ -0,0 +1,59 @@ +/* +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 main + +import ( + "flag" + "path/filepath" + + "k8s.io/code-generator/pkg/util" + "k8s.io/gengo/args" + "k8s.io/klog" + + generatorargs "github.com/knative/pkg/codegen/cmd/injection-gen/args" + "github.com/knative/pkg/codegen/cmd/injection-gen/generators" + "github.com/spf13/pflag" +) + +func main() { + klog.InitFlags(nil) + genericArgs, customArgs := generatorargs.NewDefaults() + + // Override defaults. + genericArgs.GoHeaderFilePath = filepath.Join(args.DefaultSourceTree(), util.BoilerplatePath()) + genericArgs.OutputPackagePath = "k8s.io/kubernetes/pkg/client/injection/informers/informers_generated" + + genericArgs.AddFlags(pflag.CommandLine) + customArgs.AddFlags(pflag.CommandLine) + flag.Set("logtostderr", "true") + pflag.CommandLine.AddGoFlagSet(flag.CommandLine) + pflag.Parse() + + if err := generatorargs.Validate(genericArgs); err != nil { + klog.Fatalf("Error: %v", err) + } + + // Run it. + if err := genericArgs.Execute( + generators.NameSystems(), + generators.DefaultNameSystem(), + generators.Packages, + ); err != nil { + klog.Fatalf("Error: %v", err) + } + klog.V(2).Info("Completed successfully.") +} diff --git a/vendor/github.com/knative/pkg/configmap/OWNERS b/vendor/github.com/knative/pkg/configmap/OWNERS new file mode 100644 index 0000000000..2480fc6d43 --- /dev/null +++ b/vendor/github.com/knative/pkg/configmap/OWNERS @@ -0,0 +1,4 @@ +# The OWNERS file is used by prow to automatically merge approved PRs. + +approvers: +- configmap-approvers diff --git a/vendor/github.com/knative/pkg/configmap/testing/configmap.go b/vendor/github.com/knative/pkg/configmap/testing/configmap.go new file mode 100644 index 0000000000..57646a7f8a --- /dev/null +++ b/vendor/github.com/knative/pkg/configmap/testing/configmap.go @@ -0,0 +1,97 @@ +/* +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 testing + +import ( + "fmt" + "io/ioutil" + "strings" + "testing" + + "github.com/ghodss/yaml" + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/util/sets" +) + +const ExampleKey = "_example" + +// ConfigMapFromTestFile creates a v1.ConfigMap from a YAML file +// It loads the YAML file from the testdata folder. +func ConfigMapFromTestFile(t *testing.T, name string, allowed ...string) *corev1.ConfigMap { + t.Helper() + + cm, _ := ConfigMapsFromTestFile(t, name, allowed...) + return cm +} + +// configMapsFromTestFile creates two corev1.ConfigMap resources from the config +// file read from the testdata directory: +// 1. The raw configmap read in. +// 2. A second version of the configmap augmenting `data:` with what's parsed from the value of `_example:` +func ConfigMapsFromTestFile(t *testing.T, name string, allowed ...string) (*corev1.ConfigMap, *corev1.ConfigMap) { + t.Helper() + + b, err := ioutil.ReadFile(fmt.Sprintf("testdata/%s.yaml", name)) + if err != nil { + t.Fatalf("ReadFile() = %v", err) + } + + var orig corev1.ConfigMap + + // Use github.com/ghodss/yaml since it reads json struct + // tags so things unmarshal properly + if err := yaml.Unmarshal(b, &orig); err != nil { + t.Fatalf("yaml.Unmarshal() = %v", err) + } + + // We expect each of the allowed keys, and a key holding an example + // configuration for us to validate. + allowed = append(allowed, ExampleKey) + + if len(orig.Data) != len(allowed) { + // See here for why we only check in empty ConfigMaps: + // https://github.com/knative/serving/issues/2668 + t.Errorf("Data = %v, wanted %v", orig.Data, allowed) + } + allow := sets.NewString(allowed...) + for key := range orig.Data { + if !allow.Has(key) { + t.Errorf("Encountered key %q in %q that wasn't on the allowed list", key, name) + } + } + // With the length and membership checks, we know that the keyspace matches. + + exampleBody := orig.Data[ExampleKey] + // Check that exampleBody does not have lines that end in a trailing space, + for i, line := range strings.Split(exampleBody, "\n") { + if strings.HasSuffix(line, " ") { + t.Errorf("line %d of %q example contains trailing spaces", i, name) + } + } + + // Parse exampleBody into exemplar.Data + exemplar := orig.DeepCopy() + if err := yaml.Unmarshal([]byte(exampleBody), &exemplar.Data); err != nil { + t.Fatalf("yaml.Unmarshal() = %v", err) + } + // Augment the sample with actual configuration + for k, v := range orig.Data { + if _, ok := exemplar.Data[k]; ok { + continue + } + exemplar.Data[k] = v + } + + return &orig, exemplar +} diff --git a/vendor/github.com/knative/pkg/controller/OWNERS b/vendor/github.com/knative/pkg/controller/OWNERS new file mode 100644 index 0000000000..afa22257a2 --- /dev/null +++ b/vendor/github.com/knative/pkg/controller/OWNERS @@ -0,0 +1,4 @@ +# The OWNERS file is used by prow to automatically merge approved PRs. + +approvers: +- controller-approvers diff --git a/vendor/github.com/knative/pkg/controller/controller.go b/vendor/github.com/knative/pkg/controller/controller.go index b714432f02..4471b9016f 100644 --- a/vendor/github.com/knative/pkg/controller/controller.go +++ b/vendor/github.com/knative/pkg/controller/controller.go @@ -29,6 +29,7 @@ import ( "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/util/runtime" "k8s.io/client-go/tools/cache" + "k8s.io/client-go/tools/record" "k8s.io/client-go/util/workqueue" "github.com/knative/pkg/kmeta" @@ -452,3 +453,22 @@ func GetResyncPeriod(ctx context.Context) time.Duration { func GetTrackerLease(ctx context.Context) time.Duration { return 3 * GetResyncPeriod(ctx) } + +// erKey is used to associate record.EventRecorders with contexts. +type erKey struct{} + +// WithEventRecorder attaches the given record.EventRecorder to the provided context +// in the returned context. +func WithEventRecorder(ctx context.Context, er record.EventRecorder) context.Context { + return context.WithValue(ctx, erKey{}, er) +} + +// GetEventRecorder attempts to look up the record.EventRecorder on a given context. +// It may return null if none is found. +func GetEventRecorder(ctx context.Context) record.EventRecorder { + untyped := ctx.Value(erKey{}) + if untyped == nil { + return nil + } + return untyped.(record.EventRecorder) +} diff --git a/vendor/github.com/knative/pkg/controller/testing/fake_stats_reporter.go b/vendor/github.com/knative/pkg/controller/testing/fake_stats_reporter.go new file mode 100644 index 0000000000..506754dc19 --- /dev/null +++ b/vendor/github.com/knative/pkg/controller/testing/fake_stats_reporter.go @@ -0,0 +1,65 @@ +/* +Copyright 2017 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 testing + +import ( + "sync" + "time" +) + +// FakeStatsReporter is a fake implementation of StatsReporter +type FakeStatsReporter struct { + queueDepths []int64 + reconcileData []FakeReconcileStatData + Lock sync.Mutex +} + +// FakeReconcileStatData is used to record the calls to ReportReconcile +type FakeReconcileStatData struct { + Duration time.Duration + Key, Success string +} + +// ReportQueueDepth records the call and returns success. +func (r *FakeStatsReporter) ReportQueueDepth(v int64) error { + r.Lock.Lock() + defer r.Lock.Unlock() + r.queueDepths = append(r.queueDepths, v) + return nil +} + +// ReportReconcile records the call and returns success. +func (r *FakeStatsReporter) ReportReconcile(duration time.Duration, key, success string) error { + r.Lock.Lock() + defer r.Lock.Unlock() + r.reconcileData = append(r.reconcileData, FakeReconcileStatData{duration, key, success}) + return nil +} + +// GetQueueDepths returns the recorded queue depth values +func (r *FakeStatsReporter) GetQueueDepths() []int64 { + r.Lock.Lock() + defer r.Lock.Unlock() + return r.queueDepths +} + +// GetReconcileData returns the recorded reconcile data +func (r *FakeStatsReporter) GetReconcileData() []FakeReconcileStatData { + r.Lock.Lock() + defer r.Lock.Unlock() + return r.reconcileData +} diff --git a/vendor/github.com/knative/pkg/hack/OWNERS b/vendor/github.com/knative/pkg/hack/OWNERS new file mode 100644 index 0000000000..c50adc8493 --- /dev/null +++ b/vendor/github.com/knative/pkg/hack/OWNERS @@ -0,0 +1,10 @@ +# The OWNERS file is used by prow to automatically merge approved PRs. + +approvers: +- productivity-approvers + +reviewers: +- productivity-reviewers + +labels: +- area/test-and-release diff --git a/vendor/github.com/knative/pkg/hack/boilerplate/boilerplate.go.txt b/vendor/github.com/knative/pkg/hack/boilerplate/boilerplate.go.txt new file mode 100644 index 0000000000..1f43b023ad --- /dev/null +++ b/vendor/github.com/knative/pkg/hack/boilerplate/boilerplate.go.txt @@ -0,0 +1,15 @@ +/* +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. +*/ diff --git a/vendor/github.com/knative/pkg/hack/generate-knative.sh b/vendor/github.com/knative/pkg/hack/generate-knative.sh new file mode 100755 index 0000000000..d13d491080 --- /dev/null +++ b/vendor/github.com/knative/pkg/hack/generate-knative.sh @@ -0,0 +1,78 @@ +#!/usr/bin/env bash + +# 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. + +set -o errexit +set -o nounset +set -o pipefail + +# generate-groups generates everything for a project with external types only, e.g. a project based +# on CustomResourceDefinitions. + +if [ "$#" -lt 4 ] || [ "${1}" == "--help" ]; then + cat < ... + + the generators comma separated to run (deepcopy,defaulter,client,lister,informer) or "all". + the output package name (e.g. github.com/example/project/pkg/generated). + the external types dir (e.g. github.com/example/api or github.com/example/project/pkg/apis). + the groups and their versions in the format "groupA:v1,v2 groupB:v1 groupC:v2", relative + to . + ... arbitrary flags passed to all generator binaries. + + +Examples: + $(basename $0) all github.com/example/project/pkg/client github.com/example/project/pkg/apis "foo:v1 bar:v1alpha1,v1beta1" + $(basename $0) injection,foo github.com/example/project/pkg/client github.com/example/project/pkg/apis "foo:v1 bar:v1alpha1,v1beta1" +EOF + exit 0 +fi + +GENS="$1" +OUTPUT_PKG="$2" +APIS_PKG="$3" +GROUPS_WITH_VERSIONS="$4" +shift 4 + +( + # To support running this script from anywhere, we have to first cd into this directory + # so we can install the tools. + cd $(dirname "${0}") + go install ../codegen/cmd/injection-gen +) + +function codegen::join() { local IFS="$1"; shift; echo "$*"; } + +# enumerate group versions +FQ_APIS=() # e.g. k8s.io/api/apps/v1 +for GVs in ${GROUPS_WITH_VERSIONS}; do + IFS=: read G Vs <<<"${GVs}" + + # enumerate versions + for V in ${Vs//,/ }; do + FQ_APIS+=(${APIS_PKG}/${G}/${V}) + done +done + +if grep -qw "injection" <<<"${GENS}"; then + echo "Generating injection for ${GROUPS_WITH_VERSIONS} at ${OUTPUT_PKG}/injection" + + ${GOPATH}/bin/injection-gen \ + --input-dirs $(codegen::join , "${FQ_APIS[@]}") \ + --versioned-clientset-package ${OUTPUT_PKG}/clientset/versioned \ + --external-versions-informers-package ${OUTPUT_PKG}/informers/externalversions \ + --output-package ${OUTPUT_PKG}/injection \ + "$@" +fi diff --git a/vendor/github.com/knative/pkg/hack/update-codegen.sh b/vendor/github.com/knative/pkg/hack/update-codegen.sh new file mode 100755 index 0000000000..ed4695d85f --- /dev/null +++ b/vendor/github.com/knative/pkg/hack/update-codegen.sh @@ -0,0 +1,55 @@ +#!/usr/bin/env bash + +# 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. + +set -o errexit +set -o nounset +set -o pipefail + +source $(dirname $0)/../vendor/github.com/knative/test-infra/scripts/library.sh + +CODEGEN_PKG=${CODEGEN_PKG:-$(cd ${REPO_ROOT_DIR}; ls -d -1 ./vendor/k8s.io/code-generator 2>/dev/null || echo ../code-generator)} + +go install ./vendor/k8s.io/code-generator/cmd/deepcopy-gen + +# generate the code with: +# --output-base because this script should also be able to run inside the vendor dir of +# k8s.io/kubernetes. The output-base is needed for the generators to output into the vendor dir +# instead of the $GOPATH directly. For normal projects this can be dropped. +${CODEGEN_PKG}/generate-groups.sh "deepcopy,client,informer,lister" \ + github.com/knative/pkg/client github.com/knative/pkg/apis \ + "istio:v1alpha3 istio/authentication:v1alpha1" \ + --go-header-file ${REPO_ROOT_DIR}/hack/boilerplate/boilerplate.go.txt + +# Knative Injection +${REPO_ROOT_DIR}/hack/generate-knative.sh "injection" \ + github.com/knative/pkg/client github.com/knative/pkg/apis \ + "istio:v1alpha3 istio/authentication:v1alpha1" \ + --go-header-file ${REPO_ROOT_DIR}/hack/boilerplate/boilerplate.go.txt + +# Only deepcopy the Duck types, as they are not real resources. +${CODEGEN_PKG}/generate-groups.sh "deepcopy" \ + github.com/knative/pkg/client github.com/knative/pkg/apis \ + "duck:v1alpha1,v1beta1" \ + --go-header-file ${REPO_ROOT_DIR}/hack/boilerplate/boilerplate.go.txt + +# Depends on generate-groups.sh to install bin/deepcopy-gen +${GOPATH}/bin/deepcopy-gen --input-dirs \ + github.com/knative/pkg/apis,github.com/knative/pkg/logging,github.com/knative/pkg/testing \ + -O zz_generated.deepcopy \ + --go-header-file ${REPO_ROOT_DIR}/hack/boilerplate/boilerplate.go.txt + +# Make sure our dependencies are up-to-date +${REPO_ROOT_DIR}/hack/update-deps.sh diff --git a/vendor/github.com/knative/pkg/hack/update-deps.sh b/vendor/github.com/knative/pkg/hack/update-deps.sh new file mode 100755 index 0000000000..2213d6510e --- /dev/null +++ b/vendor/github.com/knative/pkg/hack/update-deps.sh @@ -0,0 +1,29 @@ +#!/usr/bin/env bash + +# 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. + +set -o errexit +set -o nounset +set -o pipefail + +source $(dirname $0)/../vendor/github.com/knative/test-infra/scripts/library.sh + +cd ${REPO_ROOT_DIR} + +# Ensure we have everything we need under vendor/ +dep ensure + +rm -rf $(find vendor/ -name 'OWNERS') +rm -rf $(find vendor/ -name '*_test.go') diff --git a/vendor/github.com/knative/pkg/hack/verify-codegen.sh b/vendor/github.com/knative/pkg/hack/verify-codegen.sh new file mode 100755 index 0000000000..18bbe693ff --- /dev/null +++ b/vendor/github.com/knative/pkg/hack/verify-codegen.sh @@ -0,0 +1,74 @@ +#!/usr/bin/env bash + +# 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. + +set -o errexit +set -o nounset +set -o pipefail + +source $(dirname $0)/../vendor/github.com/knative/test-infra/scripts/library.sh + +readonly TMP_DIFFROOT="$(mktemp -d ${REPO_ROOT_DIR}/tmpdiffroot.XXXXXX)" + +cleanup() { + rm -rf "${TMP_DIFFROOT}" +} + +trap "cleanup" EXIT SIGINT + +cleanup + +# Save working tree state +mkdir -p "${TMP_DIFFROOT}" + +cp -aR \ + "${REPO_ROOT_DIR}/Gopkg.lock" \ + "${REPO_ROOT_DIR}/apis" \ + "${REPO_ROOT_DIR}/logging" \ + "${REPO_ROOT_DIR}/testing" \ + "${TMP_DIFFROOT}" + +"${REPO_ROOT_DIR}/hack/update-codegen.sh" +echo "Diffing ${REPO_ROOT_DIR} against freshly generated codegen" +ret=0 + +diff -Naupr --no-dereference \ + "${REPO_ROOT_DIR}/Gopkg.lock" "${TMP_DIFFROOT}/Gopkg.lock" || ret=1 + +diff -Naupr --no-dereference \ + "${REPO_ROOT_DIR}/apis" "${TMP_DIFFROOT}/apis" || ret=1 + +diff -Naupr --no-dereference \ + "${REPO_ROOT_DIR}/logging" "${TMP_DIFFROOT}/logging" || ret=1 + +diff -Naupr --no-dereference \ + "${REPO_ROOT_DIR}/testing" "${TMP_DIFFROOT}/testing" || ret=1 + +# Restore working tree state +rm -fr \ + "${REPO_ROOT_DIR}/Gopkg.lock" \ + "${REPO_ROOT_DIR}/apis" \ + "${REPO_ROOT_DIR}/logging" \ + "${REPO_ROOT_DIR}/testing" + +cp -aR "${TMP_DIFFROOT}"/* "${REPO_ROOT_DIR}" + +if [[ $ret -eq 0 ]] +then + echo "${REPO_ROOT_DIR} up to date." + else + echo "${REPO_ROOT_DIR} is out of date. Please run hack/update-codegen.sh" + exit 1 +fi diff --git a/vendor/github.com/knative/pkg/injection/OWNERS b/vendor/github.com/knative/pkg/injection/OWNERS new file mode 100644 index 0000000000..dda47512a4 --- /dev/null +++ b/vendor/github.com/knative/pkg/injection/OWNERS @@ -0,0 +1,5 @@ +# The OWNERS file is used by prow to automatically merge approved PRs. + +approvers: +- mattmoor +- n3wscott diff --git a/vendor/github.com/knative/pkg/injection/README.md b/vendor/github.com/knative/pkg/injection/README.md new file mode 100644 index 0000000000..32f0a2dfad --- /dev/null +++ b/vendor/github.com/knative/pkg/injection/README.md @@ -0,0 +1,222 @@ +# Knative Dependency Injection + +This library supports the production of controller processes with +minimal boilerplate outside of the reconciler implementation. + +## Registering Controllers + +To adopt this model of controller construction, implementations +should start with the following controller constructor: + +```go +import ( + "context" + + "github.com/knative/pkg/configmap" + "github.com/knative/pkg/controller" + "github.com/knative/pkg/injection" + "github.com/knative/pkg/logging" +) + +func NewController(ctx context.Context, cmw configmap.Watcher) *controller.Impl { + logger := logging.FromContext(ctx) + + // TODO(you): Access informers + + c := &Reconciler{ + // TODO(you): Pass listers, clients, and other stuff. + } + impl := controller.NewImpl(c, logger, "NameOfController") + + // TODO(you): Set up event handlers. + + return impl +} + +// Register our controller process. +func init() { + injection.Default.RegisterController(NewController) +} +``` + +## 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. + "github.com/knative/pkg/injection/clients/kubeclient" + svcinformer "github.com/knative/pkg/injection/informers/kubeinformers/corev1/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(), + } + impl := controller.NewImpl(c, logger, "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. + +``` +import ( + "testing" + + // Link the fakes for any informers our controller accesses. + _ "github.com/knative/pkg/injection/informers/kubeinformers/corev1/service/fake" + + "k8s.io/client-go/rest" + "github.com/knative/pkg/injection" + logtesting "github.com/knative/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: + +``` +import ( + "testing" + + fakekubeclient "github.com/knative/pkg/injection/clients/kubeclient/fake" + + "k8s.io/client-go/rest" + "github.com/knative/pkg/injection" + logtesting "github.com/knative/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 + +By registering our controller with `injection.Default` via `init()` above we +enable our shared main method to bootstrap the entire container process. All +we do is link the controller packages containing the `init()` registering them +and this transitively links in all of the things it needs. 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. + "github.com/knative/pkg/injection/sharedmain" +) + +func main() { + sharedmain.Main() +} + +``` + + +## 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/github.com/knative/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 = [ + "github.com/knative/pkg/codegen/cmd/injection-gen", +] + +# .. Constraints + +# Keeps things like the generate-knative.sh script +[[prune.project]] + name = "github.com/knative/pkg" + unused-packages = false + non-go = false +``` diff --git a/vendor/github.com/knative/pkg/injection/clients.go b/vendor/github.com/knative/pkg/injection/clients.go new file mode 100644 index 0000000000..5c464924c7 --- /dev/null +++ b/vendor/github.com/knative/pkg/injection/clients.go @@ -0,0 +1,42 @@ +/* +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 + +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...) +} diff --git a/vendor/github.com/knative/pkg/injection/clients/dynamicclient/dynamicclient.go b/vendor/github.com/knative/pkg/injection/clients/dynamicclient/dynamicclient.go new file mode 100644 index 0000000000..84eba3f0c6 --- /dev/null +++ b/vendor/github.com/knative/pkg/injection/clients/dynamicclient/dynamicclient.go @@ -0,0 +1,47 @@ +/* +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 dynamicclient + +import ( + "context" + + "k8s.io/client-go/dynamic" + "k8s.io/client-go/rest" + + "github.com/knative/pkg/injection" +) + +func init() { + injection.Default.RegisterClient(withClient) +} + +// Key is used as the key for associating information +// with a context.Context. +type Key struct{} + +func withClient(ctx context.Context, cfg *rest.Config) context.Context { + return context.WithValue(ctx, Key{}, dynamic.NewForConfigOrDie(cfg)) +} + +// Get extracts the Dynamic client from the context. +func Get(ctx context.Context) dynamic.Interface { + untyped := ctx.Value(Key{}) + if untyped == nil { + return nil + } + return untyped.(dynamic.Interface) +} diff --git a/vendor/github.com/knative/pkg/injection/clients/dynamicclient/fake/fake.go b/vendor/github.com/knative/pkg/injection/clients/dynamicclient/fake/fake.go new file mode 100644 index 0000000000..fd201c95ad --- /dev/null +++ b/vendor/github.com/knative/pkg/injection/clients/dynamicclient/fake/fake.go @@ -0,0 +1,51 @@ +/* +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 fake + +import ( + "context" + + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/client-go/dynamic/fake" + "k8s.io/client-go/rest" + + "github.com/knative/pkg/injection" + "github.com/knative/pkg/injection/clients/dynamicclient" +) + +func init() { + injection.Fake.RegisterClient(withClient) +} + +func withClient(ctx context.Context, cfg *rest.Config) context.Context { + ctx, _ = With(ctx, runtime.NewScheme()) + return ctx +} + +func With(ctx context.Context, scheme *runtime.Scheme, objects ...runtime.Object) (context.Context, *fake.FakeDynamicClient) { + cs := fake.NewSimpleDynamicClient(scheme, objects...) + return context.WithValue(ctx, dynamicclient.Key{}, cs), cs +} + +// Get extracts the Kubernetes client from the context. +func Get(ctx context.Context) *fake.FakeDynamicClient { + untyped := ctx.Value(dynamicclient.Key{}) + if untyped == nil { + return nil + } + return untyped.(*fake.FakeDynamicClient) +} diff --git a/vendor/github.com/knative/pkg/injection/clients/kubeclient/fake/fake.go b/vendor/github.com/knative/pkg/injection/clients/kubeclient/fake/fake.go new file mode 100644 index 0000000000..02be6d385d --- /dev/null +++ b/vendor/github.com/knative/pkg/injection/clients/kubeclient/fake/fake.go @@ -0,0 +1,51 @@ +/* +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 fake + +import ( + "context" + + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/client-go/kubernetes/fake" + "k8s.io/client-go/rest" + + "github.com/knative/pkg/injection" + "github.com/knative/pkg/injection/clients/kubeclient" +) + +func init() { + injection.Fake.RegisterClient(withClient) +} + +func withClient(ctx context.Context, cfg *rest.Config) context.Context { + ctx, _ = With(ctx) + return ctx +} + +func With(ctx context.Context, objects ...runtime.Object) (context.Context, *fake.Clientset) { + cs := fake.NewSimpleClientset(objects...) + return context.WithValue(ctx, kubeclient.Key{}, cs), cs +} + +// Get extracts the Kubernetes client from the context. +func Get(ctx context.Context) *fake.Clientset { + untyped := ctx.Value(kubeclient.Key{}) + if untyped == nil { + return nil + } + return untyped.(*fake.Clientset) +} diff --git a/vendor/github.com/knative/pkg/injection/clients/kubeclient/kubeclient.go b/vendor/github.com/knative/pkg/injection/clients/kubeclient/kubeclient.go new file mode 100644 index 0000000000..b12a9b327a --- /dev/null +++ b/vendor/github.com/knative/pkg/injection/clients/kubeclient/kubeclient.go @@ -0,0 +1,47 @@ +/* +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 kubeclient + +import ( + "context" + + "k8s.io/client-go/kubernetes" + "k8s.io/client-go/rest" + + "github.com/knative/pkg/injection" +) + +func init() { + injection.Default.RegisterClient(withClient) +} + +// Key is used as the key for associating information +// with a context.Context. +type Key struct{} + +func withClient(ctx context.Context, cfg *rest.Config) context.Context { + return context.WithValue(ctx, Key{}, kubernetes.NewForConfigOrDie(cfg)) +} + +// Get extracts the Kubernetes client from the context. +func Get(ctx context.Context) kubernetes.Interface { + untyped := ctx.Value(Key{}) + if untyped == nil { + return nil + } + return untyped.(kubernetes.Interface) +} diff --git a/vendor/github.com/knative/pkg/injection/controllers.go b/vendor/github.com/knative/pkg/injection/controllers.go new file mode 100644 index 0000000000..2b8bd62d73 --- /dev/null +++ b/vendor/github.com/knative/pkg/injection/controllers.go @@ -0,0 +1,43 @@ +/* +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" + + "github.com/knative/pkg/configmap" + "github.com/knative/pkg/controller" +) + +// ControllerInjector holds the type of a callback that attaches a particular +// controller type to a context. +type ControllerInjector func(context.Context, configmap.Watcher) *controller.Impl + +func (i *impl) RegisterController(ii ControllerInjector) { + i.m.Lock() + defer i.m.Unlock() + + i.controllers = append(i.controllers, ii) +} + +func (i *impl) GetControllers() []ControllerInjector { + i.m.RLock() + defer i.m.RUnlock() + + // Copy the slice before returning. + return append(i.controllers[:0:0], i.controllers...) +} diff --git a/vendor/github.com/knative/pkg/injection/doc.go b/vendor/github.com/knative/pkg/injection/doc.go new file mode 100644 index 0000000000..ca4e8ed221 --- /dev/null +++ b/vendor/github.com/knative/pkg/injection/doc.go @@ -0,0 +1,65 @@ +/* +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. +// deployinformer "github.com/knative/pkg/injection/informers/kubeinformers/appsv1/deployment" +// "github.com/knative/pkg/injection" +// ) +// +// func NewController(ctx context.Context) *controller.Impl { +// deploymentInformer := deployinformer.Get(ctx) +// // Pass deploymentInformer.Lister() to Reconciler +// ... +// // Set up events on deploymentInformer.Informer() +// ... +// } +// +// func init() { +// injection.Default.RegisterController(NewController) +// } +// +// 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 the controllers and 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. +// "github.com/knative/pkg/injection/sharedmain" +// ) +// +// func main() { +// sharedmain.Main() +// } +package injection diff --git a/vendor/github.com/knative/pkg/injection/factories.go b/vendor/github.com/knative/pkg/injection/factories.go new file mode 100644 index 0000000000..fc913612a0 --- /dev/null +++ b/vendor/github.com/knative/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/github.com/knative/pkg/injection/informers.go b/vendor/github.com/knative/pkg/injection/informers.go new file mode 100644 index 0000000000..0425ae4981 --- /dev/null +++ b/vendor/github.com/knative/pkg/injection/informers.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" + + "k8s.io/client-go/rest" + + "github.com/knative/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) + +func (i *impl) RegisterInformer(ii InformerInjector) { + i.m.Lock() + defer i.m.Unlock() + + i.informers = append(i.informers, ii) +} + +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) 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 informers + // and inject them onto the context. + var inf controller.Informer + informers := make([]controller.Informer, 0, len(i.GetInformers())) + for _, ii := range i.GetInformers() { + ctx, inf = ii(ctx) + informers = append(informers, inf) + } + return ctx, informers +} diff --git a/vendor/github.com/knative/pkg/injection/informers/kubeinformers/appsv1/deployment/deployment.go b/vendor/github.com/knative/pkg/injection/informers/kubeinformers/appsv1/deployment/deployment.go new file mode 100644 index 0000000000..a79e44351a --- /dev/null +++ b/vendor/github.com/knative/pkg/injection/informers/kubeinformers/appsv1/deployment/deployment.go @@ -0,0 +1,50 @@ +/* +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 deployment + +import ( + "context" + + appsv1 "k8s.io/client-go/informers/apps/v1" + + "github.com/knative/pkg/controller" + "github.com/knative/pkg/injection" + "github.com/knative/pkg/injection/informers/kubeinformers/factory" +) + +func init() { + injection.Default.RegisterInformer(withInformer) +} + +// Key is used as the key for associating information +// with a context.Context. +type Key struct{} + +func withInformer(ctx context.Context) (context.Context, controller.Informer) { + f := factory.Get(ctx) + inf := f.Apps().V1().Deployments() + return context.WithValue(ctx, Key{}, inf), inf.Informer() +} + +// Get extracts the Kubernetes Deployment informer from the context. +func Get(ctx context.Context) appsv1.DeploymentInformer { + untyped := ctx.Value(Key{}) + if untyped == nil { + return nil + } + return untyped.(appsv1.DeploymentInformer) +} diff --git a/vendor/github.com/knative/pkg/injection/informers/kubeinformers/appsv1/deployment/fake/fake.go b/vendor/github.com/knative/pkg/injection/informers/kubeinformers/appsv1/deployment/fake/fake.go new file mode 100644 index 0000000000..51cebf9e89 --- /dev/null +++ b/vendor/github.com/knative/pkg/injection/informers/kubeinformers/appsv1/deployment/fake/fake.go @@ -0,0 +1,38 @@ +/* +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 fake + +import ( + "context" + + "github.com/knative/pkg/controller" + "github.com/knative/pkg/injection" + "github.com/knative/pkg/injection/informers/kubeinformers/appsv1/deployment" + "github.com/knative/pkg/injection/informers/kubeinformers/factory/fake" +) + +var Get = deployment.Get + +func init() { + injection.Fake.RegisterInformer(withInformer) +} + +func withInformer(ctx context.Context) (context.Context, controller.Informer) { + f := fake.Get(ctx) + inf := f.Apps().V1().Deployments() + return context.WithValue(ctx, deployment.Key{}, inf), inf.Informer() +} diff --git a/vendor/github.com/knative/pkg/injection/informers/kubeinformers/autoscalingv1/hpa/fake/fake.go b/vendor/github.com/knative/pkg/injection/informers/kubeinformers/autoscalingv1/hpa/fake/fake.go new file mode 100644 index 0000000000..4e33caed34 --- /dev/null +++ b/vendor/github.com/knative/pkg/injection/informers/kubeinformers/autoscalingv1/hpa/fake/fake.go @@ -0,0 +1,38 @@ +/* +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 fake + +import ( + "context" + + "github.com/knative/pkg/controller" + "github.com/knative/pkg/injection" + "github.com/knative/pkg/injection/informers/kubeinformers/autoscalingv1/hpa" + "github.com/knative/pkg/injection/informers/kubeinformers/factory/fake" +) + +var Get = hpa.Get + +func init() { + injection.Fake.RegisterInformer(withInformer) +} + +func withInformer(ctx context.Context) (context.Context, controller.Informer) { + f := fake.Get(ctx) + inf := f.Autoscaling().V1().HorizontalPodAutoscalers() + return context.WithValue(ctx, hpa.Key{}, inf), inf.Informer() +} diff --git a/vendor/github.com/knative/pkg/injection/informers/kubeinformers/autoscalingv1/hpa/hpa.go b/vendor/github.com/knative/pkg/injection/informers/kubeinformers/autoscalingv1/hpa/hpa.go new file mode 100644 index 0000000000..ab1ceaa0cc --- /dev/null +++ b/vendor/github.com/knative/pkg/injection/informers/kubeinformers/autoscalingv1/hpa/hpa.go @@ -0,0 +1,50 @@ +/* +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 hpa + +import ( + "context" + + autoscalingv1 "k8s.io/client-go/informers/autoscaling/v1" + + "github.com/knative/pkg/controller" + "github.com/knative/pkg/injection" + "github.com/knative/pkg/injection/informers/kubeinformers/factory" +) + +func init() { + injection.Default.RegisterInformer(withInformer) +} + +// Key is used as the key for associating information +// with a context.Context. +type Key struct{} + +func withInformer(ctx context.Context) (context.Context, controller.Informer) { + f := factory.Get(ctx) + inf := f.Autoscaling().V1().HorizontalPodAutoscalers() + return context.WithValue(ctx, Key{}, inf), inf.Informer() +} + +// Get extracts the Kubernetes Hpa informer from the context. +func Get(ctx context.Context) autoscalingv1.HorizontalPodAutoscalerInformer { + untyped := ctx.Value(Key{}) + if untyped == nil { + return nil + } + return untyped.(autoscalingv1.HorizontalPodAutoscalerInformer) +} diff --git a/vendor/github.com/knative/pkg/injection/informers/kubeinformers/autoscalingv2beta1/hpa/fake/fake.go b/vendor/github.com/knative/pkg/injection/informers/kubeinformers/autoscalingv2beta1/hpa/fake/fake.go new file mode 100644 index 0000000000..5a9fabd0c9 --- /dev/null +++ b/vendor/github.com/knative/pkg/injection/informers/kubeinformers/autoscalingv2beta1/hpa/fake/fake.go @@ -0,0 +1,38 @@ +/* +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 fake + +import ( + "context" + + "github.com/knative/pkg/controller" + "github.com/knative/pkg/injection" + "github.com/knative/pkg/injection/informers/kubeinformers/autoscalingv2beta1/hpa" + "github.com/knative/pkg/injection/informers/kubeinformers/factory/fake" +) + +var Get = hpa.Get + +func init() { + injection.Fake.RegisterInformer(withInformer) +} + +func withInformer(ctx context.Context) (context.Context, controller.Informer) { + f := fake.Get(ctx) + inf := f.Autoscaling().V2beta1().HorizontalPodAutoscalers() + return context.WithValue(ctx, hpa.Key{}, inf), inf.Informer() +} diff --git a/vendor/github.com/knative/pkg/injection/informers/kubeinformers/autoscalingv2beta1/hpa/hpa.go b/vendor/github.com/knative/pkg/injection/informers/kubeinformers/autoscalingv2beta1/hpa/hpa.go new file mode 100644 index 0000000000..e5666cd7f6 --- /dev/null +++ b/vendor/github.com/knative/pkg/injection/informers/kubeinformers/autoscalingv2beta1/hpa/hpa.go @@ -0,0 +1,50 @@ +/* +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 hpa + +import ( + "context" + + autoscalingv2beta1 "k8s.io/client-go/informers/autoscaling/v2beta1" + + "github.com/knative/pkg/controller" + "github.com/knative/pkg/injection" + "github.com/knative/pkg/injection/informers/kubeinformers/factory" +) + +func init() { + injection.Default.RegisterInformer(withInformer) +} + +// Key is used as the key for associating information +// with a context.Context. +type Key struct{} + +func withInformer(ctx context.Context) (context.Context, controller.Informer) { + f := factory.Get(ctx) + inf := f.Autoscaling().V2beta1().HorizontalPodAutoscalers() + return context.WithValue(ctx, Key{}, inf), inf.Informer() +} + +// Get extracts the Kubernetes Hpa informer from the context. +func Get(ctx context.Context) autoscalingv2beta1.HorizontalPodAutoscalerInformer { + untyped := ctx.Value(Key{}) + if untyped == nil { + return nil + } + return untyped.(autoscalingv2beta1.HorizontalPodAutoscalerInformer) +} diff --git a/vendor/github.com/knative/pkg/injection/informers/kubeinformers/corev1/configmap/configmap.go b/vendor/github.com/knative/pkg/injection/informers/kubeinformers/corev1/configmap/configmap.go new file mode 100644 index 0000000000..cfd596ceae --- /dev/null +++ b/vendor/github.com/knative/pkg/injection/informers/kubeinformers/corev1/configmap/configmap.go @@ -0,0 +1,50 @@ +/* +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 configmap + +import ( + "context" + + corev1 "k8s.io/client-go/informers/core/v1" + + "github.com/knative/pkg/controller" + "github.com/knative/pkg/injection" + "github.com/knative/pkg/injection/informers/kubeinformers/factory" +) + +func init() { + injection.Default.RegisterInformer(withInformer) +} + +// Key is used as the key for associating information +// with a context.Context. +type Key struct{} + +func withInformer(ctx context.Context) (context.Context, controller.Informer) { + f := factory.Get(ctx) + inf := f.Core().V1().ConfigMaps() + return context.WithValue(ctx, Key{}, inf), inf.Informer() +} + +// Get extracts the Kubernetes ConfigMap informer from the context. +func Get(ctx context.Context) corev1.ConfigMapInformer { + untyped := ctx.Value(Key{}) + if untyped == nil { + return nil + } + return untyped.(corev1.ConfigMapInformer) +} diff --git a/vendor/github.com/knative/pkg/injection/informers/kubeinformers/corev1/configmap/fake/fake.go b/vendor/github.com/knative/pkg/injection/informers/kubeinformers/corev1/configmap/fake/fake.go new file mode 100644 index 0000000000..089cb95f0e --- /dev/null +++ b/vendor/github.com/knative/pkg/injection/informers/kubeinformers/corev1/configmap/fake/fake.go @@ -0,0 +1,38 @@ +/* +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 fake + +import ( + "context" + + "github.com/knative/pkg/controller" + "github.com/knative/pkg/injection" + "github.com/knative/pkg/injection/informers/kubeinformers/corev1/configmap" + "github.com/knative/pkg/injection/informers/kubeinformers/factory/fake" +) + +var Get = configmap.Get + +func init() { + injection.Fake.RegisterInformer(withInformer) +} + +func withInformer(ctx context.Context) (context.Context, controller.Informer) { + f := fake.Get(ctx) + inf := f.Core().V1().ConfigMaps() + return context.WithValue(ctx, configmap.Key{}, inf), inf.Informer() +} diff --git a/vendor/github.com/knative/pkg/injection/informers/kubeinformers/corev1/endpoints/endpoints.go b/vendor/github.com/knative/pkg/injection/informers/kubeinformers/corev1/endpoints/endpoints.go new file mode 100644 index 0000000000..27cc7a014f --- /dev/null +++ b/vendor/github.com/knative/pkg/injection/informers/kubeinformers/corev1/endpoints/endpoints.go @@ -0,0 +1,50 @@ +/* +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 endpoints + +import ( + "context" + + corev1 "k8s.io/client-go/informers/core/v1" + + "github.com/knative/pkg/controller" + "github.com/knative/pkg/injection" + "github.com/knative/pkg/injection/informers/kubeinformers/factory" +) + +func init() { + injection.Default.RegisterInformer(withInformer) +} + +// Key is used as the key for associating information +// with a context.Context. +type Key struct{} + +func withInformer(ctx context.Context) (context.Context, controller.Informer) { + f := factory.Get(ctx) + inf := f.Core().V1().Endpoints() + return context.WithValue(ctx, Key{}, inf), inf.Informer() +} + +// Get extracts the Kubernetes Endpoints informer from the context. +func Get(ctx context.Context) corev1.EndpointsInformer { + untyped := ctx.Value(Key{}) + if untyped == nil { + return nil + } + return untyped.(corev1.EndpointsInformer) +} diff --git a/vendor/github.com/knative/pkg/injection/informers/kubeinformers/corev1/endpoints/fake/fake.go b/vendor/github.com/knative/pkg/injection/informers/kubeinformers/corev1/endpoints/fake/fake.go new file mode 100644 index 0000000000..2504c1bde4 --- /dev/null +++ b/vendor/github.com/knative/pkg/injection/informers/kubeinformers/corev1/endpoints/fake/fake.go @@ -0,0 +1,38 @@ +/* +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 fake + +import ( + "context" + + "github.com/knative/pkg/controller" + "github.com/knative/pkg/injection" + "github.com/knative/pkg/injection/informers/kubeinformers/corev1/endpoints" + "github.com/knative/pkg/injection/informers/kubeinformers/factory/fake" +) + +var Get = endpoints.Get + +func init() { + injection.Fake.RegisterInformer(withInformer) +} + +func withInformer(ctx context.Context) (context.Context, controller.Informer) { + f := fake.Get(ctx) + inf := f.Core().V1().Endpoints() + return context.WithValue(ctx, endpoints.Key{}, inf), inf.Informer() +} diff --git a/vendor/github.com/knative/pkg/injection/informers/kubeinformers/corev1/secret/fake/fake.go b/vendor/github.com/knative/pkg/injection/informers/kubeinformers/corev1/secret/fake/fake.go new file mode 100644 index 0000000000..37a4a5153c --- /dev/null +++ b/vendor/github.com/knative/pkg/injection/informers/kubeinformers/corev1/secret/fake/fake.go @@ -0,0 +1,38 @@ +/* +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 fake + +import ( + "context" + + "github.com/knative/pkg/controller" + "github.com/knative/pkg/injection" + "github.com/knative/pkg/injection/informers/kubeinformers/corev1/secret" + "github.com/knative/pkg/injection/informers/kubeinformers/factory/fake" +) + +var Get = secret.Get + +func init() { + injection.Fake.RegisterInformer(withInformer) +} + +func withInformer(ctx context.Context) (context.Context, controller.Informer) { + f := fake.Get(ctx) + inf := f.Core().V1().Secrets() + return context.WithValue(ctx, secret.Key{}, inf), inf.Informer() +} diff --git a/vendor/github.com/knative/pkg/injection/informers/kubeinformers/corev1/secret/secret.go b/vendor/github.com/knative/pkg/injection/informers/kubeinformers/corev1/secret/secret.go new file mode 100644 index 0000000000..249f9d90a5 --- /dev/null +++ b/vendor/github.com/knative/pkg/injection/informers/kubeinformers/corev1/secret/secret.go @@ -0,0 +1,50 @@ +/* +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 secret + +import ( + "context" + + corev1 "k8s.io/client-go/informers/core/v1" + + "github.com/knative/pkg/controller" + "github.com/knative/pkg/injection" + "github.com/knative/pkg/injection/informers/kubeinformers/factory" +) + +func init() { + injection.Default.RegisterInformer(withInformer) +} + +// Key is used as the key for associating information +// with a context.Context. +type Key struct{} + +func withInformer(ctx context.Context) (context.Context, controller.Informer) { + f := factory.Get(ctx) + inf := f.Core().V1().Secrets() + return context.WithValue(ctx, Key{}, inf), inf.Informer() +} + +// Get extracts the Kubernetes Secret informer from the context. +func Get(ctx context.Context) corev1.SecretInformer { + untyped := ctx.Value(Key{}) + if untyped == nil { + return nil + } + return untyped.(corev1.SecretInformer) +} diff --git a/vendor/github.com/knative/pkg/injection/informers/kubeinformers/corev1/service/fake/fake.go b/vendor/github.com/knative/pkg/injection/informers/kubeinformers/corev1/service/fake/fake.go new file mode 100644 index 0000000000..8c52d19ab1 --- /dev/null +++ b/vendor/github.com/knative/pkg/injection/informers/kubeinformers/corev1/service/fake/fake.go @@ -0,0 +1,38 @@ +/* +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 fake + +import ( + "context" + + "github.com/knative/pkg/controller" + "github.com/knative/pkg/injection" + "github.com/knative/pkg/injection/informers/kubeinformers/corev1/service" + "github.com/knative/pkg/injection/informers/kubeinformers/factory/fake" +) + +var Get = service.Get + +func init() { + injection.Fake.RegisterInformer(withInformer) +} + +func withInformer(ctx context.Context) (context.Context, controller.Informer) { + f := fake.Get(ctx) + inf := f.Core().V1().Services() + return context.WithValue(ctx, service.Key{}, inf), inf.Informer() +} diff --git a/vendor/github.com/knative/pkg/injection/informers/kubeinformers/corev1/service/service.go b/vendor/github.com/knative/pkg/injection/informers/kubeinformers/corev1/service/service.go new file mode 100644 index 0000000000..bae64aa422 --- /dev/null +++ b/vendor/github.com/knative/pkg/injection/informers/kubeinformers/corev1/service/service.go @@ -0,0 +1,50 @@ +/* +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 service + +import ( + "context" + + corev1 "k8s.io/client-go/informers/core/v1" + + "github.com/knative/pkg/controller" + "github.com/knative/pkg/injection" + "github.com/knative/pkg/injection/informers/kubeinformers/factory" +) + +func init() { + injection.Default.RegisterInformer(withInformer) +} + +// Key is used as the key for associating information +// with a context.Context. +type Key struct{} + +func withInformer(ctx context.Context) (context.Context, controller.Informer) { + f := factory.Get(ctx) + inf := f.Core().V1().Services() + return context.WithValue(ctx, Key{}, inf), inf.Informer() +} + +// Get extracts the Kubernetes Service informer from the context. +func Get(ctx context.Context) corev1.ServiceInformer { + untyped := ctx.Value(Key{}) + if untyped == nil { + return nil + } + return untyped.(corev1.ServiceInformer) +} diff --git a/vendor/github.com/knative/pkg/injection/informers/kubeinformers/factory/factory.go b/vendor/github.com/knative/pkg/injection/informers/kubeinformers/factory/factory.go new file mode 100644 index 0000000000..b3a9323335 --- /dev/null +++ b/vendor/github.com/knative/pkg/injection/informers/kubeinformers/factory/factory.go @@ -0,0 +1,50 @@ +/* +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 factory + +import ( + "context" + + "k8s.io/client-go/informers" + + "github.com/knative/pkg/controller" + "github.com/knative/pkg/injection" + "github.com/knative/pkg/injection/clients/kubeclient" +) + +func init() { + injection.Default.RegisterInformerFactory(withInformerFactory) +} + +// Key is used as the key for associating information +// with a context.Context. +type Key struct{} + +func withInformerFactory(ctx context.Context) context.Context { + kc := kubeclient.Get(ctx) + return context.WithValue(ctx, Key{}, + informers.NewSharedInformerFactory(kc, controller.GetResyncPeriod(ctx))) +} + +// Get extracts the Kubernetes InformerFactory from the context. +func Get(ctx context.Context) informers.SharedInformerFactory { + untyped := ctx.Value(Key{}) + if untyped == nil { + return nil + } + return untyped.(informers.SharedInformerFactory) +} diff --git a/vendor/github.com/knative/pkg/injection/informers/kubeinformers/factory/fake/fake.go b/vendor/github.com/knative/pkg/injection/informers/kubeinformers/factory/fake/fake.go new file mode 100644 index 0000000000..7588aec5a9 --- /dev/null +++ b/vendor/github.com/knative/pkg/injection/informers/kubeinformers/factory/fake/fake.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 fake + +import ( + "context" + + "k8s.io/client-go/informers" + + "github.com/knative/pkg/controller" + "github.com/knative/pkg/injection" + "github.com/knative/pkg/injection/clients/kubeclient/fake" + "github.com/knative/pkg/injection/informers/kubeinformers/factory" +) + +var Get = factory.Get + +func init() { + injection.Fake.RegisterInformerFactory(withInformerFactory) +} + +func withInformerFactory(ctx context.Context) context.Context { + kc := fake.Get(ctx) + return context.WithValue(ctx, factory.Key{}, + informers.NewSharedInformerFactory(kc, controller.GetResyncPeriod(ctx))) +} diff --git a/vendor/github.com/knative/pkg/injection/interface.go b/vendor/github.com/knative/pkg/injection/interface.go new file mode 100644 index 0000000000..6a0df357e3 --- /dev/null +++ b/vendor/github.com/knative/pkg/injection/interface.go @@ -0,0 +1,90 @@ +/* +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" + + "github.com/knative/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 + + // 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 + + // RegisterInformer registers a new injector callback for associating + // a new informer with a context. + RegisterInformer(InformerInjector) + + // GetInformers fetches all of the registered informer injectors. + GetInformers() []InformerInjector + + // 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. + // TODO(mattmoor): Consider setting up and starting controllers? + SetupInformers(context.Context, *rest.Config) (context.Context, []controller.Informer) + + // RegisterController registers a new injector callback for associating + // a new controller with a context. + RegisterController(ControllerInjector) + + // GetControllers fetches all of the registered controller injectors. + GetControllers() []ControllerInjector +} + +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{} + + // 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 + factories []InformerFactoryInjector + informers []InformerInjector + controllers []ControllerInjector +} diff --git a/vendor/github.com/knative/pkg/injection/sharedmain/main.go b/vendor/github.com/knative/pkg/injection/sharedmain/main.go new file mode 100644 index 0000000000..8463a5b6d3 --- /dev/null +++ b/vendor/github.com/knative/pkg/injection/sharedmain/main.go @@ -0,0 +1,121 @@ +/* +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 sharedmain + +import ( + "context" + "flag" + "log" + + "k8s.io/client-go/rest" + "k8s.io/client-go/tools/clientcmd" + + // Uncomment the following line to load the gcp plugin (only required to authenticate against GKE clusters). + _ "k8s.io/client-go/plugin/pkg/client/auth/gcp" + + "github.com/knative/pkg/configmap" + "github.com/knative/pkg/controller" + "github.com/knative/pkg/injection" + "github.com/knative/pkg/injection/clients/kubeclient" + "github.com/knative/pkg/logging" + "github.com/knative/pkg/metrics" + "github.com/knative/pkg/signals" + "github.com/knative/pkg/system" + "go.uber.org/zap" +) + +func Main() { + // The default component name is "controller" + MainWithComponent("controller") +} + +func MainWithComponent(component string) { + // Set up signals so we handle the first shutdown signal gracefully. + MainWithContext(signals.NewContext(), component) +} + +func MainWithContext(ctx context.Context, component string) { + var ( + masterURL = flag.String("master", "", "The address of the Kubernetes API server. Overrides any value in kubeconfig. Only required if out-of-cluster.") + kubeconfig = flag.String("kubeconfig", "", "Path to a kubeconfig. Only required if out-of-cluster.") + ) + flag.Parse() + + cfg, err := clientcmd.BuildConfigFromFlags(*masterURL, *kubeconfig) + if err != nil { + log.Fatal("Error building kubeconfig", err) + } + MainWithConfig(ctx, component, cfg) +} + +func MainWithConfig(ctx context.Context, component string, cfg *rest.Config) { + // Set up our logger. + loggingConfigMap, err := configmap.Load("/etc/config-logging") + if err != nil { + log.Fatal("Error loading logging configuration:", err) + } + loggingConfig, err := logging.NewConfigFromMap(loggingConfigMap) + if err != nil { + log.Fatal("Error parsing logging configuration:", err) + } + logger, atomicLevel := logging.NewLoggerFromConfig(loggingConfig, component) + defer flush(logger) + ctx = logging.WithLogger(ctx, logger) + + logger.Infof("Registering %d clients", len(injection.Default.GetClients())) + logger.Infof("Registering %d informer factories", len(injection.Default.GetInformerFactories())) + logger.Infof("Registering %d informers", len(injection.Default.GetInformers())) + logger.Infof("Registering %d controllers", len(injection.Default.GetControllers())) + + // Adjust our client's rate limits based on the number of controller's we are running. + cfg.QPS = float32(len(injection.Default.GetControllers())) * rest.DefaultQPS + cfg.Burst = len(injection.Default.GetControllers()) * rest.DefaultBurst + + ctx, informers := injection.Default.SetupInformers(ctx, cfg) + + // TODO(mattmoor): This should itself take a context and be injection-based. + cmw := configmap.NewInformedWatcher(kubeclient.Get(ctx), system.Namespace()) + + // Based on the reconcilers we have linked, build up the set of controllers to run. + controllers := make([]*controller.Impl, 0, len(injection.Default.GetControllers())) + for _, cf := range injection.Default.GetControllers() { + controllers = append(controllers, cf(ctx, cmw)) + } + + // Watch the logging config map and dynamically update logging levels. + cmw.Watch(logging.ConfigMapName(), logging.UpdateLevelFromConfigMap(logger, atomicLevel, component)) + // Watch the observability config map and dynamically update metrics exporter. + cmw.Watch(metrics.ConfigMapName(), metrics.UpdateExporterFromConfigMap(component, logger)) + if err := cmw.Start(ctx.Done()); err != nil { + logger.Fatalw("failed to start configuration manager", zap.Error(err)) + } + + // Start all of the informers and wait for them to sync. + logger.Info("Starting informers.") + if err := controller.StartInformers(ctx.Done(), informers...); err != nil { + logger.Fatalw("Failed to start informers", err) + } + + // Start all of the controllers. + logger.Info("Starting controllers...") + controller.StartAll(ctx.Done(), controllers...) +} + +func flush(logger *zap.SugaredLogger) { + logger.Sync() + metrics.FlushExporter() +} diff --git a/vendor/github.com/knative/pkg/kmeta/OWNERS b/vendor/github.com/knative/pkg/kmeta/OWNERS new file mode 100644 index 0000000000..29b0d9f256 --- /dev/null +++ b/vendor/github.com/knative/pkg/kmeta/OWNERS @@ -0,0 +1,4 @@ +# The OWNERS file is used by prow to automatically merge approved PRs. + +approvers: +- kmeta-approvers diff --git a/vendor/github.com/knative/pkg/logging/OWNERS b/vendor/github.com/knative/pkg/logging/OWNERS new file mode 100644 index 0000000000..fa4854ba0a --- /dev/null +++ b/vendor/github.com/knative/pkg/logging/OWNERS @@ -0,0 +1,4 @@ +# The OWNERS file is used by prow to automatically merge approved PRs. + +approvers: +- logging-approvers diff --git a/vendor/github.com/knative/pkg/metrics/OWNERS b/vendor/github.com/knative/pkg/metrics/OWNERS new file mode 100644 index 0000000000..6d3966df44 --- /dev/null +++ b/vendor/github.com/knative/pkg/metrics/OWNERS @@ -0,0 +1,4 @@ +# The OWNERS file is used by prow to automatically merge approved PRs. + +approvers: +- metrics-approvers diff --git a/vendor/github.com/knative/pkg/metrics/testing/config.go b/vendor/github.com/knative/pkg/metrics/testing/config.go new file mode 100644 index 0000000000..5b19816d77 --- /dev/null +++ b/vendor/github.com/knative/pkg/metrics/testing/config.go @@ -0,0 +1,27 @@ +/* +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 + + https://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 testing + +import ( + "os" + + "github.com/knative/pkg/metrics" +) + +func init() { + os.Setenv(metrics.DomainEnv, "knative.dev/testing") +} diff --git a/vendor/github.com/knative/pkg/ptr/doc.go b/vendor/github.com/knative/pkg/ptr/doc.go new file mode 100644 index 0000000000..1ebcea2845 --- /dev/null +++ b/vendor/github.com/knative/pkg/ptr/doc.go @@ -0,0 +1,18 @@ +/* +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 ptr holds utilities for taking pointer references to values. +package ptr diff --git a/vendor/github.com/knative/pkg/ptr/ptr.go b/vendor/github.com/knative/pkg/ptr/ptr.go new file mode 100644 index 0000000000..3564647338 --- /dev/null +++ b/vendor/github.com/knative/pkg/ptr/ptr.go @@ -0,0 +1,41 @@ +/* +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 ptr + +// Int32 is a helper for turning integers into pointers for use in +// API types that want *int32. +func Int32(i int32) *int32 { + return &i +} + +// Int64 is a helper for turning integers into pointers for use in +// API types that want *int64. +func Int64(i int64) *int64 { + return &i +} + +// Bool is a helper for turning bools into pointers for use in +// API types that want *bool. +func Bool(b bool) *bool { + return &b +} + +// String is a helper for turning strings into pointers for use in +// API types that want *string. +func String(s string) *string { + return &s +} diff --git a/vendor/github.com/knative/pkg/reconciler/testing/context.go b/vendor/github.com/knative/pkg/reconciler/testing/context.go new file mode 100644 index 0000000000..f9692c810f --- /dev/null +++ b/vendor/github.com/knative/pkg/reconciler/testing/context.go @@ -0,0 +1,35 @@ +/* +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 testing + +import ( + "context" + "testing" + + "k8s.io/client-go/rest" + "k8s.io/client-go/tools/record" + + "github.com/knative/pkg/controller" + "github.com/knative/pkg/injection" + logtesting "github.com/knative/pkg/logging/testing" +) + +func SetupFakeContext(t *testing.T) (context.Context, []controller.Informer) { + ctx := logtesting.TestContextWithLogger(t) + ctx = controller.WithEventRecorder(ctx, record.NewFakeRecorder(1000)) + return injection.Fake.SetupInformers(ctx, &rest.Config{}) +} diff --git a/vendor/github.com/knative/pkg/test/OWNERS b/vendor/github.com/knative/pkg/test/OWNERS new file mode 100644 index 0000000000..c50adc8493 --- /dev/null +++ b/vendor/github.com/knative/pkg/test/OWNERS @@ -0,0 +1,10 @@ +# The OWNERS file is used by prow to automatically merge approved PRs. + +approvers: +- productivity-approvers + +reviewers: +- productivity-reviewers + +labels: +- area/test-and-release diff --git a/vendor/github.com/knative/pkg/test/README.md b/vendor/github.com/knative/pkg/test/README.md new file mode 100644 index 0000000000..422e5ed60c --- /dev/null +++ b/vendor/github.com/knative/pkg/test/README.md @@ -0,0 +1,259 @@ +# Test + +This directory contains tests and testing docs. + +- [Test library](#test-library) contains code you can use in your `knative` + tests +- [Flags](#flags) added by [the test library](#test-library) +- [Unit tests](#running-unit-tests) currently reside in the codebase alongside + the code they test + +## Running unit tests + +To run all unit tests: + +```bash +go test ./... +``` + +## Test library + +You can use the test library in this dir to: + +- [Use common test flags](#use-common-test-flags) +- [Output logs](#output-logs) +- [Emit metrics](#emit-metrics) +- [Ensure test cleanup](#ensure-test-cleanup) + +### Use common test flags + +These flags are useful for running against an existing cluster, making use of +your existing +[environment setup](https://github.com/knative/serving/blob/master/DEVELOPMENT.md#environment-setup). + +By importing `github.com/knative/pkg/test` you get access to a global variable +called `test.Flags` which holds the values of +[the command line flags](/test/README.md#flags). + +```go +logger.Infof("Using namespace %s", test.Flags.Namespace) +``` + +_See [e2e_flags.go](./e2e_flags.go)._ + +### Output logs + +[When tests are run with `--logverbose` option](README.md#output-verbose-logs), +debug logs will be emitted to stdout. + +We are using a generic +[FormatLogger](https://github.com/knative/pkg/blob/master/test/logging/logging.go#L49) +that can be passed in any existing logger that satisfies it. Test can use the +generic [logging methods](https://golang.org/pkg/testing/#T) to log info and +error logs. All the common methods accept generic FormatLogger as a parameter +and tests can pass in `t.Logf` like this: + +```go +_, err = pkgTest.WaitForEndpointState( + clients.KubeClient, + t.Logf, + ...), +``` + +_See [logging.go](./logging/logging.go)._ + +### Emit metrics + +You can emit metrics from your tests using +[the opencensus library](https://github.com/census-instrumentation/opencensus-go), +which +[is being used inside Knative as well](https://github.com/knative/serving/blob/master/docs/telemetry.md). +These metrics will be emitted by the test if the test is run with +[the `--emitmetrics` option](#metrics-flag). + +You can record arbitrary metrics with +[`stats.Record`](https://github.com/census-instrumentation/opencensus-go#stats) +or measure latency by creating a instance of +[`trace.Span`](https://github.com/census-instrumentation/opencensus-go#traces) +by using the helper method [`logging.GetEmitableSpan()`](../logging/logger.go) + +```go +span := logging.GetEmitableSpan(context.Background(), "MyMetric") +``` + +- These traces will be emitted automatically by + [the generic crd polling functions](#check-knative-serving-resources). +- The traces are emitted by [a custom metric exporter](./logging/logging.go) + that uses the global logger instance. + +#### Metric format + +When a `trace` metric is emitted, the format is +`metric `. The name of the metric is +arbitrary and can be any string. The values are: + +- `metric` - Indicates this log is a metric +- `` - Arbitrary string identifying the metric +- `` - Unix time in nanoseconds when measurement started +- `` - Unix time in nanoseconds when measurement ended +- `` - The difference in ms between the startTime and endTime + +For example: + +```bash +metric WaitForConfigurationState/prodxiparjxt/ConfigurationUpdatedWithRevision 1529980772357637397 1529980772431586609 73.949212ms +``` + +_The [`Wait` methods](#check-knative-serving-resources) (which poll resources) +will prefix the metric names with the name of the function, and if applicable, +the name of the resource, separated by `/`. In the example above, +`WaitForConfigurationState` is the name of the function, and `prodxiparjxt` is +the name of the configuration resource being polled. +`ConfigurationUpdatedWithRevision` is the string passed to +`WaitForConfigurationState` by the caller to identify what state is being polled +for._ + +### Check Knative Serving resources + +_WARNING: this code also exists in +[`knative/serving`](https://github.com/knative/serving/blob/master/test/adding_tests.md#make-requests-against-deployed-services)._ + +After creating Knative Serving resources or making changes to them, you will +need to wait for the system to realize those changes. You can use the Knative +Serving CRD check and polling methods to check the resources are either in or +reach the desired state. + +The `WaitFor*` functions use the kubernetes +[`wait` package](https://godoc.org/k8s.io/apimachinery/pkg/util/wait). To poll +they use +[`PollImmediate`](https://godoc.org/k8s.io/apimachinery/pkg/util/wait#PollImmediate) +and the return values of the function you provide behave the same as +[`ConditionFunc`](https://godoc.org/k8s.io/apimachinery/pkg/util/wait#ConditionFunc): +a `bool` to indicate if the function should stop or continue polling, and an +`error` to indicate if there has been an error. + +For example, you can poll a `Configuration` object to find the name of the +`Revision` that was created for it: + +```go +var revisionName string +err := test.WaitForConfigurationState( + clients.ServingClient, configName, func(c *v1alpha1.Configuration) (bool, error) { + if c.Status.LatestCreatedRevisionName != "" { + revisionName = c.Status.LatestCreatedRevisionName + return true, nil + } + return false, nil + }, "ConfigurationUpdatedWithRevision") +``` + +_[Metrics will be emitted](#emit-metrics) for these `Wait` method tracking how +long test poll for._ + +_See [kube_checks.go](./kube_checks.go)._ + +### Ensure test cleanup + +To ensure your test is cleaned up, you should defer cleanup to execute after +your test completes and also ensure the cleanup occurs if the test is +interrupted: + +```go +defer tearDown(clients) +test.CleanupOnInterrupt(func() { tearDown(clients) }) +``` + +_See [cleanup.go](./cleanup.go)._ + +## Flags + +Importing [the test library](#test-library) adds flags that are useful for end +to end tests that need to run against a cluster. + +Tests importing [`github.com/knative/pkg/test`](#test-library) recognize these +flags: + +- [`--kubeconfig`](#specifying-kubeconfig) +- [`--cluster`](#specifying-cluster) +- [`--namespace`](#specifying-namespace) +- [`--logverbose`](#output-verbose-logs) +- [`--emitmetrics`](#metrics-flag) + +### Specifying kubeconfig + +By default the tests will use the +[kubeconfig file](https://kubernetes.io/docs/concepts/configuration/organize-cluster-access-kubeconfig/) +at `~/.kube/config`. If there is an error getting the current user, it will use +`kubeconfig` instead as the default value. You can specify a different config +file with the argument `--kubeconfig`. + +To run tests with a non-default kubeconfig file: + +```bash +go test ./test --kubeconfig /my/path/kubeconfig +``` + +### Specifying cluster + +The `--cluster` argument lets you use a different cluster than +[your specified kubeconfig's](#specifying-kubeconfig) active context. + +```bash +go test ./test --cluster your-cluster-name +``` + +The current cluster names can be obtained by running: + +```bash +kubectl config get-clusters +``` + +### Specifying ingress endpoint + +The `--ingressendpoint` argument lets you specify a static url to use as the +ingress server during tests. This is useful for Kubernetes configurations which +do not provide external IPs. + +```bash +go test ./test --ingressendpoint :32380 +``` + +### Specifying namespace + +The `--namespace` argument lets you specify the namespace to use for the tests. +By default, tests will use `serving-tests`. + +```bash +go test ./test --namespace your-namespace-name +``` + +### Output verbose logs + +The `--logverbose` argument lets you see verbose test logs and k8s logs. + +```bash +go test ./test --logverbose +``` + +### Metrics flag + +Running tests with the `--emitmetrics` argument will cause latency metrics to be +emitted by the tests. + +```bash +go test ./test --emitmetrics +``` + +- To add additional metrics to a test, see + [emitting metrics](https://github.com/knative/pkg/tree/master/test#emit-metrics). +- For more info on the format of the metrics, see + [metric format](https://github.com/knative/pkg/tree/master/test#emit-metrics). + +[minikube]: https://kubernetes.io/docs/setup/minikube/ + +--- + +Except as otherwise noted, the content of this page is licensed under the +[Creative Commons Attribution 4.0 License](https://creativecommons.org/licenses/by/4.0/), +and code samples are licensed under the +[Apache 2.0 License](https://www.apache.org/licenses/LICENSE-2.0). diff --git a/vendor/github.com/knative/pkg/test/cleanup.go b/vendor/github.com/knative/pkg/test/cleanup.go new file mode 100644 index 0000000000..aa2c860fd8 --- /dev/null +++ b/vendor/github.com/knative/pkg/test/cleanup.go @@ -0,0 +1,40 @@ +/* +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. +*/ + +// cleanup allows you to define a cleanup function that will be executed +// if your test is interrupted. + +package test + +import ( + "os" + "os/signal" + + "github.com/knative/pkg/test/logging" +) + +// CleanupOnInterrupt will execute the function cleanup if an interrupt signal is caught +func CleanupOnInterrupt(cleanup func(), logf logging.FormatLogger) { + c := make(chan os.Signal, 1) + signal.Notify(c, os.Interrupt) + go func() { + for range c { + logf("Test interrupted, cleaning up.") + cleanup() + os.Exit(1) + } + }() +} diff --git a/vendor/github.com/knative/pkg/test/clients.go b/vendor/github.com/knative/pkg/test/clients.go new file mode 100644 index 0000000000..fbd9e65836 --- /dev/null +++ b/vendor/github.com/knative/pkg/test/clients.go @@ -0,0 +1,114 @@ +/* +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. +*/ + +// This file contains an object which encapsulates k8s clients which are useful for e2e tests. + +package test + +import ( + "fmt" + "strings" + + "github.com/knative/pkg/test/logging" + "github.com/knative/pkg/test/spoof" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/kubernetes" + k8styped "k8s.io/client-go/kubernetes/typed/core/v1" + "k8s.io/client-go/rest" + "k8s.io/client-go/tools/clientcmd" +) + +// KubeClient holds instances of interfaces for making requests to kubernetes client. +type KubeClient struct { + Kube *kubernetes.Clientset +} + +// NewSpoofingClient returns a spoofing client to make requests +func NewSpoofingClient(client *KubeClient, logf logging.FormatLogger, domain string, resolvable bool) (*spoof.SpoofingClient, error) { + return spoof.New(client.Kube, logf, domain, resolvable, Flags.IngressEndpoint) +} + +// NewKubeClient instantiates and returns several clientsets required for making request to the +// kube client specified by the combination of clusterName and configPath. Clients can make requests within namespace. +func NewKubeClient(configPath string, clusterName string) (*KubeClient, error) { + cfg, err := BuildClientConfig(configPath, clusterName) + if err != nil { + return nil, err + } + + k, err := kubernetes.NewForConfig(cfg) + if err != nil { + return nil, err + } + return &KubeClient{Kube: k}, nil +} + +// BuildClientConfig builds the client config specified by the config path and the cluster name +func BuildClientConfig(kubeConfigPath string, clusterName string) (*rest.Config, error) { + overrides := clientcmd.ConfigOverrides{} + // Override the cluster name if provided. + if clusterName != "" { + overrides.Context.Cluster = clusterName + } + return clientcmd.NewNonInteractiveDeferredLoadingClientConfig( + &clientcmd.ClientConfigLoadingRules{ExplicitPath: kubeConfigPath}, + &overrides).ClientConfig() +} + +// UpdateConfigMap updates the config map for specified @name with values +func (client *KubeClient) UpdateConfigMap(name string, configName string, values map[string]string) error { + configMap, err := client.GetConfigMap(name).Get(configName, metav1.GetOptions{}) + if err != nil { + return err + } + + for key, value := range values { + configMap.Data[key] = value + } + + _, err = client.GetConfigMap(name).Update(configMap) + return err +} + +// GetConfigMap gets the knative serving config map. +func (client *KubeClient) GetConfigMap(name string) k8styped.ConfigMapInterface { + return client.Kube.CoreV1().ConfigMaps(name) +} + +// CreatePod will create a Pod +func (client *KubeClient) CreatePod(pod *corev1.Pod) (*corev1.Pod, error) { + pods := client.Kube.CoreV1().Pods(pod.GetNamespace()) + return pods.Create(pod) +} + +// PodLogs returns Pod logs for given Pod and Container in the namespace +func (client *KubeClient) PodLogs(podName, containerName, namespace string) ([]byte, error) { + pods := client.Kube.CoreV1().Pods(namespace) + podList, err := pods.List(metav1.ListOptions{}) + if err != nil { + return nil, err + } + for _, pod := range podList.Items { + if strings.Contains(pod.Name, podName) { + result := pods.GetLogs(pod.Name, &corev1.PodLogOptions{ + Container: containerName, + }).Do() + return result.Raw() + } + } + return nil, fmt.Errorf("Could not find logs for %s/%s", podName, containerName) +} diff --git a/vendor/github.com/knative/pkg/test/crd.go b/vendor/github.com/knative/pkg/test/crd.go new file mode 100644 index 0000000000..ac74d09a79 --- /dev/null +++ b/vendor/github.com/knative/pkg/test/crd.go @@ -0,0 +1,95 @@ +/* +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. +*/ + +// This file contains functions that construct boilerplate CRD definitions. + +package test + +import ( + corev1 "k8s.io/api/core/v1" + rbacv1 "k8s.io/api/rbac/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +const ( + nginxPort = 80 + nginxName = "nginx" + nginxImage = "nginx:1.7.9" +) + +// ServiceAccount returns ServiceAccount object in given namespace +func ServiceAccount(name string, namespace string) *corev1.ServiceAccount { + return &corev1.ServiceAccount{ + ObjectMeta: metav1.ObjectMeta{ + Name: name, + Namespace: namespace, + }, + } +} + +// ClusterRoleBinding returns ClusterRoleBinding for given subject and role +func ClusterRoleBinding(name string, namespace string, serviceAccount string, role string) *rbacv1.ClusterRoleBinding { + return &rbacv1.ClusterRoleBinding{ + ObjectMeta: metav1.ObjectMeta{ + Name: name, + }, + Subjects: []rbacv1.Subject{ + { + Kind: "ServiceAccount", + Name: serviceAccount, + Namespace: namespace, + }, + }, + RoleRef: rbacv1.RoleRef{ + Kind: "ClusterRole", + Name: role, + APIGroup: "rbac.authorization.k8s.io", + }, + } +} + +// CoreV1ObjectReference returns a corev1.ObjectReference for the given name, kind and apiversion +func CoreV1ObjectReference(kind, apiversion, name string) *corev1.ObjectReference { + return &corev1.ObjectReference{ + Kind: kind, + APIVersion: apiversion, + Name: name, + } +} + +// NginxPod returns nginx pod defined in given namespace +func NginxPod(namespace string) *corev1.Pod { + return &corev1.Pod{ + ObjectMeta: metav1.ObjectMeta{ + Name: nginxName, + Namespace: namespace, + Annotations: map[string]string{"sidecar.istio.io/inject": "true"}, + }, + Spec: corev1.PodSpec{ + Containers: []corev1.Container{ + { + Name: nginxName, + Image: nginxImage, + Ports: []corev1.ContainerPort{ + { + ContainerPort: nginxPort, + }, + }, + }, + }, + }, + } +} diff --git a/vendor/github.com/knative/pkg/test/e2e_flags.go b/vendor/github.com/knative/pkg/test/e2e_flags.go new file mode 100644 index 0000000000..b5d911fdf5 --- /dev/null +++ b/vendor/github.com/knative/pkg/test/e2e_flags.go @@ -0,0 +1,82 @@ +/* +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. +*/ + +// This file contains logic to encapsulate flags which are needed to specify +// what cluster, etc. to use for e2e tests. + +package test + +import ( + "flag" + "fmt" + "os" + "os/user" + "path" +) + +// Flags holds the command line flags or defaults for settings in the user's environment. +// See EnvironmentFlags for a list of supported fields. +var Flags = initializeFlags() + +// EnvironmentFlags define the flags that are needed to run the e2e tests. +type EnvironmentFlags struct { + Cluster string // K8s cluster (defaults to cluster in kubeconfig) + Kubeconfig string // Path to kubeconfig (defaults to ./kube/config) + Namespace string // K8s namespace (blank by default, to be overwritten by test suite) + IngressEndpoint string // Host to use for ingress endpoint + LogVerbose bool // Enable verbose logging + EmitMetrics bool // Emit metrics + DockerRepo string // Docker repo (defaults to $KO_DOCKER_REPO) + Tag string // Tag for test images +} + +func initializeFlags() *EnvironmentFlags { + var f EnvironmentFlags + flag.StringVar(&f.Cluster, "cluster", "", + "Provide the cluster to test against. Defaults to the current cluster in kubeconfig.") + + var defaultKubeconfig string + if usr, err := user.Current(); err == nil { + defaultKubeconfig = path.Join(usr.HomeDir, ".kube/config") + } + + flag.StringVar(&f.Kubeconfig, "kubeconfig", defaultKubeconfig, + "Provide the path to the `kubeconfig` file you'd like to use for these tests. The `current-context` will be used.") + + flag.StringVar(&f.Namespace, "namespace", "", + "Provide the namespace you would like to use for these tests.") + + flag.StringVar(&f.IngressEndpoint, "ingressendpoint", "", "Provide a static endpoint url to the ingress server used during tests.") + + flag.BoolVar(&f.LogVerbose, "logverbose", false, + "Set this flag to true if you would like to see verbose logging.") + + flag.BoolVar(&f.EmitMetrics, "emitmetrics", false, + "Set this flag to true if you would like tests to emit metrics, e.g. latency of resources being realized in the system.") + + defaultRepo := os.Getenv("KO_DOCKER_REPO") + flag.StringVar(&f.DockerRepo, "dockerrepo", defaultRepo, + "Provide the uri of the docker repo you have uploaded the test image to using `uploadtestimage.sh`. Defaults to $KO_DOCKER_REPO") + + flag.StringVar(&f.Tag, "tag", "latest", "Provide the version tag for the test images.") + + return &f +} + +// ImagePath is a helper function to prefix image name with repo and suffix with tag +func ImagePath(name string) string { + return fmt.Sprintf("%s/%s:%s", Flags.DockerRepo, name, Flags.Tag) +} diff --git a/vendor/github.com/knative/pkg/test/helpers/data.go b/vendor/github.com/knative/pkg/test/helpers/data.go new file mode 100644 index 0000000000..e982b2c33e --- /dev/null +++ b/vendor/github.com/knative/pkg/test/helpers/data.go @@ -0,0 +1,77 @@ +/* +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 helpers + +import ( + "math/rand" + "strings" + "time" + "unicode" +) + +const ( + letterBytes = "abcdefghijklmnopqrstuvwxyz" + randSuffixLen = 8 + sep = '-' +) + +func init() { + rand.Seed(time.Now().UTC().UnixNano()) +} + +// AppendRandomString will generate a random string that begins with prefix. +// This is useful if you want to make sure that your tests can run at the same +// time against the same environment without conflicting. +// This method will use "-" as the separator between the prefix and +// the random suffix. +// This method will seed rand with the current time when the package is initialized. +func AppendRandomString(prefix string) string { + suffix := make([]byte, randSuffixLen) + + for i := range suffix { + suffix[i] = letterBytes[rand.Intn(len(letterBytes))] + } + + return strings.Join([]string{prefix, string(suffix)}, string(sep)) +} + +// MakeK8sNamePrefix converts each chunk of non-alphanumeric character into a single dash +// and also convert camelcase tokens into dash-delimited lowercase tokens. +func MakeK8sNamePrefix(s string) string { + var sb strings.Builder + newToken := false + for _, c := range s { + if !(unicode.IsLetter(c) || unicode.IsNumber(c)) { + newToken = true + continue + } + if sb.Len() > 0 && (newToken || unicode.IsUpper(c)) { + sb.WriteRune(sep) + } + sb.WriteRune(unicode.ToLower(c)) + newToken = false + } + return sb.String() +} + +// GetBaseFuncName returns the baseFuncName parsed from the fullFuncName. +// eg. test/e2e.TestMain will return TestMain. +func GetBaseFuncName(fullFuncName string) string { + baseFuncName := fullFuncName[strings.LastIndex(fullFuncName, "/")+1:] + baseFuncName = baseFuncName[strings.LastIndex(baseFuncName, ".")+1:] + return baseFuncName +} diff --git a/vendor/github.com/knative/pkg/test/ingress/ingress.go b/vendor/github.com/knative/pkg/test/ingress/ingress.go new file mode 100644 index 0000000000..cea5da5cb3 --- /dev/null +++ b/vendor/github.com/knative/pkg/test/ingress/ingress.go @@ -0,0 +1,72 @@ +/* +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 ingress + +import ( + "fmt" + "os" + + v1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/kubernetes" +) + +const ( + // TODO(tcnghia): These probably shouldn't be hard-coded here? + istioIngressNamespace = "istio-system" + istioIngressName = "istio-ingressgateway" +) + +// GetIngressEndpoint gets the endpoint IP or hostname to use for the service. +func GetIngressEndpoint(kubeClientset *kubernetes.Clientset) (*string, error) { + ingressName := istioIngressName + if gatewayOverride := os.Getenv("GATEWAY_OVERRIDE"); gatewayOverride != "" { + ingressName = gatewayOverride + } + ingressNamespace := istioIngressNamespace + if gatewayNsOverride := os.Getenv("GATEWAY_NAMESPACE_OVERRIDE"); gatewayNsOverride != "" { + ingressNamespace = gatewayNsOverride + } + + ingress, err := kubeClientset.CoreV1().Services(ingressNamespace).Get(ingressName, metav1.GetOptions{}) + if err != nil { + return nil, err + } + endpoint, err := EndpointFromService(ingress) + if err != nil { + return nil, err + } + return &endpoint, nil +} + +// EndpointFromService extracts the endpoint from the service's ingress. +func EndpointFromService(svc *v1.Service) (string, error) { + ingresses := svc.Status.LoadBalancer.Ingress + if len(ingresses) != 1 { + return "", fmt.Errorf("Expected exactly one ingress load balancer, instead had %d: %v", len(ingresses), ingresses) + } + itu := ingresses[0] + + switch { + case itu.IP != "": + return itu.IP, nil + case itu.Hostname != "": + return itu.Hostname, nil + default: + return "", fmt.Errorf("Expected ingress loadbalancer IP or hostname for %s to be set, instead was empty", svc.Name) + } +} diff --git a/vendor/github.com/knative/pkg/test/kube_checks.go b/vendor/github.com/knative/pkg/test/kube_checks.go new file mode 100644 index 0000000000..1b78914f5e --- /dev/null +++ b/vendor/github.com/knative/pkg/test/kube_checks.go @@ -0,0 +1,132 @@ +/* +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. +*/ + +// kube_checks contains functions which poll Kubernetes objects until +// they get into the state desired by the caller or time out. + +package test + +import ( + "context" + "fmt" + "strings" + "time" + + "github.com/knative/pkg/test/logging" + appsv1 "k8s.io/api/apps/v1" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/util/wait" + k8styped "k8s.io/client-go/kubernetes/typed/core/v1" +) + +const ( + interval = 1 * time.Second + podTimeout = 8 * time.Minute + logTimeout = 1 * time.Minute +) + +// WaitForDeploymentState polls the status of the Deployment called name +// from client every interval until inState returns `true` indicating it +// is done, returns an error or timeout. desc will be used to name the metric +// that is emitted to track how long it took for name to get into the state checked by inState. +func WaitForDeploymentState(client *KubeClient, name string, inState func(d *appsv1.Deployment) (bool, error), desc string, namespace string, timeout time.Duration) error { + d := client.Kube.AppsV1().Deployments(namespace) + span := logging.GetEmitableSpan(context.Background(), fmt.Sprintf("WaitForDeploymentState/%s/%s", name, desc)) + defer span.End() + + return wait.PollImmediate(interval, timeout, func() (bool, error) { + d, err := d.Get(name, metav1.GetOptions{}) + if err != nil { + return true, err + } + return inState(d) + }) +} + +// WaitForPodListState polls the status of the PodList +// from client every interval until inState returns `true` indicating it +// is done, returns an error or timeout. desc will be used to name the metric +// that is emitted to track how long it took to get into the state checked by inState. +func WaitForPodListState(client *KubeClient, inState func(p *corev1.PodList) (bool, error), desc string, namespace string) error { + p := client.Kube.CoreV1().Pods(namespace) + span := logging.GetEmitableSpan(context.Background(), fmt.Sprintf("WaitForPodListState/%s", desc)) + defer span.End() + + return wait.PollImmediate(interval, podTimeout, func() (bool, error) { + p, err := p.List(metav1.ListOptions{}) + if err != nil { + return true, err + } + return inState(p) + }) +} + +// GetConfigMap gets the configmaps for a given namespace +func GetConfigMap(client *KubeClient, namespace string) k8styped.ConfigMapInterface { + return client.Kube.CoreV1().ConfigMaps(namespace) +} + +// DeploymentScaledToZeroFunc returns a func that evaluates if a deployment has scaled to 0 pods +func DeploymentScaledToZeroFunc() func(d *appsv1.Deployment) (bool, error) { + return func(d *appsv1.Deployment) (bool, error) { + return d.Status.ReadyReplicas == 0, nil + } +} + +// WaitForLogContent waits until logs for given Pod/Container include the given content. +// If the content is not present within timeout it returns error. +func WaitForLogContent(client *KubeClient, podName, containerName, namespace, content string) error { + return wait.PollImmediate(interval, logTimeout, func() (bool, error) { + logs, err := client.PodLogs(podName, containerName, namespace) + if err != nil { + return true, err + } + return strings.Contains(string(logs), content), nil + }) +} + +// WaitForAllPodsRunning waits for all the pods to be in running state +func WaitForAllPodsRunning(client *KubeClient, namespace string) error { + return WaitForPodListState(client, PodsRunning, "PodsAreRunning", namespace) +} + +// WaitForPodRunning waits for the given pod to be in running state +func WaitForPodRunning(client *KubeClient, name string, namespace string) error { + p := client.Kube.CoreV1().Pods(namespace) + return wait.PollImmediate(interval, podTimeout, func() (bool, error) { + p, err := p.Get(name, metav1.GetOptions{}) + if err != nil { + return true, err + } + return PodRunning(p), nil + }) +} + +// PodsRunning will check the status conditions of the pod list and return true all pods are Running +func PodsRunning(podList *corev1.PodList) (bool, error) { + for _, pod := range podList.Items { + if isRunning := PodRunning(&pod); !isRunning { + return false, nil + } + } + return true, nil +} + +// PodRunning will check the status conditions of the pod and return true if it's Running +func PodRunning(pod *corev1.Pod) bool { + return pod.Status.Phase == corev1.PodRunning || pod.Status.Phase == corev1.PodSucceeded +} diff --git a/vendor/github.com/knative/pkg/test/logging/logging.go b/vendor/github.com/knative/pkg/test/logging/logging.go new file mode 100644 index 0000000000..2c641bd7a9 --- /dev/null +++ b/vendor/github.com/knative/pkg/test/logging/logging.go @@ -0,0 +1,146 @@ +/* +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. +*/ + +// logging.go contains the logic to configure and interact with the +// logging and metrics libraries. + +package logging + +import ( + "context" + "flag" + "fmt" + "strings" + "time" + + "github.com/davecgh/go-spew/spew" + "github.com/golang/glog" + "github.com/knative/pkg/logging" + "go.opencensus.io/stats/view" + "go.opencensus.io/trace" + "go.uber.org/zap" +) + +const ( + // VerboseLogLevel defines verbose log level as 10 + VerboseLogLevel glog.Level = 10 + + // 1 second was chosen arbitrarily + metricViewReportingPeriod = 1 * time.Second + + // prefix attached to metric name that indicates to the + // ExportSpan method that span needs to be emitted. + emitableSpanNamePrefix = "emitspan-" +) + +// FormatLogger is a printf style function for logging in tests. +type FormatLogger func(template string, args ...interface{}) + +var logger *zap.SugaredLogger + +var exporter *zapMetricExporter + +// zapMetricExporter is a stats and trace exporter that logs the +// exported data to the provided (probably test specific) zap logger. +// It conforms to the view.Exporter and trace.Exporter interfaces. +type zapMetricExporter struct { + logger *zap.SugaredLogger +} + +// ExportView will emit the view data vd (i.e. the stats that have been +// recorded) to the zap logger. +func (e *zapMetricExporter) ExportView(vd *view.Data) { + // We are not currently consuming these metrics, so for now we'll juse + // dump the view.Data object as is. + e.logger.Debug(spew.Sprint(vd)) +} + +// GetEmitableSpan starts and returns a trace.Span with a name that +// is used by the ExportSpan method to emit the span. +func GetEmitableSpan(ctx context.Context, metricName string) *trace.Span { + _, span := trace.StartSpan(ctx, emitableSpanNamePrefix+metricName) + return span +} + +// ExportSpan will emit the trace data to the zap logger. The span is emitted +// only if the metric name is prefix with emitableSpanNamePrefix constant. +func (e *zapMetricExporter) ExportSpan(vd *trace.SpanData) { + if strings.HasPrefix(vd.Name, emitableSpanNamePrefix) { + duration := vd.EndTime.Sub(vd.StartTime) + // We will start the log entry with `metric` to identify it as a metric for parsing + e.logger.Infof("metric %s %d %d %s", vd.Name[len(emitableSpanNamePrefix):], vd.StartTime.UnixNano(), vd.EndTime.UnixNano(), duration) + } +} + +func newLogger(logLevel string) *zap.SugaredLogger { + configJSONTemplate := `{ + "level": "%s", + "encoding": "console", + "outputPaths": ["stdout"], + "errorOutputPaths": ["stderr"], + "encoderConfig": { + "timeKey": "ts", + "messageKey": "message", + "levelKey": "level", + "nameKey": "logger", + "callerKey": "caller", + "messageKey": "msg", + "stacktraceKey": "stacktrace", + "lineEnding": "", + "levelEncoder": "", + "timeEncoder": "iso8601", + "durationEncoder": "", + "callerEncoder": "" + } + }` + configJSON := fmt.Sprintf(configJSONTemplate, logLevel) + l, _ := logging.NewLogger(string(configJSON), logLevel, zap.AddCallerSkip(1)) + return l +} + +// InitializeMetricExporter initializes the metric exporter logger +func InitializeMetricExporter(context string) { + // If there was a previously registered exporter, unregister it so we only emit + // the metrics in the current context. + if exporter != nil { + view.UnregisterExporter(exporter) + trace.UnregisterExporter(exporter) + } + + logger := logger.Named(context) + + exporter = &zapMetricExporter{logger: logger} + view.RegisterExporter(exporter) + trace.RegisterExporter(exporter) + + view.SetReportingPeriod(metricViewReportingPeriod) + trace.ApplyConfig(trace.Config{DefaultSampler: trace.AlwaysSample()}) +} + +// InitializeLogger initializes the base logger +func InitializeLogger(logVerbose bool) { + logLevel := "info" + if logVerbose { + // Both gLog and "go test" use -v flag. The code below is a work around so that we can still set v value for gLog + flag.StringVar(&logLevel, "logLevel", fmt.Sprint(VerboseLogLevel), "verbose log level") + flag.Lookup("v").Value.Set(logLevel) + glog.Infof("Logging set to verbose mode with logLevel %d", VerboseLogLevel) + + logLevel = "debug" + } + + logger = newLogger(logLevel) +} diff --git a/vendor/github.com/knative/pkg/test/monitoring/doc.go b/vendor/github.com/knative/pkg/test/monitoring/doc.go new file mode 100644 index 0000000000..b15d7c7262 --- /dev/null +++ b/vendor/github.com/knative/pkg/test/monitoring/doc.go @@ -0,0 +1,32 @@ +/* +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 monitoring provides common methods for all the monitoring components used in the tests + +This package exposes following methods: + + CheckPortAvailability(port int) error + Checks if the given port is available + GetPods(kubeClientset *kubernetes.Clientset, app string) (*v1.PodList, error) + Gets the list of pods that satisfy the lable selector app= + Cleanup(pid int) error + Kill the current port forwarding process running in the background + PortForward(logf logging.FormatLogger, podList *v1.PodList, localPort, remotePort int) (int, error) + Create a background process that will port forward the first pod from the local to remote port + It returns the process id for the background process created. +*/ +package monitoring diff --git a/vendor/github.com/knative/pkg/test/monitoring/monitoring.go b/vendor/github.com/knative/pkg/test/monitoring/monitoring.go new file mode 100644 index 0000000000..ccbad42b17 --- /dev/null +++ b/vendor/github.com/knative/pkg/test/monitoring/monitoring.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 monitoring + +import ( + "fmt" + "net" + "os" + "os/exec" + "strings" + + "github.com/knative/pkg/test/logging" + v1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/kubernetes" +) + +// CheckPortAvailability checks to see if the port is available on the machine. +func CheckPortAvailability(port int) error { + server, err := net.Listen("tcp", fmt.Sprintf(":%d", port)) + if err != nil { + // Port is likely taken + return err + } + server.Close() + + return nil +} + +// GetPods retrieves the current existing podlist for the app in monitoring namespace +// This uses app= as labelselector for selecting pods +func GetPods(kubeClientset *kubernetes.Clientset, app, namespace string) (*v1.PodList, error) { + pods, err := kubeClientset.CoreV1().Pods(namespace).List(metav1.ListOptions{LabelSelector: fmt.Sprintf("app=%s", app)}) + if err == nil && len(pods.Items) == 0 { + err = fmt.Errorf("No %s Pod found on the cluster. Ensure monitoring is switched on for your Knative Setup", app) + } + + return pods, err +} + +// Cleanup will clean the background process used for port forwarding +func Cleanup(pid int) error { + ps := os.Process{Pid: pid} + return ps.Kill() +} + +// PortForward sets up local port forward to the pod specified by the "app" label in the given namespace +func PortForward(logf logging.FormatLogger, podList *v1.PodList, localPort, remotePort int, namespace string) (int, error) { + podName := podList.Items[0].Name + portFwdCmd := fmt.Sprintf("kubectl port-forward %s %d:%d -n %s", podName, localPort, remotePort, namespace) + portFwdProcess, err := executeCmdBackground(logf, portFwdCmd) + + if err != nil { + return 0, fmt.Errorf("Failed to port forward: %v", err) + } + + logf("running %s port-forward in background, pid = %d", podName, portFwdProcess.Pid) + return portFwdProcess.Pid, nil +} + +// RunBackground starts a background process and returns the Process if succeed +func executeCmdBackground(logf logging.FormatLogger, format string, args ...interface{}) (*os.Process, error) { + cmd := fmt.Sprintf(format, args...) + logf("Executing command: %s", cmd) + parts := strings.Split(cmd, " ") + c := exec.Command(parts[0], parts[1:]...) // #nosec + if err := c.Start(); err != nil { + return nil, fmt.Errorf("%s command failed: %v", cmd, err) + } + return c.Process, nil +} diff --git a/vendor/github.com/knative/pkg/test/presubmit-tests.sh b/vendor/github.com/knative/pkg/test/presubmit-tests.sh new file mode 100755 index 0000000000..c3861911fe --- /dev/null +++ b/vendor/github.com/knative/pkg/test/presubmit-tests.sh @@ -0,0 +1,31 @@ +#!/usr/bin/env bash + +# 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. + +# This script runs the presubmit tests, in the right order. +# It is started by prow for each PR. +# For convenience, it can also be executed manually. + +# Markdown linting failures don't show up properly in Gubernator resulting +# in a net-negative contributor experience. +export DISABLE_MD_LINTING=1 + +source $(dirname $0)/../vendor/github.com/knative/test-infra/scripts/presubmit-tests.sh + +# TODO(#17): Write integration tests. + +# We use the default build, unit and integration test runners. + +main $@ diff --git a/vendor/github.com/knative/pkg/test/request.go b/vendor/github.com/knative/pkg/test/request.go new file mode 100644 index 0000000000..1735b6073a --- /dev/null +++ b/vendor/github.com/knative/pkg/test/request.go @@ -0,0 +1,154 @@ +/* +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. +*/ + +// request contains logic to make polling HTTP requests against an endpoint with optional host spoofing. + +package test + +import ( + "context" + "fmt" + "net/http" + "net/url" + "strings" + "time" + + "github.com/knative/pkg/test/logging" + "github.com/knative/pkg/test/spoof" +) + +// Retrying modifies a ResponseChecker to retry certain response codes. +func Retrying(rc spoof.ResponseChecker, codes ...int) spoof.ResponseChecker { + return func(resp *spoof.Response) (bool, error) { + for _, code := range codes { + if resp.StatusCode == code { + // Returning (false, nil) causes SpoofingClient.Poll to retry. + // sc.logger.Infof("Retrying for code %v", resp.StatusCode) + return false, nil + } + } + + // If we didn't match any retryable codes, invoke the ResponseChecker that we wrapped. + return rc(resp) + } +} + +// IsOneOfStatusCodes checks that the response code is equal to the given one. +func IsOneOfStatusCodes(codes ...int) spoof.ResponseChecker { + return func(resp *spoof.Response) (bool, error) { + for _, code := range codes { + if resp.StatusCode == code { + return true, nil + } + } + + return true, fmt.Errorf("status = %d, want one of: %v", resp.StatusCode, codes) + } +} + +// IsStatusOK checks that the response code is a 200. +func IsStatusOK(resp *spoof.Response) (bool, error) { + return IsOneOfStatusCodes(http.StatusOK)(resp) +} + +// MatchesBody checks that the *first* response body matches the "expected" body, otherwise failing. +func MatchesBody(expected string) spoof.ResponseChecker { + return func(resp *spoof.Response) (bool, error) { + if !strings.Contains(string(resp.Body), expected) { + // Returning (true, err) causes SpoofingClient.Poll to fail. + return true, fmt.Errorf("body = %s, want: %s", string(resp.Body), expected) + } + + return true, nil + } +} + +// EventuallyMatchesBody checks that the response body *eventually* matches the expected body. +// TODO(#1178): Delete me. We don't want to need this; we should be waiting for an appropriate Status instead. +func EventuallyMatchesBody(expected string) spoof.ResponseChecker { + return func(resp *spoof.Response) (bool, error) { + if !strings.Contains(string(resp.Body), expected) { + // Returning (false, nil) causes SpoofingClient.Poll to retry. + return false, nil + } + + return true, nil + } +} + +// MatchesAllOf combines multiple ResponseCheckers to one ResponseChecker with a logical AND. The +// checkers are executed in order. The first function to trigger an error or a retry will short-circuit +// the other functions (they will not be executed). +// +// This is useful for combining a body with a status check like: +// MatchesAllOf(IsStatusOK, MatchesBody("test")) +// +// The MatchesBody check will only be executed after the IsStatusOK has passed. +func MatchesAllOf(checkers ...spoof.ResponseChecker) spoof.ResponseChecker { + return func(resp *spoof.Response) (bool, error) { + for _, checker := range checkers { + done, err := checker(resp) + if err != nil || !done { + return done, err + } + } + return true, nil + } +} + +// WaitForEndpointState will poll an endpoint until inState indicates the state is achieved, +// or default timeout is reached. +// If resolvableDomain is false, it will use kubeClientset to look up the ingress and spoof +// the domain in the request headers, otherwise it will make the request directly to domain. +// desc will be used to name the metric that is emitted to track how long it took for the +// domain to get into the state checked by inState. Commas in `desc` must be escaped. +func WaitForEndpointState(kubeClient *KubeClient, logf logging.FormatLogger, theURL string, inState spoof.ResponseChecker, desc string, resolvable bool) (*spoof.Response, error) { + return WaitForEndpointStateWithTimeout(kubeClient, logf, theURL, inState, desc, resolvable, spoof.RequestTimeout) +} + +// WaitForEndpointStateWithTimeout will poll an endpoint until inState indicates the state is achieved +// or the provided timeout is achieved. +// If resolvableDomain is false, it will use kubeClientset to look up the ingress and spoof +// the domain in the request headers, otherwise it will make the request directly to domain. +// desc will be used to name the metric that is emitted to track how long it took for the +// domain to get into the state checked by inState. Commas in `desc` must be escaped. +func WaitForEndpointStateWithTimeout( + kubeClient *KubeClient, logf logging.FormatLogger, theURL string, inState spoof.ResponseChecker, + desc string, resolvable bool, timeout time.Duration) (*spoof.Response, error) { + defer logging.GetEmitableSpan(context.Background(), fmt.Sprintf("WaitForEndpointState/%s", desc)).End() + + // Try parsing the "theURL" with and without a scheme. + asURL, err := url.Parse(fmt.Sprintf("http://%s", theURL)) + if err != nil { + asURL, err = url.Parse(theURL) + if err != nil { + return nil, err + } + } + + req, err := http.NewRequest(http.MethodGet, asURL.String(), nil) + if err != nil { + return nil, err + } + + client, err := NewSpoofingClient(kubeClient, logf, asURL.Hostname(), resolvable) + if err != nil { + return nil, err + } + client.RequestTimeout = timeout + + return client.Poll(req, inState) +} diff --git a/vendor/github.com/knative/pkg/test/spoof/error_checks.go b/vendor/github.com/knative/pkg/test/spoof/error_checks.go new file mode 100644 index 0000000000..0cd2995ca2 --- /dev/null +++ b/vendor/github.com/knative/pkg/test/spoof/error_checks.go @@ -0,0 +1,52 @@ +/* +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. +*/ + +// spoof contains logic to make polling HTTP requests against an endpoint with optional host spoofing. + +package spoof + +import ( + "net" + "strings" +) + +func isTCPTimeout(e error) bool { + err, ok := e.(net.Error) + return err != nil && ok && err.Timeout() +} + +func isDNSError(err error) bool { + if err == nil { + return false + } + // Checking by casting to url.Error and casting the nested error + // seems to be not as robust as string check. + msg := strings.ToLower(err.Error()) + // Example error message: + // > Get http://this.url.does.not.exist: dial tcp: lookup this.url.does.not.exist on 127.0.0.1:53: no such host + return strings.Contains(msg, "no such host") || strings.Contains(msg, ":53") +} + +func isTCPConnectRefuse(err error) bool { + // The alternative for the string check is: + // errNo := (((err.(*url.Error)).Err.(*net.OpError)).Err.(*os.SyscallError).Err).(syscall.Errno) + // if errNo == syscall.Errno(0x6f) {...} + // But with assertions, of course. + if err != nil && strings.Contains(err.Error(), "connect: connection refused") { + return true + } + return false +} diff --git a/vendor/github.com/knative/pkg/test/spoof/spoof.go b/vendor/github.com/knative/pkg/test/spoof/spoof.go new file mode 100644 index 0000000000..f23d3049e1 --- /dev/null +++ b/vendor/github.com/knative/pkg/test/spoof/spoof.go @@ -0,0 +1,241 @@ +/* +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. +*/ + +// spoof contains logic to make polling HTTP requests against an endpoint with optional host spoofing. + +package spoof + +import ( + "fmt" + "io/ioutil" + "net/http" + "time" + + ingress "github.com/knative/pkg/test/ingress" + "github.com/knative/pkg/test/logging" + "github.com/knative/pkg/test/zipkin" + "github.com/pkg/errors" + "k8s.io/apimachinery/pkg/util/wait" + "k8s.io/client-go/kubernetes" + + "go.opencensus.io/plugin/ochttp" + "go.opencensus.io/plugin/ochttp/propagation/b3" + "go.opencensus.io/trace" +) + +const ( + requestInterval = 1 * time.Second + // RequestTimeout is the default timeout for the polling requests. + RequestTimeout = 5 * time.Minute + // Name of the temporary HTTP header that is added to http.Request to indicate that + // it is a SpoofClient.Poll request. This header is removed before making call to backend. + pollReqHeader = "X-Kn-Poll-Request-Do-Not-Trace" +) + +// Response is a stripped down subset of http.Response. The is primarily useful +// for ResponseCheckers to inspect the response body without consuming it. +// Notably, Body is a byte slice instead of an io.ReadCloser. +type Response struct { + Status string + StatusCode int + Header http.Header + Body []byte +} + +func (r *Response) String() string { + return fmt.Sprintf("status: %d, body: %s, headers: %v", r.StatusCode, string(r.Body), r.Header) +} + +// Interface defines the actions that can be performed by the spoofing client. +type Interface interface { + Do(*http.Request) (*Response, error) + Poll(*http.Request, ResponseChecker) (*Response, error) +} + +// https://medium.com/stupid-gopher-tricks/ensuring-go-interface-satisfaction-at-compile-time-1ed158e8fa17 +var _ Interface = (*SpoofingClient)(nil) + +// ResponseChecker is used to determine when SpoofinClient.Poll is done polling. +// This allows you to predicate wait.PollImmediate on the request's http.Response. +// +// See the apimachinery wait package: +// https://github.com/kubernetes/apimachinery/blob/cf7ae2f57dabc02a3d215f15ca61ae1446f3be8f/pkg/util/wait/wait.go#L172 +type ResponseChecker func(resp *Response) (done bool, err error) + +// SpoofingClient is a minimal HTTP client wrapper that spoofs the domain of requests +// for non-resolvable domains. +type SpoofingClient struct { + Client *http.Client + RequestInterval time.Duration + RequestTimeout time.Duration + + endpoint string + domain string + + logf logging.FormatLogger +} + +// New returns a SpoofingClient that rewrites requests if the target domain is not `resolveable`. +// It does this by looking up the ingress at construction time, so reusing a client will not +// follow the ingress if it moves (or if there are multiple ingresses). +// +// If that's a problem, see test/request.go#WaitForEndpointState for oneshot spoofing. +func New(kubeClientset *kubernetes.Clientset, logf logging.FormatLogger, domain string, resolvable bool, endpointOverride string) (*SpoofingClient, error) { + sc := SpoofingClient{ + Client: &http.Client{Transport: &ochttp.Transport{Propagation: &b3.HTTPFormat{}}}, // Using ochttp Transport required for zipkin-tracing + RequestInterval: requestInterval, + RequestTimeout: RequestTimeout, + logf: logf, + } + + if !resolvable { + e := &endpointOverride + if endpointOverride == "" { + var err error + // If the domain that the Route controller is configured to assign to Route.Status.Domain + // (the domainSuffix) is not resolvable, we need to retrieve the endpoint and spoof + // the Host in our requests. + e, err = ingress.GetIngressEndpoint(kubeClientset) + if err != nil { + return nil, err + } + } + + sc.endpoint = *e + sc.domain = domain + } else { + // If the domain is resolvable, we can use it directly when we make requests. + sc.endpoint = domain + } + + return &sc, nil +} + +// Do dispatches to the underlying http.Client.Do, spoofing domains as needed +// and transforming the http.Response into a spoof.Response. +// Each response is augmented with "ZipkinTraceID" header that identifies the zipkin trace corresponding to the request. +func (sc *SpoofingClient) Do(req *http.Request) (*Response, error) { + // Controls the Host header, for spoofing. + if sc.domain != "" { + req.Host = sc.domain + } + + // Controls the actual resolution. + if sc.endpoint != "" { + req.URL.Host = sc.endpoint + } + + // Starting span to capture zipkin trace. + traceContext, span := trace.StartSpan(req.Context(), "SpoofingClient-Trace") + defer span.End() + + // Check to see if the call to this method is coming from a Poll call. + logZipkinTrace := true + if req.Header.Get(pollReqHeader) != "" { + req.Header.Del(pollReqHeader) + logZipkinTrace = false + } + resp, err := sc.Client.Do(req.WithContext(traceContext)) + if err != nil { + return nil, err + } + + defer resp.Body.Close() + + resp.Header.Add(zipkin.ZipkinTraceIDHeader, span.SpanContext().TraceID.String()) + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + return nil, err + } + + spoofResp := &Response{ + Status: resp.Status, + StatusCode: resp.StatusCode, + Header: resp.Header, + Body: body, + } + + if logZipkinTrace { + sc.logZipkinTrace(spoofResp) + } + + return spoofResp, nil +} + +// Poll executes an http request until it satisfies the inState condition or encounters an error. +func (sc *SpoofingClient) Poll(req *http.Request, inState ResponseChecker) (*Response, error) { + var ( + resp *Response + err error + ) + + err = wait.PollImmediate(sc.RequestInterval, sc.RequestTimeout, func() (bool, error) { + // As we may do multiple Do calls as part of a single Poll we add this temporary header + // to the request to indicate to Do method not to log Zipkin trace, instead it is + // handled by this method itself. + req.Header.Add(pollReqHeader, "True") + resp, err = sc.Do(req) + if err != nil { + if isTCPTimeout(err) { + sc.logf("Retrying %s for TCP timeout %v", req.URL.String(), err) + return false, nil + } + // Retrying on DNS error, since we may be using xip.io or nip.io in tests. + if isDNSError(err) { + sc.logf("Retrying %s for DNS error %v", req.URL.String(), err) + return false, nil + } + // Repeat the poll on `connection refused` errors, which are usually transient Istio errors. + if isTCPConnectRefuse(err) { + sc.logf("Retrying %s for connection refused %v", req.URL.String(), err) + return false, nil + } + return true, err + } + + return inState(resp) + }) + + if resp != nil { + sc.logZipkinTrace(resp) + } + + if err != nil { + return resp, errors.Wrapf(err, "response: %s did not pass checks", resp) + } + return resp, nil +} + +// logZipkinTrace provides support to log Zipkin Trace for param: spoofResponse +// We only log Zipkin trace for HTTP server errors i.e for HTTP status codes between 500 to 600 +func (sc *SpoofingClient) logZipkinTrace(spoofResp *Response) { + if !zipkin.ZipkinTracingEnabled || spoofResp.StatusCode < http.StatusInternalServerError || spoofResp.StatusCode >= 600 { + return + } + + traceID := spoofResp.Header.Get(zipkin.ZipkinTraceIDHeader) + sc.logf("Logging Zipkin Trace for: %s", traceID) + + // Sleep to ensure all traces are correctly pushed on the backend. + time.Sleep(5 * time.Second) + + json, err := zipkin.JSONTrace(traceID) + if err != nil { + sc.logf("Error getting zipkin trace: %v", err) + } + + sc.logf("%s", json) +} diff --git a/vendor/github.com/knative/pkg/test/zipkin/doc.go b/vendor/github.com/knative/pkg/test/zipkin/doc.go new file mode 100644 index 0000000000..0ce3c54fdf --- /dev/null +++ b/vendor/github.com/knative/pkg/test/zipkin/doc.go @@ -0,0 +1,41 @@ +/* +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 zipkin adds Zipkin tracing support that can be used in conjunction with +SpoofingClient to log zipkin traces for requests that have encountered server errors +i.e HTTP request that have HTTP status between 500 to 600. + +This package exposes following methods: + + SetupZipkinTracing(*kubernetes.Clientset) error + SetupZipkinTracing sets up zipkin tracing by setting up port-forwarding from + localhost to zipkin pod on the cluster. On successful setup this method sets + an internal flag zipkinTracingEnabled to true. + + CleanupZipkinTracingSetup() error + CleanupZipkinTracingSetup cleans up zipkin tracing setup by cleaning up the + port-forwarding setup by call to SetupZipkinTracing. This method also sets + zipkinTracingEnabled flag to false. + +A general flow for a Test Suite to use Zipkin Tracing support is as follows: + + 1. Call SetupZipkinTracing(*kubernetes.Clientset) in TestMain. + 2. Use SpoofingClient to make HTTP requests. + 3. Call CleanupZipkinTracingSetup on cleanup after tests are executed. + +*/ +package zipkin diff --git a/vendor/github.com/knative/pkg/test/zipkin/util.go b/vendor/github.com/knative/pkg/test/zipkin/util.go new file mode 100644 index 0000000000..add07498f4 --- /dev/null +++ b/vendor/github.com/knative/pkg/test/zipkin/util.go @@ -0,0 +1,145 @@ +/* +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. +*/ + +//util has constants and helper methods useful for zipkin tracing support. + +package zipkin + +import ( + "bytes" + "encoding/json" + "io/ioutil" + "net/http" + "sync" + + "github.com/knative/pkg/test/logging" + "github.com/knative/pkg/test/monitoring" + "go.opencensus.io/trace" + "k8s.io/client-go/kubernetes" +) + +const ( + //ZipkinTraceIDHeader HTTP response header key to be used to store Zipkin Trace ID. + ZipkinTraceIDHeader = "ZIPKIN_TRACE_ID" + + // ZipkinPort is port exposed by the Zipkin Pod + // https://github.com/knative/serving/blob/master/config/monitoring/200-common/100-zipkin.yaml#L25 configures the Zipkin Port on the cluster. + ZipkinPort = 9411 + + // ZipkinTraceEndpoint port-forwarded zipkin endpoint + ZipkinTraceEndpoint = "http://localhost:9411/api/v2/trace/" + + // App is the name of this component. + // This will be used as a label selector + app = "zipkin" + + // Namespace we are using for istio components + istioNs = "istio-system" +) + +var ( + zipkinPortForwardPID int + + // ZipkinTracingEnabled variable indicating if zipkin tracing is enabled. + ZipkinTracingEnabled = false + + // sync.Once variable to ensure we execute zipkin setup only once. + setupOnce sync.Once + + // sync.Once variable to ensure we execute zipkin cleanup only if zipkin is setup and it is executed only once. + teardownOnce sync.Once +) + +// SetupZipkinTracing sets up zipkin tracing which involves: +// 1. Setting up port-forwarding from localhost to zipkin pod on the cluster +// (pid of the process doing Port-Forward is stored in a global variable). +// 2. Enable AlwaysSample config for tracing. +func SetupZipkinTracing(kubeClientset *kubernetes.Clientset, logf logging.FormatLogger) { + setupOnce.Do(func() { + if err := monitoring.CheckPortAvailability(ZipkinPort); err != nil { + logf("Zipkin port not available on the machine: %v", err) + return + } + + zipkinPods, err := monitoring.GetPods(kubeClientset, app, istioNs) + if err != nil { + logf("Error retrieving Zipkin pod details: %v", err) + return + } + + zipkinPortForwardPID, err = monitoring.PortForward(logf, zipkinPods, ZipkinPort, ZipkinPort, istioNs) + if err != nil { + logf("Error starting kubectl port-forward command: %v", err) + return + } + + logf("Zipkin port-forward process started with PID: %d", zipkinPortForwardPID) + + // Applying AlwaysSample config to ensure we propagate zipkin header for every request made by this client. + trace.ApplyConfig(trace.Config{DefaultSampler: trace.AlwaysSample()}) + logf("Successfully setup SpoofingClient for Zipkin Tracing") + ZipkinTracingEnabled = true + }) +} + +// CleanupZipkinTracingSetup cleans up the Zipkin tracing setup on the machine. This involves killing the process performing port-forward. +func CleanupZipkinTracingSetup(logf logging.FormatLogger) { + teardownOnce.Do(func() { + if !ZipkinTracingEnabled { + return + } + + if err := monitoring.Cleanup(zipkinPortForwardPID); err != nil { + logf("Encountered error killing port-forward process in CleanupZipkingTracingSetup() : %v", err) + return + } + + ZipkinTracingEnabled = false + }) +} + +// CheckZipkinPortAvailability checks to see if Zipkin Port is available on the machine. +// returns error if the port is not available. +func CheckZipkinPortAvailability() error { + return monitoring.CheckPortAvailability(ZipkinPort) +} + +// JSONTrace returns a trace for the given traceId in JSON format +func JSONTrace(traceID string) (string, error) { + // Check if zipkin port forwarding is setup correctly + if err := CheckZipkinPortAvailability(); err == nil { + return "", err + } + + resp, err := http.Get(ZipkinTraceEndpoint + traceID) + if err != nil { + return "", err + } + defer resp.Body.Close() + + trace, err := ioutil.ReadAll(resp.Body) + if err != nil { + return "", err + } + + var prettyJSON bytes.Buffer + err = json.Indent(&prettyJSON, trace, "", "\t") + if err != nil { + return "", err + } + + return prettyJSON.String(), nil +} diff --git a/vendor/github.com/knative/pkg/testing/doc.go b/vendor/github.com/knative/pkg/testing/doc.go new file mode 100644 index 0000000000..5862dfb062 --- /dev/null +++ b/vendor/github.com/knative/pkg/testing/doc.go @@ -0,0 +1,19 @@ +/* +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. +*/ + +// +k8s:deepcopy-gen=package +// +groupName=pkg.knative.dev +package testing diff --git a/vendor/github.com/knative/pkg/testing/inner_default_resource.go b/vendor/github.com/knative/pkg/testing/inner_default_resource.go new file mode 100644 index 0000000000..5ee6756484 --- /dev/null +++ b/vendor/github.com/knative/pkg/testing/inner_default_resource.go @@ -0,0 +1,157 @@ +/* +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 testing + +import ( + "context" + + "github.com/knative/pkg/apis" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// InnerDefaultResource is a simple resource that's compatible with our webhook. It differs from +// Resource by not omitting empty `spec`, so can change when it round trips +// JSON -> Golang type -> JSON. +type InnerDefaultResource struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + // Note that this does _not_ have omitempty. So when JSON is round tripped through the Golang + // type, `spec: {}` will automatically be injected. + Spec InnerDefaultSpec `json:"spec"` + + // Status is a simple status. + Status InnerDefaultStatus `json:"status,omitempty"` +} + +// InnerDefaultSpec is the spec for InnerDefaultResource. +type InnerDefaultSpec struct { + Generation int64 `json:"generation,omitempty"` + + FieldWithDefault string `json:"fieldWithDefault,omitempty"` + + // Deprecated: This field is deprecated. + DeprecatedField string `json:"field,omitempty"` + + SubFields *InnerDefaultSubSpec `json:"subfields,omitempty"` +} + +// InnerDefaultSubSpec is a helper to test strict deprecated validation. +type InnerDefaultSubSpec struct { + // Deprecated: This field is deprecated. + DeprecatedString string `json:"string,omitempty"` + + // Deprecated: This field is deprecated. + DeprecatedStringPtr *string `json:"stringPtr,omitempty"` + + // Deprecated: This field is deprecated. + DeprecatedInt int64 `json:"int,omitempty"` + + // Deprecated: This field is deprecated. + DeprecatedIntPtr *int64 `json:"intPtr,omitempty"` + + // Deprecated: This field is deprecated. + DeprecatedMap map[string]string `json:"map,omitempty"` + + // Deprecated: This field is deprecated. + DeprecatedSlice []string `json:"slice,omitempty"` + + // Deprecated: This field is deprecated. + DeprecatedStruct InnerDefaultStruct `json:"struct,omitempty"` + + // Deprecated: This field is deprecated. + DeprecatedStructPtr *InnerDefaultStruct `json:"structPtr,omitempty"` + + InlinedStruct `json:",inline"` + *InlinedPtrStruct `json:",inline"` + + // Deprecated: This field is deprecated. + DeprecatedNotJson string +} + +// Adding complication helper. +type InnerDefaultStruct struct { + FieldAsString string `json:"fieldAsString,omitempty"` + + // Deprecated: This field is deprecated. + DeprecatedField string `json:"field,omitempty"` +} + +type InlinedStruct struct { + // Deprecated: This field is deprecated. + DeprecatedField string `json:"fieldA,omitempty"` + *InlinedPtrStruct `json:",inline"` +} + +type InlinedPtrStruct struct { + // Deprecated: This field is deprecated. + DeprecatedField string `json:"fieldB,omitempty"` +} + +// InnerDefaultStatus is the status for InnerDefaultResource. +type InnerDefaultStatus struct { + FieldAsString string `json:"fieldAsString,omitempty"` +} + +// Check that ImmutableDefaultResource may be validated and defaulted. +var _ apis.Validatable = (*InnerDefaultResource)(nil) +var _ apis.Defaultable = (*InnerDefaultResource)(nil) + +// SetDefaults sets default values. +func (i *InnerDefaultResource) SetDefaults(ctx context.Context) { + i.Spec.SetDefaults(ctx) +} + +// SetDefaults sets default values. +func (cs *InnerDefaultSpec) SetDefaults(ctx context.Context) { + if cs.FieldWithDefault == "" { + cs.FieldWithDefault = "I'm a default." + } +} + +// Validate validates the resource. +func (i *InnerDefaultResource) Validate(ctx context.Context) *apis.FieldError { + var errs *apis.FieldError + if apis.IsInUpdate(ctx) { + org := apis.GetBaseline(ctx).(*InnerDefaultResource) + errs = apis.CheckDeprecatedUpdate(ctx, i.Spec, org.Spec).ViaField("spec") + if i.Spec.SubFields != nil { + var orgSubFields interface{} + if org != nil && org.Spec.SubFields != nil { + orgSubFields = org.Spec.SubFields + } + + errs = errs.Also(apis.CheckDeprecatedUpdate(ctx, i.Spec.SubFields, orgSubFields).ViaField("spec", "subFields")) + + var orgDepStruct interface{} + if orgSubFields != nil { + orgDepStruct = org.Spec.SubFields.DeprecatedStruct + } + + errs = errs.Also(apis.CheckDeprecatedUpdate(ctx, i.Spec.SubFields.DeprecatedStruct, orgDepStruct).ViaField("spec", "subFields", "deprecatedStruct")) + } + } else { + errs = apis.CheckDeprecated(ctx, i.Spec).ViaField("spec") + if i.Spec.SubFields != nil { + errs = errs.Also(apis.CheckDeprecated(ctx, i.Spec.SubFields).ViaField("spec", "subFields"). + Also(apis.CheckDeprecated(ctx, i.Spec.SubFields.DeprecatedStruct).ViaField("deprecatedStruct"))) + } + } + return errs +} diff --git a/vendor/github.com/knative/pkg/testing/register.go b/vendor/github.com/knative/pkg/testing/register.go new file mode 100644 index 0000000000..911c90fbdc --- /dev/null +++ b/vendor/github.com/knative/pkg/testing/register.go @@ -0,0 +1,42 @@ +/* +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 testing + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" +) + +// SchemeGroupVersion is group version used to register these objects +var SchemeGroupVersion = schema.GroupVersion{Group: "pkg.knative.dev", Version: "v2"} + +var ( + SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes) + AddToScheme = SchemeBuilder.AddToScheme +) + +// Adds the list of known types to Scheme. +func addKnownTypes(scheme *runtime.Scheme) error { + scheme.AddKnownTypes( + SchemeGroupVersion, + &Resource{}, + (&Resource{}).GetListType(), + ) + metav1.AddToGroupVersion(scheme, SchemeGroupVersion) + return nil +} diff --git a/vendor/github.com/knative/pkg/testing/resource.go b/vendor/github.com/knative/pkg/testing/resource.go new file mode 100644 index 0000000000..d553f8d47f --- /dev/null +++ b/vendor/github.com/knative/pkg/testing/resource.go @@ -0,0 +1,190 @@ +/* +Copyright 2017 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 testing + +import ( + "context" + "fmt" + + "github.com/knative/pkg/apis" + "github.com/knative/pkg/kmp" + + authenticationv1 "k8s.io/api/authentication/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" +) + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// Resource is a simple resource that's compatible with our webhook +type Resource struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec ResourceSpec `json:"spec,omitempty"` +} + +const ( + // CreatorAnnotation is the annotation that denotes the user that created the resource. + CreatorAnnotation = "testing.knative.dev/creator" + // UpdaterAnnotation is the annotation that denotes the user that last updated the resource. + UpdaterAnnotation = "testing.knative.dev/updater" +) + +// Check that Resource may be validated and defaulted. +var _ apis.Validatable = (*Resource)(nil) +var _ apis.Defaultable = (*Resource)(nil) +var _ apis.Immutable = (*Resource)(nil) +var _ apis.Listable = (*Resource)(nil) + +// ResourceSpec represents test resource spec. +type ResourceSpec struct { + FieldWithDefault string `json:"fieldWithDefault,omitempty"` + FieldWithContextDefault string `json:"fieldWithContextDefault,omitempty"` + FieldWithValidation string `json:"fieldWithValidation,omitempty"` + FieldThatsImmutable string `json:"fieldThatsImmutable,omitempty"` + FieldThatsImmutableWithDefault string `json:"fieldThatsImmutableWithDefault,omitempty"` +} + +// SetDefaults sets the defaults on the object. +func (c *Resource) SetDefaults(ctx context.Context) { + c.Spec.SetDefaults(ctx) + + if apis.IsInUpdate(ctx) { + old := apis.GetBaseline(ctx).(*Resource) + c.AnnotateUserInfo(ctx, old, apis.GetUserInfo(ctx)) + } else { + c.AnnotateUserInfo(ctx, nil, apis.GetUserInfo(ctx)) + } +} + +// AnnotateUserInfo satisfies the Annotatable interface. +func (c *Resource) AnnotateUserInfo(ctx context.Context, prev *Resource, ui *authenticationv1.UserInfo) { + a := c.ObjectMeta.GetAnnotations() + if a == nil { + a = map[string]string{} + } + userName := ui.Username + + // If previous is nil (i.e. this is `Create` operation), + // then we set both fields. + // Otherwise copy creator from the previous state. + if prev == nil { + a[CreatorAnnotation] = userName + } else { + // No spec update ==> bail out. + if ok, _ := kmp.SafeEqual(prev.Spec, c.Spec); ok { + if prev.ObjectMeta.GetAnnotations() != nil { + a[CreatorAnnotation] = prev.ObjectMeta.GetAnnotations()[CreatorAnnotation] + userName = prev.ObjectMeta.GetAnnotations()[UpdaterAnnotation] + } + } else { + if prev.ObjectMeta.GetAnnotations() != nil { + a[CreatorAnnotation] = prev.ObjectMeta.GetAnnotations()[CreatorAnnotation] + } + } + } + // Regardless of `old` set the updater. + a[UpdaterAnnotation] = userName + c.ObjectMeta.SetAnnotations(a) +} + +func (c *Resource) Validate(ctx context.Context) *apis.FieldError { + err := c.Spec.Validate(ctx).ViaField("spec") + + if apis.IsInUpdate(ctx) { + original := apis.GetBaseline(ctx).(*Resource) + err = err.Also(c.CheckImmutableFields(ctx, original)) + } + return err +} + +type onContextKey struct{} + +// WithValue returns a WithContext for attaching an OnContext with the given value. +func WithValue(ctx context.Context, val string) context.Context { + return context.WithValue(ctx, onContextKey{}, &OnContext{Value: val}) +} + +// OnContext is a struct for holding a value attached to a context. +type OnContext struct { + Value string +} + +// SetDefaults sets the defaults on the spec. +func (cs *ResourceSpec) SetDefaults(ctx context.Context) { + if cs.FieldWithDefault == "" { + cs.FieldWithDefault = "I'm a default." + } + if cs.FieldWithContextDefault == "" { + oc, ok := ctx.Value(onContextKey{}).(*OnContext) + if ok { + cs.FieldWithContextDefault = oc.Value + } + } + if cs.FieldThatsImmutableWithDefault == "" { + cs.FieldThatsImmutableWithDefault = "this is another default value" + } +} + +func (cs *ResourceSpec) Validate(ctx context.Context) *apis.FieldError { + if cs.FieldWithValidation != "magic value" { + return apis.ErrInvalidValue(cs.FieldWithValidation, "fieldWithValidation") + } + return nil +} + +func (current *Resource) CheckImmutableFields(ctx context.Context, og apis.Immutable) *apis.FieldError { + original, ok := og.(*Resource) + if !ok { + return &apis.FieldError{Message: "The provided original was not a Resource"} + } + + if original.Spec.FieldThatsImmutable != current.Spec.FieldThatsImmutable { + return &apis.FieldError{ + Message: "Immutable field changed", + Paths: []string{"spec.fieldThatsImmutable"}, + Details: fmt.Sprintf("got: %v, want: %v", current.Spec.FieldThatsImmutable, + original.Spec.FieldThatsImmutable), + } + } + + if original.Spec.FieldThatsImmutableWithDefault != current.Spec.FieldThatsImmutableWithDefault { + return &apis.FieldError{ + Message: "Immutable field changed", + Paths: []string{"spec.fieldThatsImmutableWithDefault"}, + Details: fmt.Sprintf("got: %v, want: %v", current.Spec.FieldThatsImmutableWithDefault, + original.Spec.FieldThatsImmutableWithDefault), + } + } + return nil +} + +// GetListType implements apis.Listable +func (r *Resource) GetListType() runtime.Object { + return &ResourceList{} +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// ResourceList is a list of Resource resources +type ResourceList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata"` + + Items []Resource `json:"items"` +} diff --git a/vendor/github.com/knative/pkg/testing/zz_generated.deepcopy.go b/vendor/github.com/knative/pkg/testing/zz_generated.deepcopy.go new file mode 100644 index 0000000000..7ae6d17918 --- /dev/null +++ b/vendor/github.com/knative/pkg/testing/zz_generated.deepcopy.go @@ -0,0 +1,285 @@ +// +build !ignore_autogenerated + +/* +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. +*/ + +// Code generated by deepcopy-gen. DO NOT EDIT. + +package testing + +import ( + runtime "k8s.io/apimachinery/pkg/runtime" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *InlinedPtrStruct) DeepCopyInto(out *InlinedPtrStruct) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InlinedPtrStruct. +func (in *InlinedPtrStruct) DeepCopy() *InlinedPtrStruct { + if in == nil { + return nil + } + out := new(InlinedPtrStruct) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *InlinedStruct) DeepCopyInto(out *InlinedStruct) { + *out = *in + if in.InlinedPtrStruct != nil { + in, out := &in.InlinedPtrStruct, &out.InlinedPtrStruct + *out = new(InlinedPtrStruct) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InlinedStruct. +func (in *InlinedStruct) DeepCopy() *InlinedStruct { + if in == nil { + return nil + } + out := new(InlinedStruct) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *InnerDefaultResource) DeepCopyInto(out *InnerDefaultResource) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + out.Status = in.Status + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InnerDefaultResource. +func (in *InnerDefaultResource) DeepCopy() *InnerDefaultResource { + if in == nil { + return nil + } + out := new(InnerDefaultResource) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *InnerDefaultResource) 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 *InnerDefaultSpec) DeepCopyInto(out *InnerDefaultSpec) { + *out = *in + if in.SubFields != nil { + in, out := &in.SubFields, &out.SubFields + *out = new(InnerDefaultSubSpec) + (*in).DeepCopyInto(*out) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InnerDefaultSpec. +func (in *InnerDefaultSpec) DeepCopy() *InnerDefaultSpec { + if in == nil { + return nil + } + out := new(InnerDefaultSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *InnerDefaultStatus) DeepCopyInto(out *InnerDefaultStatus) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InnerDefaultStatus. +func (in *InnerDefaultStatus) DeepCopy() *InnerDefaultStatus { + if in == nil { + return nil + } + out := new(InnerDefaultStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *InnerDefaultStruct) DeepCopyInto(out *InnerDefaultStruct) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InnerDefaultStruct. +func (in *InnerDefaultStruct) DeepCopy() *InnerDefaultStruct { + if in == nil { + return nil + } + out := new(InnerDefaultStruct) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *InnerDefaultSubSpec) DeepCopyInto(out *InnerDefaultSubSpec) { + *out = *in + if in.DeprecatedStringPtr != nil { + in, out := &in.DeprecatedStringPtr, &out.DeprecatedStringPtr + *out = new(string) + **out = **in + } + if in.DeprecatedIntPtr != nil { + in, out := &in.DeprecatedIntPtr, &out.DeprecatedIntPtr + *out = new(int64) + **out = **in + } + if in.DeprecatedMap != nil { + in, out := &in.DeprecatedMap, &out.DeprecatedMap + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + if in.DeprecatedSlice != nil { + in, out := &in.DeprecatedSlice, &out.DeprecatedSlice + *out = make([]string, len(*in)) + copy(*out, *in) + } + out.DeprecatedStruct = in.DeprecatedStruct + if in.DeprecatedStructPtr != nil { + in, out := &in.DeprecatedStructPtr, &out.DeprecatedStructPtr + *out = new(InnerDefaultStruct) + **out = **in + } + in.InlinedStruct.DeepCopyInto(&out.InlinedStruct) + if in.InlinedPtrStruct != nil { + in, out := &in.InlinedPtrStruct, &out.InlinedPtrStruct + *out = new(InlinedPtrStruct) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InnerDefaultSubSpec. +func (in *InnerDefaultSubSpec) DeepCopy() *InnerDefaultSubSpec { + if in == nil { + return nil + } + out := new(InnerDefaultSubSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *OnContext) DeepCopyInto(out *OnContext) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OnContext. +func (in *OnContext) DeepCopy() *OnContext { + if in == nil { + return nil + } + out := new(OnContext) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Resource) DeepCopyInto(out *Resource) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + out.Spec = in.Spec + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Resource. +func (in *Resource) DeepCopy() *Resource { + if in == nil { + return nil + } + out := new(Resource) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *Resource) 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 *ResourceList) DeepCopyInto(out *ResourceList) { + *out = *in + out.TypeMeta = in.TypeMeta + out.ListMeta = in.ListMeta + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]Resource, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ResourceList. +func (in *ResourceList) DeepCopy() *ResourceList { + if in == nil { + return nil + } + out := new(ResourceList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *ResourceList) 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 *ResourceSpec) DeepCopyInto(out *ResourceSpec) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ResourceSpec. +func (in *ResourceSpec) DeepCopy() *ResourceSpec { + if in == nil { + return nil + } + out := new(ResourceSpec) + in.DeepCopyInto(out) + return out +} diff --git a/vendor/github.com/knative/pkg/tracing/config/doc.go b/vendor/github.com/knative/pkg/tracing/config/doc.go new file mode 100644 index 0000000000..757ea40577 --- /dev/null +++ b/vendor/github.com/knative/pkg/tracing/config/doc.go @@ -0,0 +1,21 @@ +/* +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. +*/ + +// +k8s:deepcopy-gen=package + +// Package config holds the typed objects that define the schemas for +// assorted ConfigMap objects on which the Revision controller depends. +package config diff --git a/vendor/github.com/knative/pkg/tracing/config/tracing.go b/vendor/github.com/knative/pkg/tracing/config/tracing.go new file mode 100644 index 0000000000..5d21fcf5dd --- /dev/null +++ b/vendor/github.com/knative/pkg/tracing/config/tracing.go @@ -0,0 +1,95 @@ +/* +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 config + +import ( + "errors" + "fmt" + "strconv" + + corev1 "k8s.io/api/core/v1" +) + +const ( + // ConfigName is the name of the configmap + ConfigName = "config-tracing" + + enableKey = "enable" + zipkinEndpointKey = "zipkin-endpoint" + debugKey = "debug" + sampleRateKey = "sample-rate" +) + +// Config holds the configuration for tracers +type Config struct { + Enable bool + ZipkinEndpoint string + Debug bool + SampleRate float64 +} + +// Equals returns true if two Configs are identical +func (cfg *Config) Equals(other *Config) bool { + return other.Enable == cfg.Enable && other.ZipkinEndpoint == cfg.ZipkinEndpoint && other.Debug == cfg.Debug && other.SampleRate == cfg.SampleRate +} + +// NewTracingConfigFromMap returns a Config given a map corresponding to a ConfigMap +func NewTracingConfigFromMap(cfgMap map[string]string) (*Config, error) { + tc := Config{ + Enable: false, + Debug: false, + SampleRate: 0.1, + } + if enable, ok := cfgMap[enableKey]; ok { + enableBool, err := strconv.ParseBool(enable) + if err != nil { + return nil, fmt.Errorf("Failed parsing tracing config %q: %v", enableKey, err) + } + tc.Enable = enableBool + } + + if endpoint, ok := cfgMap[zipkinEndpointKey]; !ok { + if tc.Enable { + return nil, errors.New("Tracing enabled but no zipkin endpoint specified") + } + } else { + tc.ZipkinEndpoint = endpoint + } + + if debug, ok := cfgMap[debugKey]; ok { + debugBool, err := strconv.ParseBool(debug) + if err != nil { + return nil, fmt.Errorf("Failed parsing tracing config %q", debugKey) + } + tc.Debug = debugBool + } + + if sampleRate, ok := cfgMap[sampleRateKey]; ok { + sampleRateFloat, err := strconv.ParseFloat(sampleRate, 64) + if err != nil { + return nil, fmt.Errorf("Failed to parse sampleRate in tracing config: %v", err) + } + tc.SampleRate = sampleRateFloat + } + + return &tc, nil +} + +// NewTracingConfigFromConfigMap returns a Config for the given configmap +func NewTracingConfigFromConfigMap(config *corev1.ConfigMap) (*Config, error) { + return NewTracingConfigFromMap(config.Data) +} diff --git a/vendor/github.com/knative/pkg/tracing/config/zz_generated.deepcopy.go b/vendor/github.com/knative/pkg/tracing/config/zz_generated.deepcopy.go new file mode 100644 index 0000000000..6889d929d4 --- /dev/null +++ b/vendor/github.com/knative/pkg/tracing/config/zz_generated.deepcopy.go @@ -0,0 +1,37 @@ +// +build !ignore_autogenerated + +/* +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. +*/ + +// Code generated by deepcopy-gen. DO NOT EDIT. + +package config + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Config) DeepCopyInto(out *Config) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Config. +func (in *Config) DeepCopy() *Config { + if in == nil { + return nil + } + out := new(Config) + in.DeepCopyInto(out) + return out +} diff --git a/vendor/github.com/knative/pkg/tracing/http.go b/vendor/github.com/knative/pkg/tracing/http.go new file mode 100644 index 0000000000..c0ecf47238 --- /dev/null +++ b/vendor/github.com/knative/pkg/tracing/http.go @@ -0,0 +1,28 @@ +/* +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 tracing + +import ( + "net/http" + + "go.opencensus.io/plugin/ochttp" +) + +// HTTPSpanMiddleware is a http.Handler middleware to create spans for the HTTP endpoint +func HTTPSpanMiddleware(next http.Handler) http.Handler { + return &ochttp.Handler{Handler: next} +} diff --git a/vendor/github.com/knative/pkg/tracing/opencensus.go b/vendor/github.com/knative/pkg/tracing/opencensus.go new file mode 100644 index 0000000000..e022164f3e --- /dev/null +++ b/vendor/github.com/knative/pkg/tracing/opencensus.go @@ -0,0 +1,136 @@ +package tracing + +import ( + "errors" + "sync" + + "github.com/knative/pkg/tracing/config" + zipkinmodel "github.com/openzipkin/zipkin-go/model" + zipkinreporter "github.com/openzipkin/zipkin-go/reporter" + "go.opencensus.io/exporter/zipkin" + "go.opencensus.io/trace" +) + +// ConfigOption is the interface for adding additional exporters and configuring opencensus tracing. +type ConfigOption func(*config.Config) + +// OpenCensusTracer is responsible for managing and updating configuration of OpenCensus tracing +type OpenCensusTracer struct { + curCfg *config.Config + configOptions []ConfigOption + zipkinReporter zipkinreporter.Reporter + zipkinExporter trace.Exporter +} + +// OpenCensus tracing keeps state in globals and therefore we can only run one OpenCensusTracer +var ( + octMutex sync.Mutex + globalOct *OpenCensusTracer +) + +func NewOpenCensusTracer(configOptions ...ConfigOption) *OpenCensusTracer { + return &OpenCensusTracer{ + configOptions: configOptions, + } +} + +func (oct *OpenCensusTracer) ApplyConfig(cfg *config.Config) error { + err := oct.acquireGlobal() + defer octMutex.Unlock() + if err != nil { + return err + } + + // Short circuit if our config hasnt changed + if oct.curCfg != nil && oct.curCfg.Equals(cfg) { + return nil + } + + // Apply config options + for _, configOpt := range oct.configOptions { + configOpt(cfg) + } + + // Set config + trace.ApplyConfig(*createOCTConfig(cfg)) + + return nil +} + +func (oct *OpenCensusTracer) Finish() error { + err := oct.acquireGlobal() + defer octMutex.Unlock() + if err != nil { + return errors.New("Finish called on OpenTracer which is not the global OpenCensusTracer.") + } + + for _, configOpt := range oct.configOptions { + configOpt(nil) + } + globalOct = nil + + return nil +} + +func (oct *OpenCensusTracer) acquireGlobal() error { + octMutex.Lock() + + if globalOct == nil { + globalOct = oct + } else if globalOct != oct { + return errors.New("A OpenCensusTracer already exists and only one can be run at a time.") + } + + return nil +} + +func createOCTConfig(cfg *config.Config) *trace.Config { + octCfg := trace.Config{} + + if cfg.Enable { + if cfg.Debug { + octCfg.DefaultSampler = trace.AlwaysSample() + } else { + octCfg.DefaultSampler = trace.ProbabilitySampler(cfg.SampleRate) + } + } else { + octCfg.DefaultSampler = trace.NeverSample() + } + + return &octCfg +} + +func WithZipkinExporter(reporterFact ZipkinReporterFactory, endpoint *zipkinmodel.Endpoint) ConfigOption { + return func(cfg *config.Config) { + var ( + reporter zipkinreporter.Reporter + exporter trace.Exporter + ) + + if cfg != nil && cfg.Enable { + // Initialize our reporter / exporter + // do this before cleanup to minimize time where we have duplicate exporters + reporter, err := reporterFact(cfg) + if err != nil { + // TODO(greghaynes) log this error + return + } + exporter := zipkin.NewExporter(reporter, endpoint) + trace.RegisterExporter(exporter) + } + + // We know this is set because we are called with acquireGlobal lock held + oct := globalOct + if oct.zipkinExporter != nil { + trace.UnregisterExporter(oct.zipkinExporter) + } + + if oct.zipkinReporter != nil { + // TODO(greghaynes) log this error + _ = oct.zipkinReporter.Close() + } + + oct.zipkinReporter = reporter + oct.zipkinExporter = exporter + } +} diff --git a/vendor/github.com/knative/pkg/tracing/zipkin.go b/vendor/github.com/knative/pkg/tracing/zipkin.go new file mode 100644 index 0000000000..c455c47edd --- /dev/null +++ b/vendor/github.com/knative/pkg/tracing/zipkin.go @@ -0,0 +1,36 @@ +/* +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 tracing + +import ( + zipkinreporter "github.com/openzipkin/zipkin-go/reporter" + httpreporter "github.com/openzipkin/zipkin-go/reporter/http" + + "github.com/knative/pkg/tracing/config" +) + +// ZipkinReporterFactory is a factory function which creates a reporter given a config +type ZipkinReporterFactory func(*config.Config) (zipkinreporter.Reporter, error) + +// CreateZipkinReporter returns a zipkin reporter. If EndpointURL is not specified it returns +// a noop reporter +func CreateZipkinReporter(cfg *config.Config) (zipkinreporter.Reporter, error) { + if cfg.ZipkinEndpoint == "" { + return zipkinreporter.NewNoopReporter(), nil + } + return httpreporter.NewReporter(cfg.ZipkinEndpoint), nil +} diff --git a/vendor/github.com/knative/pkg/version/version.go b/vendor/github.com/knative/pkg/version/version.go new file mode 100644 index 0000000000..86e2db4b57 --- /dev/null +++ b/vendor/github.com/knative/pkg/version/version.go @@ -0,0 +1,55 @@ +/* +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 version + +import ( + "fmt" + + "github.com/rogpeppe/go-internal/semver" + "k8s.io/apimachinery/pkg/version" +) + +// ServerVersioner is an interface to mock the `ServerVersion` +// method of the Kubernetes client's Discovery interface. +// In an application `kubeClient.Discovery()` can be used to +// suffice this interface. +type ServerVersioner interface { + ServerVersion() (*version.Info, error) +} + +var minimumVersion = "v1.11.0" + +// CheckMinimumVersion checks if the currently installed version of +// Kubernetes is compatible with the minimum version required. +// Returns an error if its not. +// +// A Kubernetes discovery client can be passed in as the versioner +// like `CheckMinimumVersion(kubeClient.Discovery())`. +func CheckMinimumVersion(versioner ServerVersioner) error { + v, err := versioner.ServerVersion() + if err != nil { + return err + } + currentVersion := semver.Canonical(v.String()) + + // Compare returns 1 if the first version is greater than the + // second version. + if semver.Compare(minimumVersion, currentVersion) == 1 { + return fmt.Errorf("kubernetes version %q is not compatible, need at least %q", currentVersion, minimumVersion) + } + return nil +} diff --git a/vendor/github.com/knative/pkg/webhook/OWNERS b/vendor/github.com/knative/pkg/webhook/OWNERS new file mode 100644 index 0000000000..b87878d94a --- /dev/null +++ b/vendor/github.com/knative/pkg/webhook/OWNERS @@ -0,0 +1,4 @@ +# The OWNERS file is used by prow to automatically merge approved PRs. + +approvers: +- webhook-approvers diff --git a/vendor/github.com/knative/pkg/webhook/certs.go b/vendor/github.com/knative/pkg/webhook/certs.go new file mode 100644 index 0000000000..ba0ee73937 --- /dev/null +++ b/vendor/github.com/knative/pkg/webhook/certs.go @@ -0,0 +1,165 @@ +/* +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 webhook + +import ( + "context" + "crypto/rand" + "crypto/rsa" + "crypto/x509" + "crypto/x509/pkix" + "encoding/pem" + "errors" + "math/big" + "time" + + "go.uber.org/zap" + + "github.com/knative/pkg/logging" +) + +const ( + organization = "knative.dev" +) + +// Create the common parts of the cert. These don't change between +// the root/CA cert and the server cert. +func createCertTemplate(name, namespace string) (*x509.Certificate, error) { + serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128) + serialNumber, err := rand.Int(rand.Reader, serialNumberLimit) + if err != nil { + return nil, errors.New("failed to generate serial number: " + err.Error()) + } + + serviceName := name + "." + namespace + serviceNames := []string{ + name, + serviceName, + serviceName + ".svc", + serviceName + ".svc.cluster.local", + } + + tmpl := x509.Certificate{ + SerialNumber: serialNumber, + Subject: pkix.Name{Organization: []string{organization}}, + SignatureAlgorithm: x509.SHA256WithRSA, + NotBefore: time.Now(), + NotAfter: time.Now().AddDate(1, 0, 0), // valid for 1 years + BasicConstraintsValid: true, + DNSNames: serviceNames, + } + return &tmpl, nil +} + +// Create cert template suitable for CA and hence signing +func createCACertTemplate(name, namespace string) (*x509.Certificate, error) { + rootCert, err := createCertTemplate(name, namespace) + if err != nil { + return nil, err + } + // Make it into a CA cert and change it so we can use it to sign certs + rootCert.IsCA = true + rootCert.KeyUsage = x509.KeyUsageCertSign | x509.KeyUsageDigitalSignature + rootCert.ExtKeyUsage = []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth, x509.ExtKeyUsageClientAuth} + return rootCert, nil +} + +// Create cert template that we can use on the server for TLS +func createServerCertTemplate(name, namespace string) (*x509.Certificate, error) { + serverCert, err := createCertTemplate(name, namespace) + if err != nil { + return nil, err + } + serverCert.KeyUsage = x509.KeyUsageDigitalSignature + serverCert.ExtKeyUsage = []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth} + return serverCert, err +} + +// Actually sign the cert and return things in a form that we can use later on +func createCert(template, parent *x509.Certificate, pub interface{}, parentPriv interface{}) ( + cert *x509.Certificate, certPEM []byte, err error) { + + certDER, err := x509.CreateCertificate(rand.Reader, template, parent, pub, parentPriv) + if err != nil { + return + } + cert, err = x509.ParseCertificate(certDER) + if err != nil { + return + } + b := pem.Block{Type: "CERTIFICATE", Bytes: certDER} + certPEM = pem.EncodeToMemory(&b) + return +} + +func createCA(ctx context.Context, name, namespace string) (*rsa.PrivateKey, *x509.Certificate, []byte, error) { + logger := logging.FromContext(ctx) + rootKey, err := rsa.GenerateKey(rand.Reader, 2048) + if err != nil { + logger.Errorw("error generating random key", zap.Error(err)) + return nil, nil, nil, err + } + + rootCertTmpl, err := createCACertTemplate(name, namespace) + if err != nil { + logger.Errorw("error generating CA cert", zap.Error(err)) + return nil, nil, nil, err + } + + rootCert, rootCertPEM, err := createCert(rootCertTmpl, rootCertTmpl, &rootKey.PublicKey, rootKey) + if err != nil { + logger.Errorw("error signing the CA cert", zap.Error(err)) + return nil, nil, nil, err + } + return rootKey, rootCert, rootCertPEM, nil +} + +// CreateCerts creates and returns a CA certificate and certificate and +// key for the server. serverKey and serverCert are used by the server +// to establish trust for clients, CA certificate is used by the +// client to verify the server authentication chain. +func CreateCerts(ctx context.Context, name, namespace string) (serverKey, serverCert, caCert []byte, err error) { + logger := logging.FromContext(ctx) + // First create a CA certificate and private key + caKey, caCertificate, caCertificatePEM, err := createCA(ctx, name, namespace) + if err != nil { + return nil, nil, nil, err + } + + // Then create the private key for the serving cert + servKey, err := rsa.GenerateKey(rand.Reader, 2048) + if err != nil { + logger.Errorw("error generating random key", zap.Error(err)) + return nil, nil, nil, err + } + servCertTemplate, err := createServerCertTemplate(name, namespace) + if err != nil { + logger.Errorw("failed to create the server certificate template", zap.Error(err)) + return nil, nil, nil, err + } + + // create a certificate which wraps the server's public key, sign it with the CA private key + _, servCertPEM, err := createCert(servCertTemplate, caCertificate, &servKey.PublicKey, caKey) + if err != nil { + logger.Errorw("error signing server certificate template", zap.Error(err)) + return nil, nil, nil, err + } + servKeyPEM := pem.EncodeToMemory(&pem.Block{ + Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(servKey), + }) + return servKeyPEM, servCertPEM, caCertificatePEM, nil +} diff --git a/vendor/github.com/knative/pkg/webhook/webhook.go b/vendor/github.com/knative/pkg/webhook/webhook.go new file mode 100644 index 0000000000..8ed6417655 --- /dev/null +++ b/vendor/github.com/knative/pkg/webhook/webhook.go @@ -0,0 +1,619 @@ +/* +Copyright 2017 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 webhook + +import ( + "bytes" + "context" + "crypto/tls" + "crypto/x509" + "encoding/json" + "errors" + "fmt" + "net/http" + "sort" + "strings" + "time" + + "go.uber.org/zap" + + "github.com/knative/pkg/apis" + "github.com/knative/pkg/apis/duck" + "github.com/knative/pkg/kmp" + "github.com/knative/pkg/logging" + "github.com/knative/pkg/logging/logkey" + + "github.com/markbates/inflect" + "github.com/mattbaird/jsonpatch" + admissionv1beta1 "k8s.io/api/admission/v1beta1" + admissionregistrationv1beta1 "k8s.io/api/admissionregistration/v1beta1" + appsv1 "k8s.io/api/apps/v1" + corev1 "k8s.io/api/core/v1" + apierrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/client-go/kubernetes" + clientadmissionregistrationv1beta1 "k8s.io/client-go/kubernetes/typed/admissionregistration/v1beta1" +) + +const ( + secretServerKey = "server-key.pem" + secretServerCert = "server-cert.pem" + secretCACert = "ca-cert.pem" +) + +var ( + deploymentKind = appsv1.SchemeGroupVersion.WithKind("Deployment") + errMissingNewObject = errors.New("the new object may not be nil") +) + +// ControllerOptions contains the configuration for the webhook +type ControllerOptions struct { + // WebhookName is the name of the webhook we create to handle + // mutations before they get stored in the storage. + WebhookName string + + // ServiceName is the service name of the webhook. + ServiceName string + + // DeploymentName is the service name of the webhook. + DeploymentName string + + // SecretName is the name of k8s secret that contains the webhook + // server key/cert and corresponding CA cert that signed them. The + // server key/cert are used to serve the webhook and the CA cert + // is provided to k8s apiserver during admission controller + // registration. + SecretName string + + // Namespace is the namespace in which everything above lives. + Namespace string + + // Port where the webhook is served. Per k8s admission + // registration requirements this should be 443 unless there is + // only a single port for the service. + Port int + + // RegistrationDelay controls how long admission registration + // occurs after the webhook is started. This is used to avoid + // potential races where registration completes and k8s apiserver + // invokes the webhook before the HTTP server is started. + RegistrationDelay time.Duration + + // ClientAuthType declares the policy the webhook server will follow for + // TLS Client Authentication. + // The default value is tls.NoClientCert. + ClientAuth tls.ClientAuthType +} + +// ResourceCallback defines a signature for resource specific (Route, Configuration, etc.) +// handlers that can validate and mutate an object. If non-nil error is returned, object creation +// is denied. Mutations should be appended to the patches operations. +type ResourceCallback func(patches *[]jsonpatch.JsonPatchOperation, old GenericCRD, new GenericCRD) error + +// ResourceDefaulter defines a signature for resource specific (Route, Configuration, etc.) +// handlers that can set defaults on an object. If non-nil error is returned, object creation +// is denied. Mutations should be appended to the patches operations. +type ResourceDefaulter func(patches *[]jsonpatch.JsonPatchOperation, crd GenericCRD) error + +// AdmissionController implements the external admission webhook for validation of +// pilot configuration. +type AdmissionController struct { + Client kubernetes.Interface + Options ControllerOptions + Handlers map[schema.GroupVersionKind]GenericCRD + Logger *zap.SugaredLogger + + WithContext func(context.Context) context.Context + DisallowUnknownFields bool +} + +func nop(ctx context.Context) context.Context { + return ctx +} + +// GenericCRD is the interface definition that allows us to perform the generic +// CRD actions like deciding whether to increment generation and so forth. +type GenericCRD interface { + apis.Defaultable + apis.Validatable + runtime.Object +} + +// GetAPIServerExtensionCACert gets the Kubernetes aggregate apiserver +// client CA cert used by validator. +// +// NOTE: this certificate is provided kubernetes. We do not control +// its name or location. +func getAPIServerExtensionCACert(cl kubernetes.Interface) ([]byte, error) { + const name = "extension-apiserver-authentication" + c, err := cl.CoreV1().ConfigMaps(metav1.NamespaceSystem).Get(name, metav1.GetOptions{}) + if err != nil { + return nil, err + } + const caFileName = "requestheader-client-ca-file" + pem, ok := c.Data[caFileName] + if !ok { + return nil, fmt.Errorf("cannot find %s in ConfigMap %s: ConfigMap.Data is %#v", caFileName, name, c.Data) + } + return []byte(pem), nil +} + +// MakeTLSConfig makes a TLS configuration suitable for use with the server +func makeTLSConfig(serverCert, serverKey, caCert []byte, clientAuthType tls.ClientAuthType) (*tls.Config, error) { + caCertPool := x509.NewCertPool() + caCertPool.AppendCertsFromPEM(caCert) + cert, err := tls.X509KeyPair(serverCert, serverKey) + if err != nil { + return nil, err + } + return &tls.Config{ + Certificates: []tls.Certificate{cert}, + ClientCAs: caCertPool, + ClientAuth: clientAuthType, + }, nil +} + +func getOrGenerateKeyCertsFromSecret(ctx context.Context, client kubernetes.Interface, + options *ControllerOptions) (serverKey, serverCert, caCert []byte, err error) { + logger := logging.FromContext(ctx) + secret, err := client.CoreV1().Secrets(options.Namespace).Get(options.SecretName, metav1.GetOptions{}) + if err != nil { + if !apierrors.IsNotFound(err) { + return nil, nil, nil, err + } + logger.Info("Did not find existing secret, creating one") + newSecret, err := generateSecret(ctx, options) + if err != nil { + return nil, nil, nil, err + } + secret, err = client.CoreV1().Secrets(newSecret.Namespace).Create(newSecret) + if err != nil && !apierrors.IsAlreadyExists(err) { + return nil, nil, nil, err + } + // Ok, so something else might have created, try fetching it one more time + secret, err = client.CoreV1().Secrets(options.Namespace).Get(options.SecretName, metav1.GetOptions{}) + if err != nil { + return nil, nil, nil, err + } + } + + var ok bool + if serverKey, ok = secret.Data[secretServerKey]; !ok { + return nil, nil, nil, errors.New("server key missing") + } + if serverCert, ok = secret.Data[secretServerCert]; !ok { + return nil, nil, nil, errors.New("server cert missing") + } + if caCert, ok = secret.Data[secretCACert]; !ok { + return nil, nil, nil, errors.New("ca cert missing") + } + return serverKey, serverCert, caCert, nil +} + +// validate performs validation on the provided "new" CRD. +// For legacy purposes, this also does apis.Immutable validation, +// which is deprecated and will be removed in a future release. +func validate(ctx context.Context, new GenericCRD) error { + if apis.IsInUpdate(ctx) { + old := apis.GetBaseline(ctx) + if immutableNew, ok := new.(apis.Immutable); ok { + immutableOld, ok := old.(apis.Immutable) + if !ok { + return fmt.Errorf("unexpected type mismatch %T vs. %T", old, new) + } + if err := immutableNew.CheckImmutableFields(ctx, immutableOld); err != nil { + return err + } + } + } + + // Can't just `return new.Validate()` because it doesn't properly nil-check. + if err := new.Validate(ctx); err != nil { + return err + } + + return nil +} + +// setDefaults simply leverages apis.Defaultable to set defaults. +func setDefaults(ctx context.Context, patches duck.JSONPatch, crd GenericCRD) (duck.JSONPatch, error) { + before, after := crd.DeepCopyObject(), crd + after.SetDefaults(ctx) + + patch, err := duck.CreatePatch(before, after) + if err != nil { + return nil, err + } + + return append(patches, patch...), nil +} + +func configureCerts(ctx context.Context, client kubernetes.Interface, options *ControllerOptions) (*tls.Config, []byte, error) { + var apiServerCACert []byte + if options.ClientAuth >= tls.VerifyClientCertIfGiven { + var err error + apiServerCACert, err = getAPIServerExtensionCACert(client) + if err != nil { + return nil, nil, err + } + } + + serverKey, serverCert, caCert, err := getOrGenerateKeyCertsFromSecret(ctx, client, options) + if err != nil { + return nil, nil, err + } + tlsConfig, err := makeTLSConfig(serverCert, serverKey, apiServerCACert, options.ClientAuth) + if err != nil { + return nil, nil, err + } + return tlsConfig, caCert, nil +} + +// Run implements the admission controller run loop. +func (ac *AdmissionController) Run(stop <-chan struct{}) error { + logger := ac.Logger + ctx := logging.WithLogger(context.TODO(), logger) + tlsConfig, caCert, err := configureCerts(ctx, ac.Client, &ac.Options) + if err != nil { + logger.Errorw("could not configure admission webhook certs", zap.Error(err)) + return err + } + + server := &http.Server{ + Handler: ac, + Addr: fmt.Sprintf(":%v", ac.Options.Port), + TLSConfig: tlsConfig, + } + + logger.Info("Found certificates for webhook...") + if ac.Options.RegistrationDelay != 0 { + logger.Infof("Delaying admission webhook registration for %v", ac.Options.RegistrationDelay) + } + + select { + case <-time.After(ac.Options.RegistrationDelay): + cl := ac.Client.AdmissionregistrationV1beta1().MutatingWebhookConfigurations() + if err := ac.register(ctx, cl, caCert); err != nil { + logger.Errorw("failed to register webhook", zap.Error(err)) + return err + } + logger.Info("Successfully registered webhook") + case <-stop: + return nil + } + + serverBootstrapErrCh := make(chan struct{}) + go func() { + if err := server.ListenAndServeTLS("", ""); err != nil { + logger.Errorw("ListenAndServeTLS for admission webhook returned error", zap.Error(err)) + close(serverBootstrapErrCh) + } + }() + + select { + case <-stop: + return server.Close() + case <-serverBootstrapErrCh: + return errors.New("webhook server bootstrap failed") + } +} + +// Register registers the external admission webhook for pilot +// configuration types. +func (ac *AdmissionController) register( + ctx context.Context, client clientadmissionregistrationv1beta1.MutatingWebhookConfigurationInterface, caCert []byte) error { // nolint: lll + logger := logging.FromContext(ctx) + failurePolicy := admissionregistrationv1beta1.Fail + + var rules []admissionregistrationv1beta1.RuleWithOperations + for gvk := range ac.Handlers { + plural := strings.ToLower(inflect.Pluralize(gvk.Kind)) + + rules = append(rules, admissionregistrationv1beta1.RuleWithOperations{ + Operations: []admissionregistrationv1beta1.OperationType{ + admissionregistrationv1beta1.Create, + admissionregistrationv1beta1.Update, + }, + Rule: admissionregistrationv1beta1.Rule{ + APIGroups: []string{gvk.Group}, + APIVersions: []string{gvk.Version}, + Resources: []string{plural + "/*"}, + }, + }) + } + + // Sort the rules by Group, Version, Kind so that things are deterministically ordered. + sort.Slice(rules, func(i, j int) bool { + lhs, rhs := rules[i], rules[j] + if lhs.APIGroups[0] != rhs.APIGroups[0] { + return lhs.APIGroups[0] < rhs.APIGroups[0] + } + if lhs.APIVersions[0] != rhs.APIVersions[0] { + return lhs.APIVersions[0] < rhs.APIVersions[0] + } + return lhs.Resources[0] < rhs.Resources[0] + }) + + webhook := &admissionregistrationv1beta1.MutatingWebhookConfiguration{ + ObjectMeta: metav1.ObjectMeta{ + Name: ac.Options.WebhookName, + }, + Webhooks: []admissionregistrationv1beta1.Webhook{{ + Name: ac.Options.WebhookName, + Rules: rules, + ClientConfig: admissionregistrationv1beta1.WebhookClientConfig{ + Service: &admissionregistrationv1beta1.ServiceReference{ + Namespace: ac.Options.Namespace, + Name: ac.Options.ServiceName, + }, + CABundle: caCert, + }, + FailurePolicy: &failurePolicy, + }}, + } + + // Set the owner to our deployment. + deployment, err := ac.Client.Apps().Deployments(ac.Options.Namespace).Get(ac.Options.DeploymentName, metav1.GetOptions{}) + if err != nil { + return fmt.Errorf("failed to fetch our deployment: %v", err) + } + deploymentRef := metav1.NewControllerRef(deployment, deploymentKind) + webhook.OwnerReferences = append(webhook.OwnerReferences, *deploymentRef) + + // Try to create the webhook and if it already exists validate webhook rules. + _, err = client.Create(webhook) + if err != nil { + if !apierrors.IsAlreadyExists(err) { + return fmt.Errorf("failed to create a webhook: %v", err) + } + logger.Info("Webhook already exists") + configuredWebhook, err := client.Get(ac.Options.WebhookName, metav1.GetOptions{}) + if err != nil { + return fmt.Errorf("error retrieving webhook: %v", err) + } + if ok, err := kmp.SafeEqual(configuredWebhook.Webhooks, webhook.Webhooks); err != nil { + return fmt.Errorf("error diffing webhooks: %v", err) + } else if !ok { + logger.Info("Updating webhook") + // Set the ResourceVersion as required by update. + webhook.ObjectMeta.ResourceVersion = configuredWebhook.ObjectMeta.ResourceVersion + if _, err := client.Update(webhook); err != nil { + return fmt.Errorf("failed to update webhook: %s", err) + } + } else { + logger.Info("Webhook is already valid") + } + } else { + logger.Info("Created a webhook") + } + return nil +} + +// ServeHTTP implements the external admission webhook for mutating +// serving resources. +func (ac *AdmissionController) ServeHTTP(w http.ResponseWriter, r *http.Request) { + logger := ac.Logger + logger.Infof("Webhook ServeHTTP request=%#v", r) + + // Verify the content type is accurate. + contentType := r.Header.Get("Content-Type") + if contentType != "application/json" { + http.Error(w, "invalid Content-Type, want `application/json`", http.StatusUnsupportedMediaType) + return + } + + var review admissionv1beta1.AdmissionReview + if err := json.NewDecoder(r.Body).Decode(&review); err != nil { + http.Error(w, fmt.Sprintf("could not decode body: %v", err), http.StatusBadRequest) + return + } + + logger = logger.With( + zap.String(logkey.Kind, fmt.Sprint(review.Request.Kind)), + zap.String(logkey.Namespace, review.Request.Namespace), + zap.String(logkey.Name, review.Request.Name), + zap.String(logkey.Operation, fmt.Sprint(review.Request.Operation)), + zap.String(logkey.Resource, fmt.Sprint(review.Request.Resource)), + zap.String(logkey.SubResource, fmt.Sprint(review.Request.SubResource)), + zap.String(logkey.UserInfo, fmt.Sprint(review.Request.UserInfo))) + ctx := logging.WithLogger(r.Context(), logger) + + if ac.WithContext != nil { + ctx = ac.WithContext(ctx) + } + + reviewResponse := ac.admit(ctx, review.Request) + var response admissionv1beta1.AdmissionReview + if reviewResponse != nil { + response.Response = reviewResponse + response.Response.UID = review.Request.UID + } + + logger.Infof("AdmissionReview for %#v: %s/%s response=%#v", + review.Request.Kind, review.Request.Namespace, review.Request.Name, reviewResponse) + + if err := json.NewEncoder(w).Encode(response); err != nil { + http.Error(w, fmt.Sprintf("could encode response: %v", err), http.StatusInternalServerError) + return + } +} + +func makeErrorStatus(reason string, args ...interface{}) *admissionv1beta1.AdmissionResponse { + result := apierrors.NewBadRequest(fmt.Sprintf(reason, args...)).Status() + return &admissionv1beta1.AdmissionResponse{ + Result: &result, + Allowed: false, + } +} + +func (ac *AdmissionController) admit(ctx context.Context, request *admissionv1beta1.AdmissionRequest) *admissionv1beta1.AdmissionResponse { + logger := logging.FromContext(ctx) + switch request.Operation { + case admissionv1beta1.Create, admissionv1beta1.Update: + default: + logger.Infof("Unhandled webhook operation, letting it through %v", request.Operation) + return &admissionv1beta1.AdmissionResponse{Allowed: true} + } + + patchBytes, err := ac.mutate(ctx, request) + if err != nil { + return makeErrorStatus("mutation failed: %v", err) + } + logger.Infof("Kind: %q PatchBytes: %v", request.Kind, string(patchBytes)) + + return &admissionv1beta1.AdmissionResponse{ + Patch: patchBytes, + Allowed: true, + PatchType: func() *admissionv1beta1.PatchType { + pt := admissionv1beta1.PatchTypeJSONPatch + return &pt + }(), + } +} + +func (ac *AdmissionController) mutate(ctx context.Context, req *admissionv1beta1.AdmissionRequest) ([]byte, error) { + kind := req.Kind + newBytes := req.Object.Raw + oldBytes := req.OldObject.Raw + // Why, oh why are these different types... + gvk := schema.GroupVersionKind{ + Group: kind.Group, + Version: kind.Version, + Kind: kind.Kind, + } + + logger := logging.FromContext(ctx) + handler, ok := ac.Handlers[gvk] + if !ok { + logger.Errorf("Unhandled kind: %v", gvk) + return nil, fmt.Errorf("unhandled kind: %v", gvk) + } + + // nil values denote absence of `old` (create) or `new` (delete) objects. + var oldObj, newObj GenericCRD + + if len(newBytes) != 0 { + newObj = handler.DeepCopyObject().(GenericCRD) + newDecoder := json.NewDecoder(bytes.NewBuffer(newBytes)) + if ac.DisallowUnknownFields { + newDecoder.DisallowUnknownFields() + } + if err := newDecoder.Decode(&newObj); err != nil { + return nil, fmt.Errorf("cannot decode incoming new object: %v", err) + } + } + if len(oldBytes) != 0 { + oldObj = handler.DeepCopyObject().(GenericCRD) + oldDecoder := json.NewDecoder(bytes.NewBuffer(oldBytes)) + if ac.DisallowUnknownFields { + oldDecoder.DisallowUnknownFields() + } + if err := oldDecoder.Decode(&oldObj); err != nil { + return nil, fmt.Errorf("cannot decode incoming old object: %v", err) + } + } + var patches duck.JSONPatch + + var err error + // Skip this step if the type we're dealing with is a duck type, since it is inherently + // incomplete and this will patch away all of the unspecified fields. + if _, ok := newObj.(duck.Populatable); !ok { + // Add these before defaulting fields, otherwise defaulting may cause an illegal patch + // because it expects the round tripped through Golang fields to be present already. + rtp, err := roundTripPatch(newBytes, newObj) + if err != nil { + return nil, fmt.Errorf("cannot create patch for round tripped newBytes: %v", err) + } + patches = append(patches, rtp...) + } + + // Set up the context for defaulting and validation + if oldObj != nil { + // Copy the old object and set defaults so that we don't reject our own + // defaulting done earlier in the webhook. + oldObj = oldObj.DeepCopyObject().(GenericCRD) + oldObj.SetDefaults(ctx) + + if req.SubResource == "" { + ctx = apis.WithinUpdate(ctx, oldObj) + } else { + ctx = apis.WithinSubResourceUpdate(ctx, oldObj, req.SubResource) + } + } else { + ctx = apis.WithinCreate(ctx) + } + ctx = apis.WithUserInfo(ctx, &req.UserInfo) + + // Default the new object. + if patches, err = setDefaults(ctx, patches, newObj); err != nil { + logger.Errorw("Failed the resource specific defaulter", zap.Error(err)) + // Return the error message as-is to give the defaulter callback + // discretion over (our portion of) the message that the user sees. + return nil, err + } + + // None of the validators will accept a nil value for newObj. + if newObj == nil { + return nil, errMissingNewObject + } + if err := validate(ctx, newObj); err != nil { + logger.Errorw("Failed the resource specific validation", zap.Error(err)) + // Return the error message as-is to give the validation callback + // discretion over (our portion of) the message that the user sees. + return nil, err + } + + return json.Marshal(patches) +} + +// roundTripPatch generates the JSONPatch that corresponds to round tripping the given bytes through +// the Golang type (JSON -> Golang type -> JSON). Because it is not always true that +// bytes == json.Marshal(json.Unmarshal(bytes)). +// +// For example, if bytes did not contain a 'spec' field and the Golang type specifies its 'spec' +// field without omitempty, then by round tripping through the Golang type, we would have added +// `'spec': {}`. +func roundTripPatch(bytes []byte, unmarshalled interface{}) (duck.JSONPatch, error) { + if unmarshalled == nil { + return duck.JSONPatch{}, nil + } + marshaledBytes, err := json.Marshal(unmarshalled) + if err != nil { + return nil, fmt.Errorf("cannot marshal interface: %v", err) + } + return jsonpatch.CreatePatch(bytes, marshaledBytes) +} + +func generateSecret(ctx context.Context, options *ControllerOptions) (*corev1.Secret, error) { + serverKey, serverCert, caCert, err := CreateCerts(ctx, options.ServiceName, options.Namespace) + if err != nil { + return nil, err + } + return &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: options.SecretName, + Namespace: options.Namespace, + }, + Data: map[string][]byte{ + secretServerKey: serverKey, + secretServerCert: serverCert, + secretCACert: caCert, + }, + }, nil +} diff --git a/vendor/github.com/knative/pkg/websocket/connection.go b/vendor/github.com/knative/pkg/websocket/connection.go new file mode 100644 index 0000000000..e37202e5fd --- /dev/null +++ b/vendor/github.com/knative/pkg/websocket/connection.go @@ -0,0 +1,325 @@ +/* +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 websocket + +import ( + "bytes" + "encoding/gob" + "errors" + "fmt" + "io" + "io/ioutil" + "sync" + "time" + + "go.uber.org/zap" + + "k8s.io/apimachinery/pkg/util/wait" + + "github.com/gorilla/websocket" +) + +var ( + // ErrConnectionNotEstablished is returned by methods that need a connection + // but no connection is already created. + ErrConnectionNotEstablished = errors.New("connection has not yet been established") + + // errShuttingDown is returned internally once the shutdown signal has been sent. + errShuttingDown = errors.New("shutdown in progress") + + // pongTimeout defines the amount of time allowed between two pongs to arrive + // before the connection is considered broken. + pongTimeout = 10 * time.Second +) + +// RawConnection is an interface defining the methods needed +// from a websocket connection +type rawConnection interface { + WriteMessage(messageType int, data []byte) error + NextReader() (int, io.Reader, error) + Close() error + + SetReadDeadline(deadline time.Time) error + SetPongHandler(func(string) error) +} + +// ManagedConnection represents a websocket connection. +type ManagedConnection struct { + connection rawConnection + connectionFactory func() (rawConnection, error) + + closeChan chan struct{} + closeOnce sync.Once + + // Used to capture asynchronous processes to be waited + // on when shutting the connection down. + processingWg sync.WaitGroup + + // If set, messages will be forwarded to this channel + messageChan chan []byte + + // This mutex controls access to the connection reference + // itself. + connectionLock sync.RWMutex + + // Gorilla's documentation states, that one reader and + // one writer are allowed concurrently. + readerLock sync.Mutex + writerLock sync.Mutex + + // Used for the exponential backoff when connecting + connectionBackoff wait.Backoff +} + +// NewDurableSendingConnection creates a new websocket connection +// that can only send messages to the endpoint it connects to. +// The connection will continuously be kept alive and reconnected +// in case of a loss of connectivity. +func NewDurableSendingConnection(target string, logger *zap.SugaredLogger) *ManagedConnection { + return NewDurableConnection(target, nil, logger) +} + +// NewDurableConnection creates a new websocket connection, that +// passes incoming messages to the given message channel. It can also +// send messages to the endpoint it connects to. +// The connection will continuously be kept alive and reconnected +// in case of a loss of connectivity. +// +// Note: The given channel needs to be drained after calling `Shutdown` +// to not cause any deadlocks. If the channel's buffer is likely to be +// filled, this needs to happen in separate goroutines, i.e. +// +// go func() {conn.Shutdown(); close(messageChan)} +// go func() {for range messageChan {}} +func NewDurableConnection(target string, messageChan chan []byte, logger *zap.SugaredLogger) *ManagedConnection { + websocketConnectionFactory := func() (rawConnection, error) { + dialer := &websocket.Dialer{ + HandshakeTimeout: 3 * time.Second, + } + conn, _, err := dialer.Dial(target, nil) + return conn, err + } + + c := newConnection(websocketConnectionFactory, messageChan) + + // Keep the connection alive asynchronously and reconnect on + // connection failure. + c.processingWg.Add(1) + go func() { + defer c.processingWg.Done() + + for { + select { + default: + logger.Infof("Connecting to %q", target) + if err := c.connect(); err != nil { + logger.Errorw(fmt.Sprintf("Connecting to %q failed", target), zap.Error(err)) + continue + } + logger.Infof("Connected to %q", target) + if err := c.keepalive(); err != nil { + logger.Errorw(fmt.Sprintf("Connection to %q broke down, reconnecting...", target), zap.Error(err)) + } + if err := c.closeConnection(); err != nil { + logger.Errorw("Failed to close the connection after crashing", zap.Error(err)) + } + case <-c.closeChan: + logger.Infof("Connection to %q is being shutdown", target) + return + } + } + }() + + // Keep sending pings 3 times per pongTimeout interval. + c.processingWg.Add(1) + go func() { + defer c.processingWg.Done() + + ticker := time.NewTicker(pongTimeout / 3) + defer ticker.Stop() + for { + select { + case <-ticker.C: + if err := c.write(websocket.PingMessage, []byte{}); err != nil { + logger.Errorw("Failed to send ping message", zap.Error(err)) + } + case <-c.closeChan: + return + } + } + }() + + return c +} + +// newConnection creates a new connection primitive. +func newConnection(connFactory func() (rawConnection, error), messageChan chan []byte) *ManagedConnection { + conn := &ManagedConnection{ + connectionFactory: connFactory, + closeChan: make(chan struct{}), + messageChan: messageChan, + connectionBackoff: wait.Backoff{ + Duration: 100 * time.Millisecond, + Factor: 1.3, + Steps: 20, + Jitter: 0.5, + }, + } + + return conn +} + +// connect tries to establish a websocket connection. +func (c *ManagedConnection) connect() error { + var err error + wait.ExponentialBackoff(c.connectionBackoff, func() (bool, error) { + select { + default: + var conn rawConnection + conn, err = c.connectionFactory() + if err != nil { + return false, nil + } + + // Setting the read deadline will cause NextReader in read + // to fail if it is exceeded. This deadline is reset each + // time we receive a pong message so we know the connection + // is still intact. + conn.SetReadDeadline(time.Now().Add(pongTimeout)) + conn.SetPongHandler(func(string) error { + conn.SetReadDeadline(time.Now().Add(pongTimeout)) + return nil + }) + + c.connectionLock.Lock() + defer c.connectionLock.Unlock() + + c.connection = conn + return true, nil + case <-c.closeChan: + err = errShuttingDown + return false, err + } + }) + + return err +} + +// keepalive keeps the connection open. +func (c *ManagedConnection) keepalive() error { + for { + select { + default: + if err := c.read(); err != nil { + return err + } + case <-c.closeChan: + return errShuttingDown + } + } +} + +// closeConnection closes the underlying websocket connection. +func (c *ManagedConnection) closeConnection() error { + c.connectionLock.Lock() + defer c.connectionLock.Unlock() + + if c.connection != nil { + err := c.connection.Close() + c.connection = nil + return err + } + return nil +} + +// read reads the next message from the connection. +// If a messageChan is supplied and the current message type is not +// a control message, the message is sent to that channel. +func (c *ManagedConnection) read() error { + c.connectionLock.RLock() + defer c.connectionLock.RUnlock() + + if c.connection == nil { + return ErrConnectionNotEstablished + } + + c.readerLock.Lock() + defer c.readerLock.Unlock() + + messageType, reader, err := c.connection.NextReader() + if err != nil { + return err + } + + // Send the message to the channel if its an application level message + // and if that channel is set. + // TODO(markusthoemmes): Return the messageType along with the payload. + if c.messageChan != nil && (messageType == websocket.TextMessage || messageType == websocket.BinaryMessage) { + if message, _ := ioutil.ReadAll(reader); message != nil { + c.messageChan <- message + } + } + + return nil +} + +func (c *ManagedConnection) write(messageType int, body []byte) error { + c.connectionLock.RLock() + defer c.connectionLock.RUnlock() + + if c.connection == nil { + return ErrConnectionNotEstablished + } + + c.writerLock.Lock() + defer c.writerLock.Unlock() + + return c.connection.WriteMessage(messageType, body) +} + +// Status checks the connection status of the webhook. +func (c *ManagedConnection) Status() error { + c.connectionLock.RLock() + defer c.connectionLock.RUnlock() + + if c.connection == nil { + return ErrConnectionNotEstablished + } + return nil +} + +// Send sends an encodable message over the websocket connection. +func (c *ManagedConnection) Send(msg interface{}) error { + var b bytes.Buffer + enc := gob.NewEncoder(&b) + if err := enc.Encode(msg); err != nil { + return err + } + + return c.write(websocket.BinaryMessage, b.Bytes()) +} + +// Shutdown closes the websocket connection. +func (c *ManagedConnection) Shutdown() error { + c.closeOnce.Do(func() { + close(c.closeChan) + }) + + err := c.closeConnection() + c.processingWg.Wait() + return err +} diff --git a/vendor/github.com/knative/pkg/websocket/hijack.go b/vendor/github.com/knative/pkg/websocket/hijack.go new file mode 100644 index 0000000000..f1ac075732 --- /dev/null +++ b/vendor/github.com/knative/pkg/websocket/hijack.go @@ -0,0 +1,32 @@ +/* +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 websocket + +import ( + "bufio" + "fmt" + "net" + "net/http" +) + +// HijackIfPossible calls Hijack() on the given http.ResponseWriter if it implements +// http.Hijacker interface, which is required for net/http/httputil/reverseproxy +// to handle connection upgrade/switching protocol. Otherwise returns an error. +func HijackIfPossible(w http.ResponseWriter) (net.Conn, *bufio.ReadWriter, error) { + hj, ok := w.(http.Hijacker) + if !ok { + return nil, nil, fmt.Errorf("wrapped writer of type %T can't be hijacked", w) + } + return hj.Hijack() +}