diff --git a/Gopkg.lock b/Gopkg.lock index be4cc8dfcb05..953ba0d30dc6 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -1671,8 +1671,7 @@ revision = "88e1e4db86d11beb16248a94b1072beac20aef4c" [[projects]] - branch = "master" - digest = "1:c8e0ec560560e16616821b3999e905e6b9085c832b5b57216905711e63679d19" + digest = "1:c16662b4601d7f106742ee660846d05e740aed640e938e12ff08a8b8c88fc4ec" name = "knative.dev/pkg" packages = [ "apis", @@ -1711,7 +1710,6 @@ "client/injection/informers/istio/v1alpha3/virtualservice/fake", "client/injection/kube/client", "client/injection/kube/client/fake", - "client/injection/kube/informers/admissionregistration/v1beta1/mutatingwebhookconfiguration", "client/injection/kube/informers/admissionregistration/v1beta1/validatingwebhookconfiguration", "client/injection/kube/informers/apps/v1/deployment", "client/injection/kube/informers/apps/v1/deployment/fake", @@ -1797,7 +1795,8 @@ "websocket", ] pruneopts = "T" - revision = "d4ce00139499bd3ea11cdb18ef20a41bdb248245" + revision = "3f9bcd4d73fb89a1976eed9d7a5c6dd023435e3f" + source = "github.com/mattmoor/pkg-1" [[projects]] branch = "master" diff --git a/Gopkg.toml b/Gopkg.toml index de187232ffc0..66ceff882320 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 = "3f9bcd4d73fb89a1976eed9d7a5c6dd023435e3f" + # branch = "master" [[constraint]] name = "knative.dev/caching" diff --git a/cmd/webhook/main.go b/cmd/webhook/main.go index 60bdc81f37ff..066942625298 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,70 @@ 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", + "defaulting.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. + "/validation", + + // 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 +159,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..86840cc77014 100644 --- a/config/500-webhook-configuration.yaml +++ b/config/500-webhook-configuration.yaml @@ -15,7 +15,7 @@ apiVersion: admissionregistration.k8s.io/v1beta1 kind: MutatingWebhookConfiguration metadata: - name: webhook.serving.knative.dev + name: defaulting.webhook.serving.knative.dev labels: serving.knative.dev/release: devel webhooks: @@ -26,7 +26,23 @@ webhooks: name: webhook namespace: knative-serving failurePolicy: Fail - name: webhook.serving.knative.dev + name: defaulting.webhook.serving.knative.dev +--- +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 diff --git a/third_party/VENDOR-LICENSE b/third_party/VENDOR-LICENSE index 89273f9b8bf3..bb04d1846429 100644 --- a/third_party/VENDOR-LICENSE +++ b/third_party/VENDOR-LICENSE @@ -3938,20 +3938,6 @@ Import: knative.dev/serving/vendor/github.com/go-openapi/swag -=========================================================== -Import: knative.dev/serving/vendor/github.com/gobuffalo/envy - -The MIT License (MIT) -Copyright (c) 2018 Mark Bates - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - - =========================================================== Import: knative.dev/serving/vendor/github.com/gogo/protobuf @@ -6008,35 +5994,6 @@ limitations under the License. -=========================================================== -Import: knative.dev/serving/vendor/github.com/joho/godotenv - -Copyright (c) 2013 John Barton - -MIT License - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - - - =========================================================== Import: knative.dev/serving/vendor/github.com/json-iterator/go @@ -6309,19 +6266,6 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI -=========================================================== -Import: knative.dev/serving/vendor/github.com/markbates/inflect - -Copyright (c) 2011 Chris Farmiloe - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - - =========================================================== Import: knative.dev/serving/vendor/github.com/mattbaird/jsonpatch 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..437fc707239c 100644 --- a/vendor/knative.dev/pkg/OWNERS_ALIASES +++ b/vendor/knative.dev/pkg/OWNERS_ALIASES @@ -19,11 +19,6 @@ aliases: - vaikas-google - vaikas - cloudevents-approvers: - - n3wscott - - vaikas-google - - vaikas - configmap-approvers: - mattmoor - mdemirhan 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/interfaces.go b/vendor/knative.dev/pkg/apis/interfaces.go index 6b6c772d746f..240102dac721 100644 --- a/vendor/knative.dev/pkg/apis/interfaces.go +++ b/vendor/knative.dev/pkg/apis/interfaces.go @@ -47,11 +47,7 @@ type Convertible interface { // 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 -} +type Immutable interface{} // Listable indicates that a particular type can be returned via the returned // list type by the API server. 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/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/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/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/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..fe8e4e942dab 100644 --- a/vendor/knative.dev/pkg/metrics/stackdriver_exporter.go +++ b/vendor/knative.dev/pkg/metrics/stackdriver_exporter.go @@ -40,8 +40,10 @@ 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" ) @@ -53,8 +55,30 @@ var ( 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() { kubeclientInitErr = nil } @@ -93,15 +117,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 @@ -164,28 +192,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/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/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/cloudevents/doc.go b/vendor/knative.dev/pkg/webhook/resourcesemantics/interface.go similarity index 58% rename from vendor/knative.dev/pkg/cloudevents/doc.go rename to vendor/knative.dev/pkg/webhook/resourcesemantics/interface.go index 62bc3b02ce11..7f216b101556 100644 --- a/vendor/knative.dev/pkg/cloudevents/doc.go +++ b/vendor/knative.dev/pkg/webhook/resourcesemantics/interface.go @@ -1,5 +1,5 @@ /* -Copyright 2018 The Knative Authors +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. @@ -14,9 +14,17 @@ 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 +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..e920114f2032 --- /dev/null +++ b/vendor/knative.dev/pkg/webhook/resourcesemantics/validation/validation.go @@ -0,0 +1,261 @@ +/* +Copyright 2019 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package 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.Errorf("Error fetching secret: %v", 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("mutation 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. +// 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 { + // 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.