From adb69a4586de11ea63825993555c24c996850016 Mon Sep 17 00:00:00 2001 From: Matt Moore Date: Tue, 5 Nov 2019 14:14:56 -0800 Subject: [PATCH 1/2] Split apart defaulting and validation webhooks Related: knative/pkg#848 --- Gopkg.lock | 11 +- Gopkg.toml | 5 +- cmd/webhook/main.go | 88 ++-- config/500-webhook-configuration.yaml | 16 + vendor/knative.dev/pkg/Gopkg.lock | 1 - vendor/knative.dev/pkg/OWNERS_ALIASES | 9 - vendor/knative.dev/pkg/RELEASING.md | 10 + .../knative.dev/pkg/apis/condition_types.go | 1 - .../pkg/apis/duck/v1/destination.go | 93 ++++ .../pkg/apis/duck/v1/source_types.go | 5 +- .../pkg/apis/duck/v1/status_types.go | 1 - .../pkg/apis/duck/v1/zz_generated.deepcopy.go | 27 ++ .../{v1alpha1 => duck/v1beta1}/destination.go | 2 +- .../pkg/apis/duck/v1beta1/source_types.go | 5 +- .../pkg/apis/duck/v1beta1/status_types.go | 1 - .../duck/v1beta1/zz_generated.deepcopy.go | 27 ++ vendor/knative.dev/pkg/apis/interfaces.go | 9 - .../apis/v1alpha1/zz_generated.deepcopy.go | 52 --- vendor/knative.dev/pkg/apis/volatile_time.go | 1 - vendor/knative.dev/pkg/cloudevents/README.md | 151 ------- vendor/knative.dev/pkg/cloudevents/builder.go | 135 ------ vendor/knative.dev/pkg/cloudevents/client.go | 81 ---- vendor/knative.dev/pkg/cloudevents/doc.go | 22 - .../pkg/cloudevents/encoding_binary.go | 125 ------ .../pkg/cloudevents/encoding_structured.go | 143 ------- vendor/knative.dev/pkg/cloudevents/event.go | 205 --------- .../knative.dev/pkg/cloudevents/event_v01.go | 236 ----------- .../knative.dev/pkg/cloudevents/event_v02.go | 261 ------------ vendor/knative.dev/pkg/cloudevents/handler.go | 401 ------------------ .../injection-gen/generators/fakeinformer.go | 1 - .../knative.dev/pkg/controller/controller.go | 8 + .../pkg/controller/stats_reporter.go | 12 +- vendor/knative.dev/pkg/hack/update-codegen.sh | 6 +- vendor/knative.dev/pkg/logging/config.go | 6 +- vendor/knative.dev/pkg/metrics/config.go | 99 +++-- .../metrics/metricskey/constants_eventing.go | 20 +- .../pkg/metrics/metricstest/metricstest.go | 1 + .../metrics/monitored_resources_eventing.go | 8 +- vendor/knative.dev/pkg/metrics/record.go | 38 +- .../pkg/metrics/stackdriver_exporter.go | 79 +++- vendor/knative.dev/pkg/profiling/server.go | 6 +- .../pkg/reconciler/testing/sorter.go | 2 +- .../pkg/resolver/addressable_resolver.go | 3 +- .../pkg/test/ghutil/fakeghutil/fakeghutil.go | 12 +- vendor/knative.dev/pkg/test/gke/client.go | 9 +- vendor/knative.dev/pkg/test/gke/wait.go | 5 +- vendor/knative.dev/pkg/test/helpers/dryrun.go | 2 +- .../pkg/test/mako/alerter/github/issue.go | 4 +- .../resourcetree/test_util.go | 1 + vendor/knative.dev/pkg/testing/resource.go | 8 +- .../testutils/clustermanager/e2e-tests/gke.go | 2 +- .../{ => defaulting}/controller.go | 5 +- .../defaulting.go} | 58 +-- .../{ => defaulting}/user_info.go | 2 +- .../resourcesemantics/interface.go} | 16 +- .../validation/controller.go | 84 ++++ .../validation/validation.go | 259 +++++++++++ .../pkg/webhook/testing/testing.go | 9 +- vendor/knative.dev/pkg/webhook/webhook.go | 4 - 59 files changed, 797 insertions(+), 2096 deletions(-) create mode 100644 vendor/knative.dev/pkg/apis/duck/v1/destination.go rename vendor/knative.dev/pkg/apis/{v1alpha1 => duck/v1beta1}/destination.go (99%) delete mode 100644 vendor/knative.dev/pkg/apis/v1alpha1/zz_generated.deepcopy.go delete mode 100644 vendor/knative.dev/pkg/cloudevents/README.md delete mode 100644 vendor/knative.dev/pkg/cloudevents/builder.go delete mode 100644 vendor/knative.dev/pkg/cloudevents/client.go delete mode 100644 vendor/knative.dev/pkg/cloudevents/doc.go delete mode 100644 vendor/knative.dev/pkg/cloudevents/encoding_binary.go delete mode 100644 vendor/knative.dev/pkg/cloudevents/encoding_structured.go delete mode 100644 vendor/knative.dev/pkg/cloudevents/event.go delete mode 100644 vendor/knative.dev/pkg/cloudevents/event_v01.go delete mode 100644 vendor/knative.dev/pkg/cloudevents/event_v02.go delete mode 100644 vendor/knative.dev/pkg/cloudevents/handler.go rename vendor/knative.dev/pkg/webhook/resourcesemantics/{ => defaulting}/controller.go (95%) rename vendor/knative.dev/pkg/webhook/resourcesemantics/{resourcesemantics.go => defaulting/defaulting.go} (85%) rename vendor/knative.dev/pkg/webhook/resourcesemantics/{ => defaulting}/user_info.go (98%) rename vendor/knative.dev/pkg/{apis/v1alpha1/doc.go => webhook/resourcesemantics/interface.go} (62%) create mode 100644 vendor/knative.dev/pkg/webhook/resourcesemantics/validation/controller.go create mode 100644 vendor/knative.dev/pkg/webhook/resourcesemantics/validation/validation.go diff --git a/Gopkg.lock b/Gopkg.lock index be4cc8dfcb05..55044107ca4a 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -1671,8 +1671,7 @@ revision = "88e1e4db86d11beb16248a94b1072beac20aef4c" [[projects]] - branch = "master" - digest = "1:c8e0ec560560e16616821b3999e905e6b9085c832b5b57216905711e63679d19" + digest = "1:ae0703535ce20353d201a0e2043fc770f00f017c4b0a9302368d619a273aeb1b" name = "knative.dev/pkg" packages = [ "apis", @@ -1686,7 +1685,6 @@ "apis/istio/common/v1alpha1", "apis/istio/v1alpha3", "apis/testing/v1", - "apis/v1alpha1", "changeset", "client/clientset/versioned", "client/clientset/versioned/fake", @@ -1794,10 +1792,13 @@ "webhook/certificates/resources", "webhook/configmaps", "webhook/resourcesemantics", + "webhook/resourcesemantics/defaulting", + "webhook/resourcesemantics/validation", "websocket", ] pruneopts = "T" - revision = "d4ce00139499bd3ea11cdb18ef20a41bdb248245" + revision = "6058c9300faf3145ed64c7936f9a53c0d3b1fe9d" + source = "github.com/mattmoor/pkg-1" [[projects]] branch = "master" @@ -2031,6 +2032,8 @@ "knative.dev/pkg/webhook/certificates", "knative.dev/pkg/webhook/configmaps", "knative.dev/pkg/webhook/resourcesemantics", + "knative.dev/pkg/webhook/resourcesemantics/defaulting", + "knative.dev/pkg/webhook/resourcesemantics/validation", "knative.dev/pkg/websocket", "knative.dev/test-infra/scripts", "knative.dev/test-infra/shared/junit", diff --git a/Gopkg.toml b/Gopkg.toml index de187232ffc0..d3fa30a8e2ed 100644 --- a/Gopkg.toml +++ b/Gopkg.toml @@ -31,7 +31,10 @@ required = [ [[override]] name = "knative.dev/pkg" - branch = "master" + #TODO(mattmoor): DO NOT SUBMIT + source = "github.com/mattmoor/pkg-1" + revision = "6058c9300faf3145ed64c7936f9a53c0d3b1fe9d" + # branch = "master" [[constraint]] name = "knative.dev/caching" diff --git a/cmd/webhook/main.go b/cmd/webhook/main.go index 60bdc81f37ff..3e42921c53a9 100644 --- a/cmd/webhook/main.go +++ b/cmd/webhook/main.go @@ -30,6 +30,8 @@ import ( "knative.dev/pkg/webhook/certificates" "knative.dev/pkg/webhook/configmaps" "knative.dev/pkg/webhook/resourcesemantics" + "knative.dev/pkg/webhook/resourcesemantics/defaulting" + "knative.dev/pkg/webhook/resourcesemantics/validation" // resource validation types autoscalingv1alpha1 "knative.dev/serving/pkg/apis/autoscaling/v1alpha1" @@ -51,49 +53,74 @@ import ( domainconfig "knative.dev/serving/pkg/reconciler/route/config" ) -func NewResourceAdmissionController(ctx context.Context, cmw configmap.Watcher) *controller.Impl { +var types = map[schema.GroupVersionKind]resourcesemantics.GenericCRD{ + v1alpha1.SchemeGroupVersion.WithKind("Revision"): &v1alpha1.Revision{}, + v1alpha1.SchemeGroupVersion.WithKind("Configuration"): &v1alpha1.Configuration{}, + v1alpha1.SchemeGroupVersion.WithKind("Route"): &v1alpha1.Route{}, + v1alpha1.SchemeGroupVersion.WithKind("Service"): &v1alpha1.Service{}, + v1beta1.SchemeGroupVersion.WithKind("Revision"): &v1beta1.Revision{}, + v1beta1.SchemeGroupVersion.WithKind("Configuration"): &v1beta1.Configuration{}, + v1beta1.SchemeGroupVersion.WithKind("Route"): &v1beta1.Route{}, + v1beta1.SchemeGroupVersion.WithKind("Service"): &v1beta1.Service{}, + v1.SchemeGroupVersion.WithKind("Revision"): &v1.Revision{}, + v1.SchemeGroupVersion.WithKind("Configuration"): &v1.Configuration{}, + v1.SchemeGroupVersion.WithKind("Route"): &v1.Route{}, + v1.SchemeGroupVersion.WithKind("Service"): &v1.Service{}, + + autoscalingv1alpha1.SchemeGroupVersion.WithKind("PodAutoscaler"): &autoscalingv1alpha1.PodAutoscaler{}, + autoscalingv1alpha1.SchemeGroupVersion.WithKind("Metric"): &autoscalingv1alpha1.Metric{}, + + net.SchemeGroupVersion.WithKind("Certificate"): &net.Certificate{}, + net.SchemeGroupVersion.WithKind("Ingress"): &net.Ingress{}, + net.SchemeGroupVersion.WithKind("ServerlessService"): &net.ServerlessService{}, +} + +func NewDefaultingAdmissionController(ctx context.Context, cmw configmap.Watcher) *controller.Impl { // Decorate contexts with the current state of the config. store := defaultconfig.NewStore(logging.FromContext(ctx).Named("config-store")) store.WatchConfigs(cmw) - ctxFunc := func(ctx context.Context) context.Context { - return v1.WithUpgradeViaDefaulting(store.ToContext(ctx)) - } - return resourcesemantics.NewAdmissionController(ctx, + return defaulting.NewAdmissionController(ctx, // Name of the resource webhook. - // TODO(mattmoor): This can be changed after 0.10, once the lifecycle of - // this object is not managed by OwnerReferences. "webhook.serving.knative.dev", // The path on which to serve the webhook. - "/", + "/defaulting", // The resources to validate and default. - map[schema.GroupVersionKind]resourcesemantics.GenericCRD{ - v1alpha1.SchemeGroupVersion.WithKind("Revision"): &v1alpha1.Revision{}, - v1alpha1.SchemeGroupVersion.WithKind("Configuration"): &v1alpha1.Configuration{}, - v1alpha1.SchemeGroupVersion.WithKind("Route"): &v1alpha1.Route{}, - v1alpha1.SchemeGroupVersion.WithKind("Service"): &v1alpha1.Service{}, - v1beta1.SchemeGroupVersion.WithKind("Revision"): &v1beta1.Revision{}, - v1beta1.SchemeGroupVersion.WithKind("Configuration"): &v1beta1.Configuration{}, - v1beta1.SchemeGroupVersion.WithKind("Route"): &v1beta1.Route{}, - v1beta1.SchemeGroupVersion.WithKind("Service"): &v1beta1.Service{}, - v1.SchemeGroupVersion.WithKind("Revision"): &v1.Revision{}, - v1.SchemeGroupVersion.WithKind("Configuration"): &v1.Configuration{}, - v1.SchemeGroupVersion.WithKind("Route"): &v1.Route{}, - v1.SchemeGroupVersion.WithKind("Service"): &v1.Service{}, - - autoscalingv1alpha1.SchemeGroupVersion.WithKind("PodAutoscaler"): &autoscalingv1alpha1.PodAutoscaler{}, - autoscalingv1alpha1.SchemeGroupVersion.WithKind("Metric"): &autoscalingv1alpha1.Metric{}, - - net.SchemeGroupVersion.WithKind("Certificate"): &net.Certificate{}, - net.SchemeGroupVersion.WithKind("Ingress"): &net.Ingress{}, - net.SchemeGroupVersion.WithKind("ServerlessService"): &net.ServerlessService{}, + types, + + // A function that infuses the context passed to Validate/SetDefaults with custom metadata. + func(ctx context.Context) context.Context { + return v1.WithUpgradeViaDefaulting(store.ToContext(ctx)) }, + // Whether to disallow unknown fields. + true, + ) +} + +func NewValidationAdmissionController(ctx context.Context, cmw configmap.Watcher) *controller.Impl { + return validation.NewAdmissionController(ctx, + + // Name of the resource webhook. + "validation.webhook.serving.knative.dev", + + // The path on which to serve the webhook. + // TODO(mattmoor): We must leave this as '/' because on downgrade the + // validating webhook configuration will be left around and it should exist + // at a path that is configured to handle requests or all mutations will be + // denied. + "/", + + // The resources to validate and default. + types, + // A function that infuses the context passed to Validate/SetDefaults with custom metadata. - ctxFunc, + func(ctx context.Context) context.Context { + return ctx + }, // Whether to disallow unknown fields. true, @@ -136,7 +163,8 @@ func main() { sharedmain.MainWithContext(ctx, "webhook", certificates.NewController, - NewResourceAdmissionController, + NewDefaultingAdmissionController, + NewValidationAdmissionController, NewConfigValidationController, ) } diff --git a/config/500-webhook-configuration.yaml b/config/500-webhook-configuration.yaml index 197082fccd4d..77b16aeded60 100644 --- a/config/500-webhook-configuration.yaml +++ b/config/500-webhook-configuration.yaml @@ -30,6 +30,22 @@ webhooks: --- apiVersion: admissionregistration.k8s.io/v1beta1 kind: ValidatingWebhookConfiguration +metadata: + name: validation.webhook.serving.knative.dev + labels: + serving.knative.dev/release: devel +webhooks: +- admissionReviewVersions: + - v1beta1 + clientConfig: + service: + name: webhook + namespace: knative-serving + failurePolicy: Fail + name: validation.webhook.serving.knative.dev +--- +apiVersion: admissionregistration.k8s.io/v1beta1 +kind: ValidatingWebhookConfiguration metadata: name: config.webhook.serving.knative.dev labels: diff --git a/vendor/knative.dev/pkg/Gopkg.lock b/vendor/knative.dev/pkg/Gopkg.lock index 193efe473408..d0344daad6b2 100644 --- a/vendor/knative.dev/pkg/Gopkg.lock +++ b/vendor/knative.dev/pkg/Gopkg.lock @@ -1326,7 +1326,6 @@ "go.uber.org/zap/zaptest", "golang.org/x/net/context", "golang.org/x/oauth2", - "golang.org/x/oauth2/google", "golang.org/x/sync/errgroup", "google.golang.org/api/container/v1beta1", "google.golang.org/api/iterator", diff --git a/vendor/knative.dev/pkg/OWNERS_ALIASES b/vendor/knative.dev/pkg/OWNERS_ALIASES index 40c15c7954f4..f8e44ba434c4 100644 --- a/vendor/knative.dev/pkg/OWNERS_ALIASES +++ b/vendor/knative.dev/pkg/OWNERS_ALIASES @@ -2,12 +2,10 @@ aliases: pkg-approvers: - evankanderson - mattmoor - - vaikas-google - vaikas apis-approvers: - mattmoor - - vaikas-google - vaikas - n3wscott @@ -16,12 +14,6 @@ aliases: apis-duck-approvers: - mattmoor - - vaikas-google - - vaikas - - cloudevents-approvers: - - n3wscott - - vaikas-google - vaikas configmap-approvers: @@ -68,7 +60,6 @@ aliases: source-approvers: - n3wscott - - vaikas-google - vaikas webhook-approvers: diff --git a/vendor/knative.dev/pkg/RELEASING.md b/vendor/knative.dev/pkg/RELEASING.md index 451ea2828a7e..3299c7398903 100644 --- a/vendor/knative.dev/pkg/RELEASING.md +++ b/vendor/knative.dev/pkg/RELEASING.md @@ -88,3 +88,13 @@ their own release branches, so to update the `knative/pkg` dependency we run: dep ensure -update knative.dev/pkg ./hack/update-deps.sh ``` + +## Revert to Master + +Post release, reverse the process. `Gopkg.toml` should look like: + +```toml +[[override]] + name = "knative.dev/pkg" + branch = "master" +``` diff --git a/vendor/knative.dev/pkg/apis/condition_types.go b/vendor/knative.dev/pkg/apis/condition_types.go index c90438648b09..a3d3f2b2f6aa 100644 --- a/vendor/knative.dev/pkg/apis/condition_types.go +++ b/vendor/knative.dev/pkg/apis/condition_types.go @@ -55,7 +55,6 @@ const ( // Conditions defines a readiness condition for a Knative resource. // See: https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#typical-status-properties // +k8s:deepcopy-gen=true -// +k8s:openapi-gen=true type Condition struct { // Type of condition. // +required diff --git a/vendor/knative.dev/pkg/apis/duck/v1/destination.go b/vendor/knative.dev/pkg/apis/duck/v1/destination.go new file mode 100644 index 000000000000..136e757aeaf6 --- /dev/null +++ b/vendor/knative.dev/pkg/apis/duck/v1/destination.go @@ -0,0 +1,93 @@ +/* +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 v1 + +import ( + "context" + + corev1 "k8s.io/api/core/v1" + "knative.dev/pkg/apis" +) + +// Destination represents a target of an invocation over HTTP. +type Destination struct { + // Ref points to an Addressable. + // +optional + Ref *corev1.ObjectReference `json:"ref,omitempty"` + + // URI can be an absolute URL(non-empty scheme and non-empty host) pointing to the target or a relative URI. Relative URIs will be resolved using the base URI retrieved from Ref. + // +optional + URI *apis.URL `json:"uri,omitempty"` +} + +func (dest *Destination) Validate(ctx context.Context) *apis.FieldError { + if dest == nil { + return nil + } + return ValidateDestination(*dest).ViaField(apis.CurrentField) +} + +// ValidateDestination validates Destination. +func ValidateDestination(dest Destination) *apis.FieldError { + var ref *corev1.ObjectReference + if dest.Ref != nil { + ref = dest.Ref + } + if ref == nil && dest.URI == nil { + return apis.ErrGeneric("expected at least one, got none", "ref", "uri") + } + + if ref != nil && dest.URI != nil && dest.URI.URL().IsAbs() { + return apis.ErrGeneric("Absolute URI is not allowed when Ref or [apiVersion, kind, name] is present", "[apiVersion, kind, name]", "ref", "uri") + } + // IsAbs() check whether the URL has a non-empty scheme. Besides the non-empty scheme, we also require dest.URI has a non-empty host + if ref == nil && dest.URI != nil && (!dest.URI.URL().IsAbs() || dest.URI.Host == "") { + return apis.ErrInvalidValue("Relative URI is not allowed when Ref and [apiVersion, kind, name] is absent", "uri") + } + if ref != nil && dest.URI == nil { + if dest.Ref != nil { + return validateDestinationRef(*ref).ViaField("ref") + } + } + return nil +} + +// GetRef gets the ObjectReference from this Destination, if one is present. If no ref is present, +// then nil is returned. +func (dest *Destination) GetRef() *corev1.ObjectReference { + if dest == nil { + return nil + } + return dest.Ref +} + +func validateDestinationRef(ref corev1.ObjectReference) *apis.FieldError { + // Check the object. + var errs *apis.FieldError + // Required Fields + if ref.Name == "" { + errs = errs.Also(apis.ErrMissingField("name")) + } + if ref.APIVersion == "" { + errs = errs.Also(apis.ErrMissingField("apiVersion")) + } + if ref.Kind == "" { + errs = errs.Also(apis.ErrMissingField("kind")) + } + + return errs +} diff --git a/vendor/knative.dev/pkg/apis/duck/v1/source_types.go b/vendor/knative.dev/pkg/apis/duck/v1/source_types.go index da217c59c772..834a17734f24 100644 --- a/vendor/knative.dev/pkg/apis/duck/v1/source_types.go +++ b/vendor/knative.dev/pkg/apis/duck/v1/source_types.go @@ -25,7 +25,6 @@ import ( "knative.dev/pkg/apis" "knative.dev/pkg/apis/duck" - apisv1alpha1 "knative.dev/pkg/apis/v1alpha1" ) // Source is an Implementable "duck type". @@ -51,7 +50,7 @@ type Source struct { type SourceSpec struct { // Sink is a reference to an object that will resolve to a domain name or a // URI directly to use as the sink. - Sink apisv1alpha1.Destination `json:"sink,omitempty"` + Sink Destination `json:"sink,omitempty"` // CloudEventOverrides defines overrides to control the output format and // modifications of the event sent to the sink. @@ -117,7 +116,7 @@ func (*Source) GetFullType() duck.Populatable { // Populate implements duck.Populatable func (s *Source) Populate() { - s.Spec.Sink = apisv1alpha1.Destination{ + s.Spec.Sink = Destination{ URI: &apis.URL{ Scheme: "https", Host: "tableflip.dev", diff --git a/vendor/knative.dev/pkg/apis/duck/v1/status_types.go b/vendor/knative.dev/pkg/apis/duck/v1/status_types.go index 68a6b4769393..dc48c574ccaa 100644 --- a/vendor/knative.dev/pkg/apis/duck/v1/status_types.go +++ b/vendor/knative.dev/pkg/apis/duck/v1/status_types.go @@ -36,7 +36,6 @@ var _ duck.Implementable = (*Conditions)(nil) // +genclient // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object -// +k8s:openapi-gen=true // KResource is a skeleton type wrapping Conditions in the manner we expect // resource writers defining compatible resources to embed it. We will diff --git a/vendor/knative.dev/pkg/apis/duck/v1/zz_generated.deepcopy.go b/vendor/knative.dev/pkg/apis/duck/v1/zz_generated.deepcopy.go index 6be6207a3abc..12d8c120e547 100644 --- a/vendor/knative.dev/pkg/apis/duck/v1/zz_generated.deepcopy.go +++ b/vendor/knative.dev/pkg/apis/duck/v1/zz_generated.deepcopy.go @@ -21,6 +21,7 @@ limitations under the License. package v1 import ( + corev1 "k8s.io/api/core/v1" runtime "k8s.io/apimachinery/pkg/runtime" apis "knative.dev/pkg/apis" ) @@ -172,6 +173,32 @@ func (in Conditions) DeepCopy() Conditions { return *out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Destination) DeepCopyInto(out *Destination) { + *out = *in + if in.Ref != nil { + in, out := &in.Ref, &out.Ref + *out = new(corev1.ObjectReference) + **out = **in + } + if in.URI != nil { + in, out := &in.URI, &out.URI + *out = new(apis.URL) + (*in).DeepCopyInto(*out) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Destination. +func (in *Destination) DeepCopy() *Destination { + if in == nil { + return nil + } + out := new(Destination) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *KResource) DeepCopyInto(out *KResource) { *out = *in diff --git a/vendor/knative.dev/pkg/apis/v1alpha1/destination.go b/vendor/knative.dev/pkg/apis/duck/v1beta1/destination.go similarity index 99% rename from vendor/knative.dev/pkg/apis/v1alpha1/destination.go rename to vendor/knative.dev/pkg/apis/duck/v1beta1/destination.go index 85c4eebfbe0b..9c247b0305b1 100644 --- a/vendor/knative.dev/pkg/apis/v1alpha1/destination.go +++ b/vendor/knative.dev/pkg/apis/duck/v1beta1/destination.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package v1alpha1 +package v1beta1 import ( "context" diff --git a/vendor/knative.dev/pkg/apis/duck/v1beta1/source_types.go b/vendor/knative.dev/pkg/apis/duck/v1beta1/source_types.go index 9358e35318cb..d4c478939272 100644 --- a/vendor/knative.dev/pkg/apis/duck/v1beta1/source_types.go +++ b/vendor/knative.dev/pkg/apis/duck/v1beta1/source_types.go @@ -25,7 +25,6 @@ import ( "knative.dev/pkg/apis" "knative.dev/pkg/apis/duck" - apisv1alpha1 "knative.dev/pkg/apis/v1alpha1" ) // Source is an Implementable "duck type". @@ -51,7 +50,7 @@ type Source struct { type SourceSpec struct { // Sink is a reference to an object that will resolve to a domain name or a // URI directly to use as the sink. - Sink apisv1alpha1.Destination `json:"sink,omitempty"` + Sink Destination `json:"sink,omitempty"` // CloudEventOverrides defines overrides to control the output format and // modifications of the event sent to the sink. @@ -117,7 +116,7 @@ func (*Source) GetFullType() duck.Populatable { // Populate implements duck.Populatable func (s *Source) Populate() { - s.Spec.Sink = apisv1alpha1.Destination{ + s.Spec.Sink = Destination{ URI: &apis.URL{ Scheme: "https", Host: "tableflip.dev", diff --git a/vendor/knative.dev/pkg/apis/duck/v1beta1/status_types.go b/vendor/knative.dev/pkg/apis/duck/v1beta1/status_types.go index ef6804deae8b..7056b0d095a9 100644 --- a/vendor/knative.dev/pkg/apis/duck/v1beta1/status_types.go +++ b/vendor/knative.dev/pkg/apis/duck/v1beta1/status_types.go @@ -36,7 +36,6 @@ var _ duck.Implementable = (*Conditions)(nil) // +genclient // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object -// +k8s:openapi-gen=true // KResource is a skeleton type wrapping Conditions in the manner we expect // resource writers defining compatible resources to embed it. We will diff --git a/vendor/knative.dev/pkg/apis/duck/v1beta1/zz_generated.deepcopy.go b/vendor/knative.dev/pkg/apis/duck/v1beta1/zz_generated.deepcopy.go index 79e359d88492..eb64a47674ce 100644 --- a/vendor/knative.dev/pkg/apis/duck/v1beta1/zz_generated.deepcopy.go +++ b/vendor/knative.dev/pkg/apis/duck/v1beta1/zz_generated.deepcopy.go @@ -21,6 +21,7 @@ limitations under the License. package v1beta1 import ( + v1 "k8s.io/api/core/v1" runtime "k8s.io/apimachinery/pkg/runtime" apis "knative.dev/pkg/apis" ) @@ -172,6 +173,32 @@ func (in Conditions) DeepCopy() Conditions { return *out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Destination) DeepCopyInto(out *Destination) { + *out = *in + if in.Ref != nil { + in, out := &in.Ref, &out.Ref + *out = new(v1.ObjectReference) + **out = **in + } + if in.URI != nil { + in, out := &in.URI, &out.URI + *out = new(apis.URL) + (*in).DeepCopyInto(*out) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Destination. +func (in *Destination) DeepCopy() *Destination { + if in == nil { + return nil + } + out := new(Destination) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *KResource) DeepCopyInto(out *KResource) { *out = *in diff --git a/vendor/knative.dev/pkg/apis/interfaces.go b/vendor/knative.dev/pkg/apis/interfaces.go index 6b6c772d746f..fef69d8b315f 100644 --- a/vendor/knative.dev/pkg/apis/interfaces.go +++ b/vendor/knative.dev/pkg/apis/interfaces.go @@ -44,15 +44,6 @@ type Convertible interface { ConvertDown(ctx context.Context, from Convertible) error } -// Immutable indicates that a particular type has fields that should -// not change after creation. -// DEPRECATED: Use WithinUpdate / GetBaseline from within Validatable instead. -type Immutable interface { - // CheckImmutableFields checks that the current instance's immutable - // fields haven't changed from the provided original. - CheckImmutableFields(ctx context.Context, original Immutable) *FieldError -} - // Listable indicates that a particular type can be returned via the returned // list type by the API server. type Listable interface { diff --git a/vendor/knative.dev/pkg/apis/v1alpha1/zz_generated.deepcopy.go b/vendor/knative.dev/pkg/apis/v1alpha1/zz_generated.deepcopy.go deleted file mode 100644 index 5640bf0a81b5..000000000000 --- a/vendor/knative.dev/pkg/apis/v1alpha1/zz_generated.deepcopy.go +++ /dev/null @@ -1,52 +0,0 @@ -// +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 v1alpha1 - -import ( - v1 "k8s.io/api/core/v1" - apis "knative.dev/pkg/apis" -) - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *Destination) DeepCopyInto(out *Destination) { - *out = *in - if in.Ref != nil { - in, out := &in.Ref, &out.Ref - *out = new(v1.ObjectReference) - **out = **in - } - if in.URI != nil { - in, out := &in.URI, &out.URI - *out = new(apis.URL) - (*in).DeepCopyInto(*out) - } - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Destination. -func (in *Destination) DeepCopy() *Destination { - if in == nil { - return nil - } - out := new(Destination) - in.DeepCopyInto(out) - return out -} diff --git a/vendor/knative.dev/pkg/apis/volatile_time.go b/vendor/knative.dev/pkg/apis/volatile_time.go index 48d790d92eae..3d2daa2772c1 100644 --- a/vendor/knative.dev/pkg/apis/volatile_time.go +++ b/vendor/knative.dev/pkg/apis/volatile_time.go @@ -22,7 +22,6 @@ import ( ) // VolatileTime wraps metav1.Time -// +k8s:openapi-gen=true type VolatileTime struct { Inner metav1.Time } diff --git a/vendor/knative.dev/pkg/cloudevents/README.md b/vendor/knative.dev/pkg/cloudevents/README.md deleted file mode 100644 index 0489cb5d77bb..000000000000 --- a/vendor/knative.dev/pkg/cloudevents/README.md +++ /dev/null @@ -1,151 +0,0 @@ -# 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 ( - "knative.dev/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" - - "knative.dev/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/knative.dev/pkg/cloudevents/builder.go b/vendor/knative.dev/pkg/cloudevents/builder.go deleted file mode 100644 index 4cf3706d964d..000000000000 --- a/vendor/knative.dev/pkg/cloudevents/builder.go +++ /dev/null @@ -1,135 +0,0 @@ -/* -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/knative.dev/pkg/cloudevents/client.go b/vendor/knative.dev/pkg/cloudevents/client.go deleted file mode 100644 index 9846edf1da3a..000000000000 --- a/vendor/knative.dev/pkg/cloudevents/client.go +++ /dev/null @@ -1,81 +0,0 @@ -/* -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/knative.dev/pkg/cloudevents/doc.go b/vendor/knative.dev/pkg/cloudevents/doc.go deleted file mode 100644 index 62bc3b02ce11..000000000000 --- a/vendor/knative.dev/pkg/cloudevents/doc.go +++ /dev/null @@ -1,22 +0,0 @@ -/* -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/knative.dev/pkg/cloudevents/encoding_binary.go b/vendor/knative.dev/pkg/cloudevents/encoding_binary.go deleted file mode 100644 index 8ed4fbfaad15..000000000000 --- a/vendor/knative.dev/pkg/cloudevents/encoding_binary.go +++ /dev/null @@ -1,125 +0,0 @@ -/* -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/knative.dev/pkg/cloudevents/encoding_structured.go b/vendor/knative.dev/pkg/cloudevents/encoding_structured.go deleted file mode 100644 index 8670241d38f3..000000000000 --- a/vendor/knative.dev/pkg/cloudevents/encoding_structured.go +++ /dev/null @@ -1,143 +0,0 @@ -/* -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/knative.dev/pkg/cloudevents/event.go b/vendor/knative.dev/pkg/cloudevents/event.go deleted file mode 100644 index 48f85afcad46..000000000000 --- a/vendor/knative.dev/pkg/cloudevents/event.go +++ /dev/null @@ -1,205 +0,0 @@ -/* -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 -} - -// 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/knative.dev/pkg/cloudevents/event_v01.go b/vendor/knative.dev/pkg/cloudevents/event_v01.go deleted file mode 100644 index 2ba67ca0c0dd..000000000000 --- a/vendor/knative.dev/pkg/cloudevents/event_v01.go +++ /dev/null @@ -1,236 +0,0 @@ -/* -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/knative.dev/pkg/cloudevents/event_v02.go b/vendor/knative.dev/pkg/cloudevents/event_v02.go deleted file mode 100644 index dc64767cc59d..000000000000 --- a/vendor/knative.dev/pkg/cloudevents/event_v02.go +++ /dev/null @@ -1,261 +0,0 @@ -/* -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/knative.dev/pkg/cloudevents/handler.go b/vendor/knative.dev/pkg/cloudevents/handler.go deleted file mode 100644 index 3b8575a1cfcc..000000000000 --- a/vendor/knative.dev/pkg/cloudevents/handler.go +++ /dev/null @@ -1,401 +0,0 @@ -/* -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/knative.dev/pkg/codegen/cmd/injection-gen/generators/fakeinformer.go b/vendor/knative.dev/pkg/codegen/cmd/injection-gen/generators/fakeinformer.go index 9218c418dd47..c8e4223002d0 100644 --- a/vendor/knative.dev/pkg/codegen/cmd/injection-gen/generators/fakeinformer.go +++ b/vendor/knative.dev/pkg/codegen/cmd/injection-gen/generators/fakeinformer.go @@ -32,7 +32,6 @@ type fakeInformerGenerator struct { generator.DefaultGen outputPackage string imports namer.ImportTracker - filtered bool typeToGenerate *types.Type groupVersion clientgentypes.GroupVersion diff --git a/vendor/knative.dev/pkg/controller/controller.go b/vendor/knative.dev/pkg/controller/controller.go index 19b87e6d44e0..d385908c7640 100644 --- a/vendor/knative.dev/pkg/controller/controller.go +++ b/vendor/knative.dev/pkg/controller/controller.go @@ -186,6 +186,14 @@ func (c *Impl) Enqueue(obj interface{}) { c.EnqueueKey(types.NamespacedName{Namespace: object.GetNamespace(), Name: object.GetName()}) } +// EnqueueSentinel returns a Enqueue method which will always enqueue a +// predefined key instead of the object key. +func (c *Impl) EnqueueSentinel(k types.NamespacedName) func(interface{}) { + return func(interface{}) { + c.EnqueueKey(k) + } +} + // EnqueueControllerOf takes a resource, identifies its controller resource, // converts it into a namespace/name string, and passes that to EnqueueKey. func (c *Impl) EnqueueControllerOf(obj interface{}) { diff --git a/vendor/knative.dev/pkg/controller/stats_reporter.go b/vendor/knative.dev/pkg/controller/stats_reporter.go index b829c9f2ef79..de0a938d444a 100644 --- a/vendor/knative.dev/pkg/controller/stats_reporter.go +++ b/vendor/knative.dev/pkg/controller/stats_reporter.go @@ -174,15 +174,9 @@ func init() { Aggregation: reconcileDistribution, TagKeys: []tag.Key{reconcilerTagKey, keyTagKey, successTagKey}, }} - for _, view := range wp.DefaultViews() { - views = append(views, view) - } - for _, view := range rp.DefaultViews() { - views = append(views, view) - } - for _, view := range cp.DefaultViews() { - views = append(views, view) - } + views = append(views, wp.DefaultViews()...) + views = append(views, rp.DefaultViews()...) + views = append(views, cp.DefaultViews()...) // Create views to see our measurements. This can return an error if // a previously-registered view has the same name with a different value. diff --git a/vendor/knative.dev/pkg/hack/update-codegen.sh b/vendor/knative.dev/pkg/hack/update-codegen.sh index fdffe6513d83..e75a975c7550 100755 --- a/vendor/knative.dev/pkg/hack/update-codegen.sh +++ b/vendor/knative.dev/pkg/hack/update-codegen.sh @@ -20,9 +20,9 @@ set -o pipefail source $(dirname $0)/../vendor/knative.dev/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)} +CODEGEN_PKG=${CODEGEN_PKG:-$(cd ${REPO_ROOT_DIR}; ls -d -1 $(dirname $0)/../vendor/k8s.io/code-generator 2>/dev/null || echo ../code-generator)} -go install ./vendor/k8s.io/code-generator/cmd/deepcopy-gen +go install $(dirname $0)/../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 @@ -64,7 +64,7 @@ ${CODEGEN_PKG}/generate-groups.sh "deepcopy" \ # Depends on generate-groups.sh to install bin/deepcopy-gen ${GOPATH}/bin/deepcopy-gen --input-dirs \ - knative.dev/pkg/apis,knative.dev/pkg/apis/v1alpha1,knative.dev/pkg/logging,knative.dev/pkg/testing \ + knative.dev/pkg/apis,knative.dev/pkg/logging,knative.dev/pkg/testing \ -O zz_generated.deepcopy \ --go-header-file ${REPO_ROOT_DIR}/hack/boilerplate/boilerplate.go.txt diff --git a/vendor/knative.dev/pkg/logging/config.go b/vendor/knative.dev/pkg/logging/config.go index 2317c9271157..192c424158a8 100644 --- a/vendor/knative.dev/pkg/logging/config.go +++ b/vendor/knative.dev/pkg/logging/config.go @@ -38,7 +38,7 @@ const ( fallbackLoggerName = "fallback-logger" ) -var emptyLoggerConfigError = errors.New("empty logger configuration") +var errEmptyLoggerConfig = errors.New("empty logger configuration") // NewLogger creates a logger with the supplied configuration. // In addition to the logger, it returns AtomicLevel that can @@ -112,7 +112,7 @@ func newLoggerFromConfig(configJSON string, levelOverride string, opts []zap.Opt func zapConfigFromJSON(configJSON string) (*zap.Config, error) { if configJSON == "" { - return nil, emptyLoggerConfigError + return nil, errEmptyLoggerConfig } loggingCfg := &zap.Config{} @@ -206,7 +206,7 @@ func UpdateLevelFromConfigMap(logger *zap.SugaredLogger, atomicLevel zap.AtomicL // reset to global level loggingCfg, err := zapConfigFromJSON(config.LoggingConfig) switch { - case err == emptyLoggerConfigError: + case err == errEmptyLoggerConfig: level = zap.NewAtomicLevel().Level() case err != nil: logger.With(zap.Error(err)).Errorf("Failed to parse logger configuration. "+ diff --git a/vendor/knative.dev/pkg/metrics/config.go b/vendor/knative.dev/pkg/metrics/config.go index af7e3e729952..8ffa0dae8474 100644 --- a/vendor/knative.dev/pkg/metrics/config.go +++ b/vendor/knative.dev/pkg/metrics/config.go @@ -17,6 +17,7 @@ limitations under the License. package metrics import ( + "context" "encoding/json" "errors" "fmt" @@ -27,6 +28,8 @@ import ( "time" "go.uber.org/zap" + "go.opencensus.io/stats" + "knative.dev/pkg/metrics/metricskey" ) const ( @@ -46,11 +49,10 @@ const ( ReportingPeriodKey = "metrics.reporting-period-seconds" StackdriverCustomMetricSubDomainKey = "metrics.stackdriver-custom-metrics-subdomain" // Stackdriver client configuration keys - stackdriverProjectIDKey = "metrics.stackdriver-project-id" - stackdriverGCPLocationKey = "metrics.stackdriver-gcp-location" - stackdriverClusterNameKey = "metrics.stackdriver-cluster-name" - stackdriverGCPSecretNameKey = "metrics.stackdriver-gcp-secret-name" - stackdriverGCPSecretNamespaceKey = "metrics.stackdriver-gcp-secret-namespace" + StackdriverProjectIDKey = "metrics.stackdriver-project-id" + StackdriverGCPLocationKey = "metrics.stackdriver-gcp-location" + StackdriverClusterNameKey = "metrics.stackdriver-cluster-name" + StackdriverUseSecretKey = "metrics.stackdriver-use-secret" // Stackdriver is used for Stackdriver backend Stackdriver metricsBackend = "stackdriver" @@ -75,22 +77,16 @@ type metricsConfig struct { // If duration is less than or equal to zero, it enables the default behavior. reportingPeriod time.Duration + // recorder provides a hook for performing custom transformations before + // writing the metrics to the stats.RecordWithOptions interface. + recorder func(context.Context, stats.Measurement, ...stats.Options) error + // ---- Prometheus specific below ---- // prometheusPort is the port where metrics are exposed in Prometheus // format. It defaults to 9090. prometheusPort int // ---- Stackdriver specific below ---- - // allowStackdriverCustomMetrics indicates whether it is allowed to send metrics to - // Stackdriver using "global" resource type and custom metric type if the - // metrics are not supported by the registered monitored resource types. Setting this - // flag to "true" could cause extra Stackdriver charge. - // If backendDestination is not Stackdriver, this is ignored. - allowStackdriverCustomMetrics bool - // stackdriverCustomMetricsSubDomain is the subdomain to use when sending custom metrics to StackDriver. - // If not specified, the default is `knative.dev`. - // If backendDestination is not Stackdriver, this is ignored. - stackdriverCustomMetricsSubDomain string // True if backendDestination equals to "stackdriver". Store this in a variable // to reduce string comparison operations. isStackdriverBackend bool @@ -103,11 +99,11 @@ type metricsConfig struct { // Store this in a variable to reduce string join operations. stackdriverCustomMetricTypePrefix string // stackdriverClientConfig is the metadata to configure the metrics exporter's Stackdriver client. - stackdriverClientConfig stackdriverClientConfig + stackdriverClientConfig StackdriverClientConfig } -// stackdriverClientConfig encapsulates the metadata required to configure a Stackdriver client. -type stackdriverClientConfig struct { +// StackdriverClientConfig encapsulates the metadata required to configure a Stackdriver client. +type StackdriverClientConfig struct { // ProjectID is the stackdriver project ID to which data is uploaded. // This is not necessarily the GCP project ID where the Kubernetes cluster is hosted. // Required when the Kubernetes cluster is not hosted on GCE. @@ -119,25 +115,31 @@ type stackdriverClientConfig struct { // ClusterName is the cluster name with which the data will be associated in Stackdriver. // Required when the Kubernetes cluster is not hosted on GCE. ClusterName string - // GCPSecretName is the optional GCP service account key which will be used to - // authenticate with Stackdriver. If not provided, Google Application Default Credentials + // UseSecret is whether the credentials stored in a Kubernetes Secret should be used to + // authenticate with Stackdriver. The Secret name and namespace can be specified by calling + // metrics.SetStackdriverSecretLocation. + // If UseSecret is false, Google Application Default Credentials // will be used (https://cloud.google.com/docs/authentication/production). - GCPSecretName string - // GCPSecretNamespace is the Kubernetes namespace where GCPSecretName is located. - // The Kubernetes ServiceAccount used by the pod that is exporting data to - // Stackdriver should have access to Secrets in this namespace. - GCPSecretNamespace string + UseSecret bool +} + +// NewStackdriverClientConfigFromMap creates a stackdriverClientConfig from the given map +func NewStackdriverClientConfigFromMap(config map[string]string) *StackdriverClientConfig { + return &StackdriverClientConfig{ + ProjectID: config[StackdriverProjectIDKey], + GCPLocation: config[StackdriverGCPLocationKey], + ClusterName: config[StackdriverClusterNameKey], + UseSecret: strings.EqualFold(config[StackdriverUseSecretKey], "true"), + } } -// newStackdriverClientConfigFromMap creates a stackdriverClientConfig from the given map -func newStackdriverClientConfigFromMap(config map[string]string) *stackdriverClientConfig { - return &stackdriverClientConfig{ - ProjectID: config[stackdriverProjectIDKey], - GCPLocation: config[stackdriverGCPLocationKey], - ClusterName: config[stackdriverClusterNameKey], - GCPSecretName: config[stackdriverGCPSecretNameKey], - GCPSecretNamespace: config[stackdriverGCPSecretNamespaceKey], +// Record applies the `ros` Options to `ms` and then records the resulting +// measurements in the metricsConfig's designated backend. +func (mc *metricsConfig) Record(ctx context.Context, ms stats.Measurement, ros ...stats.Options) error { + if mc == nil || mc.recorder == nil { + return stats.RecordWithOptions(ctx, append(ros, stats.WithMeasurements(ms))...) } + return mc.recorder(ctx, ms, ros...) } func createMetricsConfig(ops ExporterOptions, logger *zap.SugaredLogger) (*metricsConfig, error) { @@ -190,22 +192,37 @@ func createMetricsConfig(ops ExporterOptions, logger *zap.SugaredLogger) (*metri // use the application default credentials. If that is not available, Opencensus would fail to create the // metrics exporter. if mc.backendDestination == Stackdriver { - scc := newStackdriverClientConfigFromMap(m) + scc := NewStackdriverClientConfigFromMap(m) mc.stackdriverClientConfig = *scc mc.isStackdriverBackend = true + var allowCustomMetrics bool + var err error mc.stackdriverMetricTypePrefix = path.Join(mc.domain, mc.component) - mc.stackdriverCustomMetricsSubDomain = defaultCustomMetricSubDomain - if sdcmd, ok := m[StackdriverCustomMetricSubDomainKey]; ok && sdcmd != "" { - mc.stackdriverCustomMetricsSubDomain = sdcmd + customMetricsSubDomain := m[StackdriverCustomMetricSubDomainKey] + if customMetricsSubDomain == "" { + customMetricsSubDomain = defaultCustomMetricSubDomain } - mc.stackdriverCustomMetricTypePrefix = path.Join(customMetricTypePrefix, mc.stackdriverCustomMetricsSubDomain, mc.component) - if ascmStr, ok := m[AllowStackdriverCustomMetricsKey]; ok && ascmStr != "" { - ascmBool, err := strconv.ParseBool(ascmStr) + mc.stackdriverCustomMetricTypePrefix = path.Join(customMetricTypePrefix, customMetricsSubDomain, mc.component) + if ascmStr := m[AllowStackdriverCustomMetricsKey]; ascmStr != "" { + allowCustomMetrics, err = strconv.ParseBool(ascmStr) if err != nil { return nil, fmt.Errorf("invalid %s value %q", AllowStackdriverCustomMetricsKey, ascmStr) } - mc.allowStackdriverCustomMetrics = ascmBool + } + + if !allowCustomMetrics { + servingOrEventing := metricskey.KnativeRevisionMetrics.Union( + metricskey.KnativeTriggerMetrics) + mc.recorder = func(ctx context.Context, ms stats.Measurement, ros... stats.Options) error { + metricType := path.Join(mc.stackdriverMetricTypePrefix, ms.Measure().Name()) + + if servingOrEventing.Has(metricType) { + return stats.RecordWithOptions(ctx, append(ros, stats.WithMeasurements(ms))...) + } + // Otherwise, skip (because it won't be accepted) + return nil + } } } diff --git a/vendor/knative.dev/pkg/metrics/metricskey/constants_eventing.go b/vendor/knative.dev/pkg/metrics/metricskey/constants_eventing.go index 081f9005948b..7362ad037e34 100644 --- a/vendor/knative.dev/pkg/metrics/metricskey/constants_eventing.go +++ b/vendor/knative.dev/pkg/metrics/metricskey/constants_eventing.go @@ -36,7 +36,10 @@ const ( // LabelResourceGroup is the name of the resource CRD. LabelResourceGroup = "resource_group" - // LabelBrokerName is the label for the name of the Trigger's broker. + // LabelTriggerName is the label for the name of the Trigger. + LabelTriggerName = "trigger_name" + + // LabelBrokerName is the label for the name of the Broker. LabelBrokerName = "broker_name" // LabelEventType is the label for the name of the event type. @@ -47,9 +50,6 @@ const ( // LabelFilterType is the label for the Trigger filter attribute "type". LabelFilterType = "filter_type" - - // LabelFilterSource is the label for the Trigger filter attribute "source". - LabelFilterSource = "filter_source" ) var ( @@ -59,16 +59,16 @@ var ( LabelLocation, LabelClusterName, LabelNamespaceName, - LabelName, LabelBrokerName, + LabelTriggerName, ) // KnativeTriggerMetrics stores a set of metric types which are supported // by resource type knative_trigger. KnativeTriggerMetrics = sets.NewString( - "knative.dev/eventing/trigger/event_count", - "knative.dev/eventing/trigger/event_processing_latencies", - "knative.dev/eventing/trigger/event_dispatch_latencies", + "knative.dev/internal/eventing/trigger/event_count", + "knative.dev/internal/eventing/trigger/event_processing_latencies", + "knative.dev/internal/eventing/trigger/event_dispatch_latencies", ) // KnativeBrokerLabels stores the set of resource labels for resource type knative_broker. @@ -77,13 +77,13 @@ var ( LabelLocation, LabelClusterName, LabelNamespaceName, - LabelName, + LabelBrokerName, ) // KnativeBrokerMetrics stores a set of metric types which are supported // by resource type knative_trigger. KnativeBrokerMetrics = sets.NewString( - "knative.dev/eventing/broker/event_count", + "knative.dev/internal/eventing/broker/event_count", ) // KnativeSourceLabels stores the set of resource labels for resource type knative_source. diff --git a/vendor/knative.dev/pkg/metrics/metricstest/metricstest.go b/vendor/knative.dev/pkg/metrics/metricstest/metricstest.go index 0f9678884c6a..bc7a92d307c2 100644 --- a/vendor/knative.dev/pkg/metrics/metricstest/metricstest.go +++ b/vendor/knative.dev/pkg/metrics/metricstest/metricstest.go @@ -143,6 +143,7 @@ func checkExactlyOneRow(t *testing.T, name string) *view.Row { } if len(d) != 1 { t.Errorf("For metric %s: Reporter.Report() len(d)=%v, want 1", name, len(d)) + return nil } return d[0] diff --git a/vendor/knative.dev/pkg/metrics/monitored_resources_eventing.go b/vendor/knative.dev/pkg/metrics/monitored_resources_eventing.go index ecf817b59df5..87c2b55a96d7 100644 --- a/vendor/knative.dev/pkg/metrics/monitored_resources_eventing.go +++ b/vendor/knative.dev/pkg/metrics/monitored_resources_eventing.go @@ -59,8 +59,8 @@ func (kt *KnativeTrigger) MonitoredResource() (resType string, labels map[string metricskey.LabelLocation: kt.Location, metricskey.LabelClusterName: kt.ClusterName, metricskey.LabelNamespaceName: kt.NamespaceName, - metricskey.LabelName: kt.TriggerName, metricskey.LabelBrokerName: kt.BrokerName, + metricskey.LabelTriggerName: kt.TriggerName, } return metricskey.ResourceTypeKnativeTrigger, labels } @@ -71,7 +71,7 @@ func (kb *KnativeBroker) MonitoredResource() (resType string, labels map[string] metricskey.LabelLocation: kb.Location, metricskey.LabelClusterName: kb.ClusterName, metricskey.LabelNamespaceName: kb.NamespaceName, - metricskey.LabelName: kb.BrokerName, + metricskey.LabelBrokerName: kb.BrokerName, } return metricskey.ResourceTypeKnativeBroker, labels } @@ -98,7 +98,7 @@ func GetKnativeBrokerMonitoredResource( ClusterName: gm.cluster, // The rest resource labels are from metrics labels. NamespaceName: valueOrUnknown(metricskey.LabelNamespaceName, tagsMap), - BrokerName: valueOrUnknown(metricskey.LabelName, tagsMap), + BrokerName: valueOrUnknown(metricskey.LabelBrokerName, tagsMap), } var newTags []tag.Tag @@ -122,8 +122,8 @@ func GetKnativeTriggerMonitoredResource( ClusterName: gm.cluster, // The rest resource labels are from metrics labels. NamespaceName: valueOrUnknown(metricskey.LabelNamespaceName, tagsMap), - TriggerName: valueOrUnknown(metricskey.LabelName, tagsMap), BrokerName: valueOrUnknown(metricskey.LabelBrokerName, tagsMap), + TriggerName: valueOrUnknown(metricskey.LabelTriggerName, tagsMap), } var newTags []tag.Tag diff --git a/vendor/knative.dev/pkg/metrics/record.go b/vendor/knative.dev/pkg/metrics/record.go index a8756837a83d..397f9be77c13 100644 --- a/vendor/knative.dev/pkg/metrics/record.go +++ b/vendor/knative.dev/pkg/metrics/record.go @@ -18,52 +18,18 @@ package metrics import ( "context" - "path" "go.opencensus.io/stats" - "knative.dev/pkg/metrics/metricskey" ) // TODO should be properly refactored and pieces should move to eventing and serving, as appropriate. // See https://github.com/knative/pkg/issues/608 -// Record decides whether to record one measurement via OpenCensus based on the -// following conditions: -// 1) No package level metrics config. In this case it just proxies to OpenCensus -// based on the assumption that users expect the metrics to be recorded when -// they call this function. Users must ensure metrics config are set before -// using this function to get expected behavior. -// 2) The backend is not Stackdriver. -// 3) The backend is Stackdriver and it is allowed to use custom metrics. -// 4) The backend is Stackdriver and the metric is one of the built-in metrics: "knative_revision", "knative_broker", -// "knative_trigger", "knative_source". +// Record stores the given Measurement from `ms` in the current metrics backend. func Record(ctx context.Context, ms stats.Measurement, ros ...stats.Options) { mc := getCurMetricsConfig() - ros = append(ros, stats.WithMeasurements(ms)) - - // Condition 1) - if mc == nil { - stats.RecordWithOptions(ctx, ros...) - return - } - - // Condition 2) and 3) - if !mc.isStackdriverBackend || mc.allowStackdriverCustomMetrics { - stats.RecordWithOptions(ctx, ros...) - return - } - - // Condition 4) - metricType := path.Join(mc.stackdriverMetricTypePrefix, ms.Measure().Name()) - isServingBuiltIn := metricskey.KnativeRevisionMetrics.Has(metricType) - isEventingBuiltIn := metricskey.KnativeTriggerMetrics.Has(metricType) || - metricskey.KnativeBrokerMetrics.Has(metricType) || - metricskey.KnativeSourceMetrics.Has(metricType) - - if isServingBuiltIn || isEventingBuiltIn { - stats.RecordWithOptions(ctx, ros...) - } + mc.Record(ctx, ms, ros...) } // Buckets125 generates an array of buckets with approximate powers-of-two diff --git a/vendor/knative.dev/pkg/metrics/stackdriver_exporter.go b/vendor/knative.dev/pkg/metrics/stackdriver_exporter.go index bb396ac0c6d0..ff5deb581b1c 100644 --- a/vendor/knative.dev/pkg/metrics/stackdriver_exporter.go +++ b/vendor/knative.dev/pkg/metrics/stackdriver_exporter.go @@ -40,22 +40,63 @@ const ( // defaultCustomMetricSubDomain is the default subdomain to use for unsupported metrics by monitored resource types. // See: https://cloud.google.com/monitoring/api/ref_v3/rest/v3/projects.metricDescriptors#MetricDescriptor defaultCustomMetricSubDomain = "knative.dev" - // secretNamespaceDefault is the namespace to search for a k8s Secret to pass to Stackdriver client to authenticate with Stackdriver. - secretNamespaceDefault = "default" + // StackdriverSecretNamespaceDefault is the default namespace to search for a k8s Secret to pass to Stackdriver client to authenticate with Stackdriver. + StackdriverSecretNamespaceDefault = "default" + // StackdriverSecretNameDefault is the default name of the k8s Secret to pass to Stackdriver client to authenticate with Stackdriver. + StackdriverSecretNameDefault = "stackdriver-service-account-key" // secretDataFieldKey is the name of the k8s Secret field that contains the Secret's key. secretDataFieldKey = "key.json" ) var ( + // gcpMetadataFunc is the function used to fetch GCP metadata. + // In product usage, this is always set to function retrieveGCPMetadata. + // In unit tests this is set to a fake one to avoid calling GCP metadata + // service. + gcpMetadataFunc func() *gcpMetadata + + // newStackdriverExporterFunc is the function used to create new stackdriver + // exporter. + // In product usage, this is always set to function newOpencensusSDExporter. + // In unit tests this is set to a fake one to avoid calling actual Google API + // service. + newStackdriverExporterFunc func(stackdriver.Options) (view.Exporter, error) + // kubeclient is the in-cluster Kubernetes kubeclient, which is lazy-initialized on first use. kubeclient *kubernetes.Clientset // initClientOnce is the lazy initializer for kubeclient. initClientOnce sync.Once // kubeclientInitErr capture an error during initClientOnce kubeclientInitErr error + + // stackdriverMtx protects setting secretNamespace and secretName and useStackdriverSecretEnabled + stackdriverMtx sync.RWMutex + // secretName is the name of the k8s Secret to pass to Stackdriver client to authenticate with Stackdriver. + secretName = StackdriverSecretNameDefault + // secretNamespace is the namespace to search for a k8s Secret to pass to Stackdriver client to authenticate with Stackdriver. + secretNamespace = StackdriverSecretNamespaceDefault + // useStackdriverSecretEnabled specifies whether or not the exporter can be configured with a Secret. + // Consuming packages must do explicitly enable this by calling SetStackdriverSecretLocation. + useStackdriverSecretEnabled = false ) +// SetStackdriverSecretLocation sets the name and namespace of the Secret that can be used to authenticate with Stackdriver. +// The Secret is only used if both: +// 1. This function has been explicitly called to set the name and namespace +// 2. Users set metricsConfig.stackdriverClientConfig.UseSecret to "true" +func SetStackdriverSecretLocation(name string, namespace string) { + stackdriverMtx.Lock() + defer stackdriverMtx.Unlock() + secretName = name + secretNamespace = namespace + useStackdriverSecretEnabled = true +} + func init() { + // Set gcpMetadataFunc to call GCP metadata service. + gcpMetadataFunc = retrieveGCPMetadata + newStackdriverExporterFunc = newOpencensusSDExporter + kubeclientInitErr = nil } @@ -73,7 +114,7 @@ func newStackdriverExporter(config *metricsConfig, logger *zap.SugaredLogger) (v logger.Warnw("Issue configuring Stackdriver exporter client options, no additional client options will be used: ", zap.Error(err)) } // Automatically fall back on Google application default credentials - e, err := newOpencensusSDExporter(stackdriver.Options{ + e, err := newStackdriverExporterFunc(stackdriver.Options{ ProjectID: gm.project, Location: gm.location, MonitoringClientOptions: co, @@ -93,15 +134,19 @@ func newStackdriverExporter(config *metricsConfig, logger *zap.SugaredLogger) (v // getStackdriverExporterClientOptions creates client options for the opencensus Stackdriver exporter from the given stackdriverClientConfig. // On error, an empty array of client options is returned. -func getStackdriverExporterClientOptions(sdconfig *stackdriverClientConfig) ([]option.ClientOption, error) { +func getStackdriverExporterClientOptions(sdconfig *StackdriverClientConfig) ([]option.ClientOption, error) { var co []option.ClientOption - if sdconfig.GCPSecretName != "" { + if sdconfig.UseSecret && useStackdriverSecretEnabled { secret, err := getStackdriverSecret(sdconfig) if err != nil { return co, err } - co = append(co, convertSecretToExporterOption(secret)) + if opt, err := convertSecretToExporterOption(secret); err == nil { + co = append(co, opt) + } else { + return co, err + } } return co, nil @@ -111,7 +156,7 @@ func getStackdriverExporterClientOptions(sdconfig *stackdriverClientConfig) ([]o // to Stackdriver. Values can come from the GCE metadata server or the config. // Values explicitly set in the config take the highest precedent. func getMergedGCPMetadata(config *metricsConfig) *gcpMetadata { - gm := retrieveGCPMetadata() + gm := gcpMetadataFunc() if config.stackdriverClientConfig.ProjectID != "" { gm.project = config.stackdriverClientConfig.ProjectID } @@ -164,28 +209,30 @@ func getMetricTypeFunc(metricTypePrefix, customMetricTypePrefix string) func(vie } // getStackdriverSecret returns the Kubernetes Secret specified in the given config. -func getStackdriverSecret(sdconfig *stackdriverClientConfig) (*corev1.Secret, error) { +// TODO(anniefu): Update exporter if Secret changes (https://github.com/knative/pkg/issues/842) +func getStackdriverSecret(sdconfig *StackdriverClientConfig) (*corev1.Secret, error) { if err := ensureKubeclient(); err != nil { return nil, err } - ns := sdconfig.GCPSecretNamespace - if ns == "" { - ns = secretNamespaceDefault - } + stackdriverMtx.RLock() + defer stackdriverMtx.RUnlock() - sec, secErr := kubeclient.CoreV1().Secrets(ns).Get(sdconfig.GCPSecretName, metav1.GetOptions{}) + sec, secErr := kubeclient.CoreV1().Secrets(secretNamespace).Get(secretName, metav1.GetOptions{}) if secErr != nil { - return nil, fmt.Errorf("Error getting Secret [%v] in namespace [%v]: %v", sdconfig.GCPSecretName, sdconfig.GCPSecretNamespace, secErr) + return nil, fmt.Errorf("Error getting Secret [%v] in namespace [%v]: %v", secretName, secretNamespace, secErr) } return sec, nil } // convertSecretToExporterOption converts a Kubernetes Secret to an OpenCensus Stackdriver Exporter Option. -func convertSecretToExporterOption(secret *corev1.Secret) option.ClientOption { - return option.WithCredentialsJSON(secret.Data[secretDataFieldKey]) +func convertSecretToExporterOption(secret *corev1.Secret) (option.ClientOption, error) { + if data, ok := secret.Data[secretDataFieldKey]; ok { + return option.WithCredentialsJSON(data), nil + } + return nil, fmt.Errorf("Expected Secret to store key in data field named [%v]", secretDataFieldKey) } // ensureKubeclient is the lazy initializer for kubeclient. diff --git a/vendor/knative.dev/pkg/profiling/server.go b/vendor/knative.dev/pkg/profiling/server.go index 22089ed5eb91..fb27a5180977 100644 --- a/vendor/knative.dev/pkg/profiling/server.go +++ b/vendor/knative.dev/pkg/profiling/server.go @@ -76,8 +76,8 @@ func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { } } -func readProfilingFlag(configMap *corev1.ConfigMap) (bool, error) { - profiling, ok := configMap.Data[profilingKey] +func ReadProfilingFlag(config map[string]string) (bool, error) { + profiling, ok := config[profilingKey] if !ok { return false, nil } @@ -91,7 +91,7 @@ func readProfilingFlag(configMap *corev1.ConfigMap) (bool, error) { // UpdateFromConfigMap modifies the Enabled flag in the Handler // according to the value in the given ConfigMap func (h *Handler) UpdateFromConfigMap(configMap *corev1.ConfigMap) { - enabled, err := readProfilingFlag(configMap) + enabled, err := ReadProfilingFlag(configMap.Data) if err != nil { h.log.Errorw("Failed to update the profiling flag", zap.Error(err)) return diff --git a/vendor/knative.dev/pkg/reconciler/testing/sorter.go b/vendor/knative.dev/pkg/reconciler/testing/sorter.go index 27061b69d39b..2c1e91923d93 100644 --- a/vendor/knative.dev/pkg/reconciler/testing/sorter.go +++ b/vendor/knative.dev/pkg/reconciler/testing/sorter.go @@ -89,5 +89,5 @@ func (o *ObjectSorter) IndexerForObjectType(obj runtime.Object) cache.Indexer { } func emptyIndexer() cache.Indexer { - return cache.NewIndexer(cache.MetaNamespaceKeyFunc, cache.Indexers{}) + return cache.NewIndexer(cache.MetaNamespaceKeyFunc, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}) } diff --git a/vendor/knative.dev/pkg/resolver/addressable_resolver.go b/vendor/knative.dev/pkg/resolver/addressable_resolver.go index e4d572a2a38a..3358514ac8da 100644 --- a/vendor/knative.dev/pkg/resolver/addressable_resolver.go +++ b/vendor/knative.dev/pkg/resolver/addressable_resolver.go @@ -28,7 +28,6 @@ import ( "knative.dev/pkg/apis" pkgapisduck "knative.dev/pkg/apis/duck" duckv1beta1 "knative.dev/pkg/apis/duck/v1beta1" - apisv1alpha1 "knative.dev/pkg/apis/v1alpha1" "knative.dev/pkg/controller" "knative.dev/pkg/network" "knative.dev/pkg/tracker" @@ -63,7 +62,7 @@ func NewURIResolver(ctx context.Context, callback func(types.NamespacedName)) *U } // URIFromDestination resolves a Destination into a URI string. -func (r *URIResolver) URIFromDestination(dest apisv1alpha1.Destination, parent interface{}) (string, error) { +func (r *URIResolver) URIFromDestination(dest duckv1beta1.Destination, parent interface{}) (string, error) { var deprecatedObjectReference *corev1.ObjectReference if dest.DeprecatedAPIVersion == "" && dest.DeprecatedKind == "" && dest.DeprecatedName == "" && dest.DeprecatedNamespace == "" { deprecatedObjectReference = nil diff --git a/vendor/knative.dev/pkg/test/ghutil/fakeghutil/fakeghutil.go b/vendor/knative.dev/pkg/test/ghutil/fakeghutil/fakeghutil.go index 010eccc61327..6ae939dc4063 100644 --- a/vendor/knative.dev/pkg/test/ghutil/fakeghutil/fakeghutil.go +++ b/vendor/knative.dev/pkg/test/ghutil/fakeghutil/fakeghutil.go @@ -214,8 +214,8 @@ func (fgc *FakeGithubClient) ListPullRequests(org, repo, head, base string) ([]* } for _, PR := range PRs { // Filter with consistent logic of CreatePullRequest function below - if ("" == head || *PR.Head.Label == head) && - ("" == base || *PR.Base.Ref == base) { + if (head == "" || head == *PR.Head.Label) && + (base == "" || base == *PR.Base.Ref) { res = append(res, PR) } } @@ -304,7 +304,7 @@ func (fgc *FakeGithubClient) CreatePullRequest(org, repo, head, base, title, bod State: &stateStr, Number: &PRNumber, } - if "" != head { + if head != "" { tokens := strings.Split(head, ":") if len(tokens) != 2 { return nil, fmt.Errorf("invalid head, want: 'user:ref', got: '%s'", head) @@ -314,7 +314,7 @@ func (fgc *FakeGithubClient) CreatePullRequest(org, repo, head, base, title, bod Ref: &tokens[1], } } - if "" != base { + if base != "" { l := fmt.Sprintf("%s:%s", repo, base) PR.Base = &github.PullRequestBranch{ Label: &l, @@ -349,7 +349,7 @@ func (fgc *FakeGithubClient) AddFileToCommit(org, repo, SHA, filename, patch str Patch: &patch, } if _, ok := fgc.CommitFiles[SHA]; !ok { - fgc.CommitFiles[SHA] = make([]*github.CommitFile, 0, 0) + fgc.CommitFiles[SHA] = make([]*github.CommitFile, 0) } fgc.CommitFiles[SHA] = append(fgc.CommitFiles[SHA], f) return nil @@ -366,7 +366,7 @@ func (fgc *FakeGithubClient) AddCommitToPullRequest(org, repo string, ID int, SH return fmt.Errorf("Pull Request %d not exist", ID) } if _, ok = fgc.PRCommits[ID]; !ok { - fgc.PRCommits[ID] = make([]*github.RepositoryCommit, 0, 0) + fgc.PRCommits[ID] = make([]*github.RepositoryCommit, 0) } fgc.PRCommits[ID] = append(fgc.PRCommits[ID], &github.RepositoryCommit{SHA: &SHA}) return nil diff --git a/vendor/knative.dev/pkg/test/gke/client.go b/vendor/knative.dev/pkg/test/gke/client.go index 9d76bd78718b..cd69cf625fae 100644 --- a/vendor/knative.dev/pkg/test/gke/client.go +++ b/vendor/knative.dev/pkg/test/gke/client.go @@ -22,7 +22,6 @@ import ( container "google.golang.org/api/container/v1beta1" "golang.org/x/net/context" - "golang.org/x/oauth2/google" ) // SDKOperations wraps GKE SDK related functions @@ -43,13 +42,7 @@ type sdkClient struct { // NewSDKClient returns an SDKClient that implements SDKOperations func NewSDKClient() (SDKOperations, error) { - ctx := context.Background() - c, err := google.DefaultClient(ctx, container.CloudPlatformScope) - if err != nil { - return nil, fmt.Errorf("failed to create Google client: '%v'", err) - } - - containerService, err := container.New(c) + containerService, err := container.NewService(context.Background()) if err != nil { return nil, fmt.Errorf("failed to create container service: '%v'", err) } diff --git a/vendor/knative.dev/pkg/test/gke/wait.go b/vendor/knative.dev/pkg/test/gke/wait.go index e53d2ef62636..b6226c31a33e 100644 --- a/vendor/knative.dev/pkg/test/gke/wait.go +++ b/vendor/knative.dev/pkg/test/gke/wait.go @@ -43,13 +43,14 @@ func Wait(gsc SDKOperations, project, region, zone, opName string, wait time.Dur var err error timeout := time.After(wait) - tick := time.Tick(500 * time.Millisecond) + ticker := time.NewTicker(500 * time.Millisecond) + defer ticker.Stop() for { select { // Got a timeout! fail with a timeout error case <-timeout: return errors.New("timed out waiting") - case <-tick: + case <-ticker.C: // Retry 3 times in case of weird network error, or rate limiting for r, w := 0, 50*time.Microsecond; r < 3; r, w = r+1, w*2 { op, err = gsc.GetOperation(project, region, zone, opName) diff --git a/vendor/knative.dev/pkg/test/helpers/dryrun.go b/vendor/knative.dev/pkg/test/helpers/dryrun.go index 056436dedfb3..68f799444413 100644 --- a/vendor/knative.dev/pkg/test/helpers/dryrun.go +++ b/vendor/knative.dev/pkg/test/helpers/dryrun.go @@ -26,7 +26,7 @@ func Run(message string, call func() error, dryrun bool) error { log.Printf("[dry run] %s", message) return nil } - log.Printf(message) + log.Print(message) return call() } diff --git a/vendor/knative.dev/pkg/test/mako/alerter/github/issue.go b/vendor/knative.dev/pkg/test/mako/alerter/github/issue.go index 764410b567f7..edc957884d80 100644 --- a/vendor/knative.dev/pkg/test/mako/alerter/github/issue.go +++ b/vendor/knative.dev/pkg/test/mako/alerter/github/issue.go @@ -177,7 +177,7 @@ func (gih *IssueHandler) CloseIssueForTest(testName string) error { return nil } // If the issue is still active, do not close it. - if time.Now().Sub(issue.GetUpdatedAt()) < daysConsideredActive*24*time.Hour { + if time.Since(issue.GetUpdatedAt()) < daysConsideredActive*24*time.Hour { return nil } @@ -233,7 +233,7 @@ func (gih *IssueHandler) findIssue(title string) (*github.Issue, error) { if *issue.Title == title { // If the issue has been closed a long time ago, ignore this issue. if issue.GetState() == string(ghutil.IssueCloseState) && - time.Now().Sub(*issue.UpdatedAt) > daysConsideredOld*24*time.Hour { + time.Since(*issue.UpdatedAt) > daysConsideredOld*24*time.Hour { continue } diff --git a/vendor/knative.dev/pkg/test/webhook-apicoverage/resourcetree/test_util.go b/vendor/knative.dev/pkg/test/webhook-apicoverage/resourcetree/test_util.go index b44b05f0115d..34fca0545a5c 100644 --- a/vendor/knative.dev/pkg/test/webhook-apicoverage/resourcetree/test_util.go +++ b/vendor/knative.dev/pkg/test/webhook-apicoverage/resourcetree/test_util.go @@ -17,6 +17,7 @@ limitations under the License. package resourcetree //test_util contains types defined and used by types and their corresponding verification methods. +//lint:file-ignore U1000 Ignore all unused code, it's needed import ( "container/list" diff --git a/vendor/knative.dev/pkg/testing/resource.go b/vendor/knative.dev/pkg/testing/resource.go index aa1d68139037..e44b29867a20 100644 --- a/vendor/knative.dev/pkg/testing/resource.go +++ b/vendor/knative.dev/pkg/testing/resource.go @@ -38,7 +38,6 @@ type Resource struct { // 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. @@ -105,12 +104,7 @@ func (cs *ResourceSpec) Validate(ctx context.Context) *apis.FieldError { 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"} - } - +func (current *Resource) CheckImmutableFields(ctx context.Context, original *Resource) *apis.FieldError { if original.Spec.FieldThatsImmutable != current.Spec.FieldThatsImmutable { return &apis.FieldError{ Message: "Immutable field changed", diff --git a/vendor/knative.dev/pkg/testutils/clustermanager/e2e-tests/gke.go b/vendor/knative.dev/pkg/testutils/clustermanager/e2e-tests/gke.go index d24ea1dfd437..6adc7cc930bc 100644 --- a/vendor/knative.dev/pkg/testutils/clustermanager/e2e-tests/gke.go +++ b/vendor/knative.dev/pkg/testutils/clustermanager/e2e-tests/gke.go @@ -234,7 +234,7 @@ func (gc *GKECluster) Acquire() error { if i != len(regions)-1 { errMsg = fmt.Sprintf("%sRetry another region %q for cluster creation", errMsg, regions[i+1]) } - log.Printf(errMsg) + log.Print(errMsg) } else { log.Print("Cluster creation completed") gc.Cluster = cluster diff --git a/vendor/knative.dev/pkg/webhook/resourcesemantics/controller.go b/vendor/knative.dev/pkg/webhook/resourcesemantics/defaulting/controller.go similarity index 95% rename from vendor/knative.dev/pkg/webhook/resourcesemantics/controller.go rename to vendor/knative.dev/pkg/webhook/resourcesemantics/defaulting/controller.go index 38d1dd505780..9f7135f6edbd 100644 --- a/vendor/knative.dev/pkg/webhook/resourcesemantics/controller.go +++ b/vendor/knative.dev/pkg/webhook/resourcesemantics/defaulting/controller.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package resourcesemantics +package defaulting import ( "context" @@ -30,13 +30,14 @@ import ( "knative.dev/pkg/logging" "knative.dev/pkg/system" "knative.dev/pkg/webhook" + "knative.dev/pkg/webhook/resourcesemantics" ) // NewAdmissionController constructs a reconciler func NewAdmissionController( ctx context.Context, name, path string, - handlers map[schema.GroupVersionKind]GenericCRD, + handlers map[schema.GroupVersionKind]resourcesemantics.GenericCRD, wc func(context.Context) context.Context, disallowUnknownFields bool, ) *controller.Impl { diff --git a/vendor/knative.dev/pkg/webhook/resourcesemantics/resourcesemantics.go b/vendor/knative.dev/pkg/webhook/resourcesemantics/defaulting/defaulting.go similarity index 85% rename from vendor/knative.dev/pkg/webhook/resourcesemantics/resourcesemantics.go rename to vendor/knative.dev/pkg/webhook/resourcesemantics/defaulting/defaulting.go index 14203a1c7ca3..bfd51ebd2458 100644 --- a/vendor/knative.dev/pkg/webhook/resourcesemantics/resourcesemantics.go +++ b/vendor/knative.dev/pkg/webhook/resourcesemantics/defaulting/defaulting.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package resourcesemantics +package defaulting import ( "bytes" @@ -30,7 +30,6 @@ import ( "go.uber.org/zap" admissionv1beta1 "k8s.io/api/admission/v1beta1" admissionregistrationv1beta1 "k8s.io/api/admissionregistration/v1beta1" - "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/client-go/kubernetes" admissionlisters "k8s.io/client-go/listers/admissionregistration/v1beta1" @@ -44,23 +43,16 @@ import ( "knative.dev/pkg/system" "knative.dev/pkg/webhook" certresources "knative.dev/pkg/webhook/certificates/resources" + "knative.dev/pkg/webhook/resourcesemantics" ) -// 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 -} - var errMissingNewObject = errors.New("the new object may not be nil") // reconciler implements the AdmissionController for resources type reconciler struct { name string path string - handlers map[schema.GroupVersionKind]GenericCRD + handlers map[schema.GroupVersionKind]resourcesemantics.GenericCRD withContext func(context.Context) context.Context @@ -217,10 +209,10 @@ func (ac *reconciler) mutate(ctx context.Context, req *admissionv1beta1.Admissio } // nil values denote absence of `old` (create) or `new` (delete) objects. - var oldObj, newObj GenericCRD + var oldObj, newObj resourcesemantics.GenericCRD if len(newBytes) != 0 { - newObj = handler.DeepCopyObject().(GenericCRD) + newObj = handler.DeepCopyObject().(resourcesemantics.GenericCRD) newDecoder := json.NewDecoder(bytes.NewBuffer(newBytes)) if ac.disallowUnknownFields { newDecoder.DisallowUnknownFields() @@ -230,7 +222,7 @@ func (ac *reconciler) mutate(ctx context.Context, req *admissionv1beta1.Admissio } } if len(oldBytes) != 0 { - oldObj = handler.DeepCopyObject().(GenericCRD) + oldObj = handler.DeepCopyObject().(resourcesemantics.GenericCRD) oldDecoder := json.NewDecoder(bytes.NewBuffer(oldBytes)) if ac.disallowUnknownFields { oldDecoder.DisallowUnknownFields() @@ -258,7 +250,7 @@ func (ac *reconciler) mutate(ctx context.Context, req *admissionv1beta1.Admissio 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 = oldObj.DeepCopyObject().(resourcesemantics.GenericCRD) oldObj.SetDefaults(ctx) s, ok := oldObj.(apis.HasSpec) @@ -293,17 +285,10 @@ func (ac *reconciler) mutate(ctx context.Context, req *admissionv1beta1.Admissio 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) } -func (ac *reconciler) setUserInfoAnnotations(ctx context.Context, patches duck.JSONPatch, new GenericCRD, groupName string) (duck.JSONPatch, error) { +func (ac *reconciler) setUserInfoAnnotations(ctx context.Context, patches duck.JSONPatch, new resourcesemantics.GenericCRD, groupName string) (duck.JSONPatch, error) { if new == nil { return patches, nil } @@ -341,33 +326,8 @@ func roundTripPatch(bytes []byte, unmarshalled interface{}) (duck.JSONPatch, err return jsonpatch.CreatePatch(bytes, marshaledBytes) } -// 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 apis.Validatable) 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) { +func setDefaults(ctx context.Context, patches duck.JSONPatch, crd resourcesemantics.GenericCRD) (duck.JSONPatch, error) { before, after := crd.DeepCopyObject(), crd after.SetDefaults(ctx) diff --git a/vendor/knative.dev/pkg/webhook/resourcesemantics/user_info.go b/vendor/knative.dev/pkg/webhook/resourcesemantics/defaulting/user_info.go similarity index 98% rename from vendor/knative.dev/pkg/webhook/resourcesemantics/user_info.go rename to vendor/knative.dev/pkg/webhook/resourcesemantics/defaulting/user_info.go index ae92feb6478a..a1243b8e8ab8 100644 --- a/vendor/knative.dev/pkg/webhook/resourcesemantics/user_info.go +++ b/vendor/knative.dev/pkg/webhook/resourcesemantics/defaulting/user_info.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package resourcesemantics +package defaulting import ( "context" diff --git a/vendor/knative.dev/pkg/apis/v1alpha1/doc.go b/vendor/knative.dev/pkg/webhook/resourcesemantics/interface.go similarity index 62% rename from vendor/knative.dev/pkg/apis/v1alpha1/doc.go rename to vendor/knative.dev/pkg/webhook/resourcesemantics/interface.go index 9fb4a2a85e7b..7f216b101556 100644 --- a/vendor/knative.dev/pkg/apis/v1alpha1/doc.go +++ b/vendor/knative.dev/pkg/webhook/resourcesemantics/interface.go @@ -14,5 +14,17 @@ See the License for the specific language governing permissions and limitations under the License. */ -// +k8s:deepcopy-gen=package -package v1alpha1 +package resourcesemantics + +import ( + "k8s.io/apimachinery/pkg/runtime" + "knative.dev/pkg/apis" +) + +// 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 +} diff --git a/vendor/knative.dev/pkg/webhook/resourcesemantics/validation/controller.go b/vendor/knative.dev/pkg/webhook/resourcesemantics/validation/controller.go new file mode 100644 index 000000000000..583784a4c586 --- /dev/null +++ b/vendor/knative.dev/pkg/webhook/resourcesemantics/validation/controller.go @@ -0,0 +1,84 @@ +/* +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 validation + +import ( + "context" + + // Injection stuff + kubeclient "knative.dev/pkg/client/injection/kube/client" + vwhinformer "knative.dev/pkg/client/injection/kube/informers/admissionregistration/v1beta1/validatingwebhookconfiguration" + secretinformer "knative.dev/pkg/client/injection/kube/informers/core/v1/secret" + + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/client-go/tools/cache" + "knative.dev/pkg/controller" + "knative.dev/pkg/logging" + "knative.dev/pkg/system" + "knative.dev/pkg/webhook" + "knative.dev/pkg/webhook/resourcesemantics" +) + +// NewAdmissionController constructs a reconciler +func NewAdmissionController( + ctx context.Context, + name, path string, + handlers map[schema.GroupVersionKind]resourcesemantics.GenericCRD, + wc func(context.Context) context.Context, + disallowUnknownFields bool, +) *controller.Impl { + + client := kubeclient.Get(ctx) + vwhInformer := vwhinformer.Get(ctx) + secretInformer := secretinformer.Get(ctx) + options := webhook.GetOptions(ctx) + + wh := &reconciler{ + name: name, + path: path, + handlers: handlers, + + withContext: wc, + disallowUnknownFields: disallowUnknownFields, + secretName: options.SecretName, + + client: client, + vwhlister: vwhInformer.Lister(), + secretlister: secretInformer.Lister(), + } + + logger := logging.FromContext(ctx) + c := controller.NewImpl(wh, logger, "ConfigMapWebhook") + + // Reconcile when the named ValidatingWebhookConfiguration changes. + vwhInformer.Informer().AddEventHandler(cache.FilteringResourceEventHandler{ + FilterFunc: controller.FilterWithName(name), + // It doesn't matter what we enqueue because we will always Reconcile + // the named VWH resource. + Handler: controller.HandleAll(c.Enqueue), + }) + + // Reconcile when the cert bundle changes. + secretInformer.Informer().AddEventHandler(cache.FilteringResourceEventHandler{ + FilterFunc: controller.FilterWithNameAndNamespace(system.Namespace(), wh.secretName), + // It doesn't matter what we enqueue because we will always Reconcile + // the named VWH resource. + Handler: controller.HandleAll(c.Enqueue), + }) + + return c +} diff --git a/vendor/knative.dev/pkg/webhook/resourcesemantics/validation/validation.go b/vendor/knative.dev/pkg/webhook/resourcesemantics/validation/validation.go new file mode 100644 index 000000000000..cefb34e35e50 --- /dev/null +++ b/vendor/knative.dev/pkg/webhook/resourcesemantics/validation/validation.go @@ -0,0 +1,259 @@ +/* +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 validation + +import ( + "bytes" + "context" + "encoding/json" + "errors" + "fmt" + "sort" + "strings" + + "github.com/markbates/inflect" + "go.uber.org/zap" + admissionv1beta1 "k8s.io/api/admission/v1beta1" + admissionregistrationv1beta1 "k8s.io/api/admissionregistration/v1beta1" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/client-go/kubernetes" + admissionlisters "k8s.io/client-go/listers/admissionregistration/v1beta1" + corelisters "k8s.io/client-go/listers/core/v1" + "knative.dev/pkg/apis" + "knative.dev/pkg/controller" + "knative.dev/pkg/kmp" + "knative.dev/pkg/logging" + "knative.dev/pkg/ptr" + "knative.dev/pkg/system" + "knative.dev/pkg/webhook" + certresources "knative.dev/pkg/webhook/certificates/resources" + "knative.dev/pkg/webhook/resourcesemantics" +) + +var errMissingNewObject = errors.New("the new object may not be nil") + +// reconciler implements the AdmissionController for resources +type reconciler struct { + name string + path string + handlers map[schema.GroupVersionKind]resourcesemantics.GenericCRD + + withContext func(context.Context) context.Context + + client kubernetes.Interface + vwhlister admissionlisters.ValidatingWebhookConfigurationLister + secretlister corelisters.SecretLister + + disallowUnknownFields bool + secretName string +} + +var _ controller.Reconciler = (*reconciler)(nil) +var _ webhook.AdmissionController = (*reconciler)(nil) + +// Reconcile implements controller.Reconciler +func (ac *reconciler) Reconcile(ctx context.Context, key string) error { + logger := logging.FromContext(ctx) + + // Look up the webhook secret, and fetch the CA cert bundle. + secret, err := ac.secretlister.Secrets(system.Namespace()).Get(ac.secretName) + if err != nil { + logger.Errorw("Error fetching secret", zap.Error(err)) + return err + } + caCert, ok := secret.Data[certresources.CACert] + if !ok { + return fmt.Errorf("secret %q is missing %q key", ac.secretName, certresources.CACert) + } + + // Reconcile the webhook configuration. + return ac.reconcileValidatingWebhook(ctx, caCert) +} + +// Path implements AdmissionController +func (ac *reconciler) Path() string { + return ac.path +} + +// Admit implements AdmissionController +func (ac *reconciler) Admit(ctx context.Context, request *admissionv1beta1.AdmissionRequest) *admissionv1beta1.AdmissionResponse { + if ac.withContext != nil { + ctx = ac.withContext(ctx) + } + + 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} + } + + err := ac.validate(ctx, request) + if err != nil { + return webhook.MakeErrorStatus("validation failed: %v", err) + } + + return &admissionv1beta1.AdmissionResponse{Allowed: true} +} + +func (ac *reconciler) reconcileValidatingWebhook(ctx context.Context, caCert []byte) error { + logger := logging.FromContext(ctx) + + 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] + }) + + configuredWebhook, err := ac.vwhlister.Get(ac.name) + if err != nil { + return fmt.Errorf("error retrieving webhook: %v", err) + } + + webhook := configuredWebhook.DeepCopy() + + // Clear out any previous (bad) OwnerReferences. + // See: https://github.com/knative/serving/issues/5845 + webhook.OwnerReferences = nil + + for i, wh := range webhook.Webhooks { + if wh.Name != webhook.Name { + continue + } + webhook.Webhooks[i].Rules = rules + webhook.Webhooks[i].ClientConfig.CABundle = caCert + if webhook.Webhooks[i].ClientConfig.Service == nil { + return fmt.Errorf("missing service reference for webhook: %s", wh.Name) + } + webhook.Webhooks[i].ClientConfig.Service.Path = ptr.String(ac.Path()) + } + + if ok, err := kmp.SafeEqual(configuredWebhook, webhook); err != nil { + return fmt.Errorf("error diffing webhooks: %v", err) + } else if !ok { + logger.Info("Updating webhook") + vwhclient := ac.client.AdmissionregistrationV1beta1().ValidatingWebhookConfigurations() + if _, err := vwhclient.Update(webhook); err != nil { + return fmt.Errorf("failed to update webhook: %v", err) + } + } else { + logger.Info("Webhook is valid") + } + return nil +} + +func (ac *reconciler) validate(ctx context.Context, req *admissionv1beta1.AdmissionRequest) 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 fmt.Errorf("unhandled kind: %v", gvk) + } + + // nil values denote absence of `old` (create) or `new` (delete) objects. + var oldObj, newObj resourcesemantics.GenericCRD + + if len(newBytes) != 0 { + newObj = handler.DeepCopyObject().(resourcesemantics.GenericCRD) + newDecoder := json.NewDecoder(bytes.NewBuffer(newBytes)) + if ac.disallowUnknownFields { + newDecoder.DisallowUnknownFields() + } + if err := newDecoder.Decode(&newObj); err != nil { + return fmt.Errorf("cannot decode incoming new object: %v", err) + } + } + if len(oldBytes) != 0 { + oldObj = handler.DeepCopyObject().(resourcesemantics.GenericCRD) + oldDecoder := json.NewDecoder(bytes.NewBuffer(oldBytes)) + if ac.disallowUnknownFields { + oldDecoder.DisallowUnknownFields() + } + if err := oldDecoder.Decode(&oldObj); err != nil { + return fmt.Errorf("cannot decode incoming old object: %v", err) + } + } + + // Set up the context for defaulting and validation + if oldObj != nil { + 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) + + // None of the validators will accept a nil value for newObj. + if newObj == nil { + return 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 err + } + + return nil +} + +// validate performs validation on the provided "new" CRD. +func validate(ctx context.Context, new apis.Validatable) error { + // Can't just `return new.Validate()` because it doesn't properly nil-check. + if err := new.Validate(ctx); err != nil { + return err + } + + return nil +} diff --git a/vendor/knative.dev/pkg/webhook/testing/testing.go b/vendor/knative.dev/pkg/webhook/testing/testing.go index 7e3b31754c3d..0be7c6ce104b 100644 --- a/vendor/knative.dev/pkg/webhook/testing/testing.go +++ b/vendor/knative.dev/pkg/webhook/testing/testing.go @@ -28,21 +28,20 @@ import ( admissionv1beta1 "k8s.io/api/admission/v1beta1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "knative.dev/pkg/system" + pkgtest "knative.dev/pkg/testing" // Makes system.Namespace work in tests. _ "knative.dev/pkg/system/testing" - - . "knative.dev/pkg/testing" ) // CreateResource creates a testing.Resource with the given name in the system namespace. -func CreateResource(name string) *Resource { - return &Resource{ +func CreateResource(name string) *pkgtest.Resource { + return &pkgtest.Resource{ ObjectMeta: metav1.ObjectMeta{ Namespace: system.Namespace(), Name: name, }, - Spec: ResourceSpec{ + Spec: pkgtest.ResourceSpec{ FieldWithValidation: "magic value", }, } diff --git a/vendor/knative.dev/pkg/webhook/webhook.go b/vendor/knative.dev/pkg/webhook/webhook.go index 24b7752a6092..b4efd79641c5 100644 --- a/vendor/knative.dev/pkg/webhook/webhook.go +++ b/vendor/knative.dev/pkg/webhook/webhook.go @@ -41,10 +41,6 @@ import ( certresources "knative.dev/pkg/webhook/certificates/resources" ) -var ( - errMissingNewObject = errors.New("the new object may not be nil") -) - // Options contains the configuration for the webhook type Options struct { // ServiceName is the service name of the webhook. From 2b2146288b0629919ca1d20d44f2e672db8be0b0 Mon Sep 17 00:00:00 2001 From: "Matt Moore (via sockpuppet)" Date: Sat, 9 Nov 2019 16:13:42 +0000 Subject: [PATCH 2/2] golang format tools Produced via: `gofmt -s -w $(find -path './vendor' -prune -o -type f -name '*.go' -print))` `goimports -w $(find -name '*.go' | grep -v vendor)` /assign mattmoor --- pkg/reconciler/revision/table_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/reconciler/revision/table_test.go b/pkg/reconciler/revision/table_test.go index c8c757d45e6a..ae879e3f44a6 100644 --- a/pkg/reconciler/revision/table_test.go +++ b/pkg/reconciler/revision/table_test.go @@ -550,7 +550,7 @@ func TestReconcile(t *testing.T) { }, Key: "foo/missing-owners", }, { - Name: "image pull secrets", + Name: "image pull secrets", // This test case tests that the image pull secrets from revision propagate to deployment and image Objects: []runtime.Object{ rev("foo", "image-pull-secrets", WithImagePullSecrets("foo-secret")),