diff --git a/cmd/broker/fanout/main.go b/cmd/broker/fanout/main.go index 5432f260d4..d0c160fdca 100644 --- a/cmd/broker/fanout/main.go +++ b/cmd/broker/fanout/main.go @@ -28,6 +28,7 @@ import ( "github.com/google/knative-gcp/pkg/metrics" "github.com/google/knative-gcp/pkg/utils" "github.com/google/knative-gcp/pkg/utils/appcredentials" + "github.com/google/knative-gcp/pkg/utils/clients" "github.com/google/knative-gcp/pkg/utils/mainhelper" "go.uber.org/zap" @@ -81,7 +82,7 @@ func main() { syncSignal := poolSyncSignal(ctx, targetsUpdateCh) syncPool, err := InitializeSyncPool( ctx, - handler.ProjectID(projectID), + clients.ProjectID(projectID), metrics.PodName(env.PodName), metrics.ContainerName(component), []volume.Option{ diff --git a/cmd/broker/fanout/wire.go b/cmd/broker/fanout/wire.go index 08f8fb819e..9fd978b39a 100644 --- a/cmd/broker/fanout/wire.go +++ b/cmd/broker/fanout/wire.go @@ -24,6 +24,7 @@ import ( "github.com/google/knative-gcp/pkg/broker/config/volume" "github.com/google/knative-gcp/pkg/broker/handler" "github.com/google/knative-gcp/pkg/metrics" + "github.com/google/knative-gcp/pkg/utils/clients" "github.com/google/wire" ) @@ -31,7 +32,7 @@ import ( // retry pool's pubsub client and uses targetsVolumeOpts to initialize the targets volume watcher. func InitializeSyncPool( ctx context.Context, - projectID handler.ProjectID, + projectID clients.ProjectID, podName metrics.PodName, containerName metrics.ContainerName, targetsVolumeOpts []volume.Option, diff --git a/cmd/broker/fanout/wire_gen.go b/cmd/broker/fanout/wire_gen.go index 19272d22a3..1b991a5fb7 100644 --- a/cmd/broker/fanout/wire_gen.go +++ b/cmd/broker/fanout/wire_gen.go @@ -10,16 +10,17 @@ import ( "github.com/google/knative-gcp/pkg/broker/config/volume" "github.com/google/knative-gcp/pkg/broker/handler" "github.com/google/knative-gcp/pkg/metrics" + "github.com/google/knative-gcp/pkg/utils/clients" ) // Injectors from wire.go: -func InitializeSyncPool(ctx context.Context, projectID handler.ProjectID, podName metrics.PodName, containerName metrics.ContainerName, targetsVolumeOpts []volume.Option, opts ...handler.Option) (*handler.FanoutPool, error) { +func InitializeSyncPool(ctx context.Context, projectID clients.ProjectID, podName metrics.PodName, containerName metrics.ContainerName, targetsVolumeOpts []volume.Option, opts ...handler.Option) (*handler.FanoutPool, error) { readonlyTargets, err := volume.NewTargetsFromFile(targetsVolumeOpts...) if err != nil { return nil, err } - client, err := handler.NewPubsubClient(ctx, projectID) + client, err := clients.NewPubsubClient(ctx, projectID) if err != nil { return nil, err } diff --git a/cmd/broker/ingress/main.go b/cmd/broker/ingress/main.go index 49a28baca5..5010140325 100644 --- a/cmd/broker/ingress/main.go +++ b/cmd/broker/ingress/main.go @@ -17,11 +17,11 @@ limitations under the License. package main import ( - "github.com/google/knative-gcp/pkg/broker/ingress" metadataClient "github.com/google/knative-gcp/pkg/gclient/metadata" "github.com/google/knative-gcp/pkg/metrics" "github.com/google/knative-gcp/pkg/utils" "github.com/google/knative-gcp/pkg/utils/appcredentials" + "github.com/google/knative-gcp/pkg/utils/clients" "github.com/google/knative-gcp/pkg/utils/mainhelper" "go.uber.org/zap" @@ -59,8 +59,8 @@ func main() { ingress, err := InitializeHandler( ctx, - ingress.Port(env.Port), - ingress.ProjectID(projectID), + clients.Port(env.Port), + clients.ProjectID(projectID), metrics.PodName(env.PodName), metrics.ContainerName(component), ) diff --git a/cmd/broker/ingress/wire.go b/cmd/broker/ingress/wire.go index fa8e4343ab..590cb991a8 100644 --- a/cmd/broker/ingress/wire.go +++ b/cmd/broker/ingress/wire.go @@ -24,13 +24,14 @@ import ( "github.com/google/knative-gcp/pkg/broker/config/volume" "github.com/google/knative-gcp/pkg/broker/ingress" "github.com/google/knative-gcp/pkg/metrics" + "github.com/google/knative-gcp/pkg/utils/clients" "github.com/google/wire" ) func InitializeHandler( ctx context.Context, - port ingress.Port, - projectID ingress.ProjectID, + port clients.Port, + projectID clients.ProjectID, podName metrics.PodName, containerName metrics.ContainerName, ) (*ingress.Handler, error) { diff --git a/cmd/broker/ingress/wire_gen.go b/cmd/broker/ingress/wire_gen.go index 7019e24743..f711fe6110 100644 --- a/cmd/broker/ingress/wire_gen.go +++ b/cmd/broker/ingress/wire_gen.go @@ -10,18 +10,19 @@ import ( "github.com/google/knative-gcp/pkg/broker/config/volume" "github.com/google/knative-gcp/pkg/broker/ingress" "github.com/google/knative-gcp/pkg/metrics" + "github.com/google/knative-gcp/pkg/utils/clients" ) // Injectors from wire.go: -func InitializeHandler(ctx context.Context, port ingress.Port, projectID ingress.ProjectID, podName metrics.PodName, containerName metrics.ContainerName) (*ingress.Handler, error) { - httpMessageReceiver := ingress.NewHTTPMessageReceiver(port) +func InitializeHandler(ctx context.Context, port clients.Port, projectID clients.ProjectID, podName metrics.PodName, containerName metrics.ContainerName) (*ingress.Handler, error) { + httpMessageReceiver := clients.NewHTTPMessageReceiver(port) v := _wireValue readonlyTargets, err := volume.NewTargetsFromFile(v...) if err != nil { return nil, err } - client, err := ingress.NewPubsubClient(ctx, projectID) + client, err := clients.NewPubsubClient(ctx, projectID) if err != nil { return nil, err } diff --git a/cmd/broker/retry/main.go b/cmd/broker/retry/main.go index 21e6820a8e..a5da28998b 100644 --- a/cmd/broker/retry/main.go +++ b/cmd/broker/retry/main.go @@ -30,6 +30,7 @@ import ( "github.com/google/knative-gcp/pkg/metrics" "github.com/google/knative-gcp/pkg/utils" "github.com/google/knative-gcp/pkg/utils/appcredentials" + "github.com/google/knative-gcp/pkg/utils/clients" "github.com/google/knative-gcp/pkg/utils/mainhelper" ) @@ -89,7 +90,7 @@ func main() { syncSignal := poolSyncSignal(ctx, targetsUpdateCh) syncPool, err := InitializeSyncPool( ctx, - handler.ProjectID(projectID), + clients.ProjectID(projectID), metrics.PodName(env.PodName), metrics.ContainerName(component), []volume.Option{ diff --git a/cmd/broker/retry/wire.go b/cmd/broker/retry/wire.go index 6cf68e6c41..9574112f41 100644 --- a/cmd/broker/retry/wire.go +++ b/cmd/broker/retry/wire.go @@ -24,6 +24,7 @@ import ( "github.com/google/knative-gcp/pkg/broker/config/volume" "github.com/google/knative-gcp/pkg/broker/handler" "github.com/google/knative-gcp/pkg/metrics" + "github.com/google/knative-gcp/pkg/utils/clients" "github.com/google/wire" ) @@ -31,7 +32,7 @@ import ( // retry pool's pubsub client and uses targetsVolumeOpts to initialize the targets volume watcher. func InitializeSyncPool( ctx context.Context, - projectID handler.ProjectID, + projectID clients.ProjectID, podName metrics.PodName, containerName metrics.ContainerName, targetsVolumeOpts []volume.Option, diff --git a/cmd/broker/retry/wire_gen.go b/cmd/broker/retry/wire_gen.go index 040fb55b16..43145d0bb6 100644 --- a/cmd/broker/retry/wire_gen.go +++ b/cmd/broker/retry/wire_gen.go @@ -10,16 +10,17 @@ import ( "github.com/google/knative-gcp/pkg/broker/config/volume" "github.com/google/knative-gcp/pkg/broker/handler" "github.com/google/knative-gcp/pkg/metrics" + "github.com/google/knative-gcp/pkg/utils/clients" ) // Injectors from wire.go: -func InitializeSyncPool(ctx context.Context, projectID handler.ProjectID, podName metrics.PodName, containerName metrics.ContainerName, targetsVolumeOpts []volume.Option, opts ...handler.Option) (*handler.RetryPool, error) { +func InitializeSyncPool(ctx context.Context, projectID clients.ProjectID, podName metrics.PodName, containerName metrics.ContainerName, targetsVolumeOpts []volume.Option, opts ...handler.Option) (*handler.RetryPool, error) { readonlyTargets, err := volume.NewTargetsFromFile(targetsVolumeOpts...) if err != nil { return nil, err } - client, err := handler.NewPubsubClient(ctx, projectID) + client, err := clients.NewPubsubClient(ctx, projectID) if err != nil { return nil, err } diff --git a/cmd/pubsub/publisher/main.go b/cmd/pubsub/publisher/main.go index 66e58c7e16..63c3d1f8a2 100644 --- a/cmd/pubsub/publisher/main.go +++ b/cmd/pubsub/publisher/main.go @@ -21,17 +21,22 @@ import ( "flag" "log" - "cloud.google.com/go/compute/metadata" + metadataClient "github.com/google/knative-gcp/pkg/gclient/metadata" + . "github.com/google/knative-gcp/pkg/pubsub/publisher" + tracingconfig "github.com/google/knative-gcp/pkg/tracing" + "github.com/google/knative-gcp/pkg/utils" + "github.com/google/knative-gcp/pkg/utils/appcredentials" + "github.com/google/knative-gcp/pkg/utils/clients" "github.com/kelseyhightower/envconfig" "go.uber.org/zap" "go.uber.org/zap/zapcore" "knative.dev/eventing/pkg/tracing" - - "github.com/google/knative-gcp/pkg/pubsub/publisher" - tracingconfig "github.com/google/knative-gcp/pkg/tracing" ) type envConfig struct { + // Environment variable containing the port for the publisher. + Port int `envconfig:"PORT" default:"8080"` + // Environment variable containing project id. Project string `envconfig:"PROJECT_ID"` @@ -47,6 +52,8 @@ type envConfig struct { } func main() { + appcredentials.MustExistOrUnsetEnv() + flag.Parse() ctx := context.Background() @@ -62,15 +69,15 @@ func main() { logger.Fatal("Failed to process env var", zap.Error(err)) } - if env.Project == "" { - project, err := metadata.ProjectID() - if err != nil { - logger.Fatal("failed to find project id. ", zap.Error(err)) - } - env.Project = project + projectID, err := utils.ProjectID(env.Project, metadataClient.NewDefaultMetadataClient()) + if err != nil { + logger.Fatal("Failed to retrieve project id", zap.Error(err)) } - logger.Info("Using project.", zap.String("project", env.Project)) + topicID := env.Topic + if topicID == "" { + logger.Fatal("Failed to retrieve topic id", zap.Error(err)) + } tracingConfig, err := tracingconfig.JSONToConfig(env.TracingConfigJson) if err != nil { @@ -80,13 +87,21 @@ func main() { logger.Error("Failed to setup tracing", zap.Error(err), zap.Any("tracingConfig", tracingConfig)) } - startable := &publisher.Publisher{ - ProjectID: env.Project, - TopicID: env.Topic, + logger.Info("Initializing publisher", zap.String("Project ID", projectID), zap.String("Topic ID", topicID)) + + publisher, err := InitializePublisher( + ctx, + clients.Port(env.Port), + clients.ProjectID(projectID), + TopicID(topicID), + ) + + if err != nil { + logger.Fatal("Unable to create publisher", zap.Error(err)) } - logger.Info("Starting Pub/Sub Publisher.", zap.Any("publisher", startable)) - if err := startable.Start(ctx); err != nil { - logger.Fatal("failed to start publisher: ", zap.Error(err)) + logger.Info("Starting publisher", zap.Any("publisher", publisher)) + if err := publisher.Start(ctx); err != nil { + logger.Error("Publisher has stopped with error", zap.String("Project ID", projectID), zap.String("Topic ID", topicID), zap.Error(err)) } } diff --git a/cmd/pubsub/publisher/wire.go b/cmd/pubsub/publisher/wire.go new file mode 100644 index 0000000000..8c0e95f988 --- /dev/null +++ b/cmd/pubsub/publisher/wire.go @@ -0,0 +1,39 @@ +// +build wireinject + +/* +Copyright 2020 Google LLC. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package main + +import ( + "context" + + "github.com/google/knative-gcp/pkg/pubsub/publisher" + "github.com/google/knative-gcp/pkg/utils/clients" + + "github.com/google/wire" +) + +func InitializePublisher( + ctx context.Context, + port clients.Port, + projectID clients.ProjectID, + topicID publisher.TopicID, +) (*publisher.Publisher, error) { + panic(wire.Build( + publisher.PublisherSet, + )) +} diff --git a/cmd/pubsub/publisher/wire_gen.go b/cmd/pubsub/publisher/wire_gen.go new file mode 100644 index 0000000000..8110e6af06 --- /dev/null +++ b/cmd/pubsub/publisher/wire_gen.go @@ -0,0 +1,25 @@ +// Code generated by Wire. DO NOT EDIT. + +//go:generate wire +//+build !wireinject + +package main + +import ( + "context" + "github.com/google/knative-gcp/pkg/pubsub/publisher" + "github.com/google/knative-gcp/pkg/utils/clients" +) + +// Injectors from wire.go: + +func InitializePublisher(ctx context.Context, port clients.Port, projectID clients.ProjectID, topicID publisher.TopicID) (*publisher.Publisher, error) { + httpMessageReceiver := clients.NewHTTPMessageReceiver(port) + client, err := clients.NewPubsubClient(ctx, projectID) + if err != nil { + return nil, err + } + topic := publisher.NewPubSubTopic(ctx, client, topicID) + publisherPublisher := publisher.NewPublisher(ctx, httpMessageReceiver, topic) + return publisherPublisher, nil +} diff --git a/cmd/pubsub/receive_adapter/main.go b/cmd/pubsub/receive_adapter/main.go index 6d3da83358..213f21b043 100644 --- a/cmd/pubsub/receive_adapter/main.go +++ b/cmd/pubsub/receive_adapter/main.go @@ -19,35 +19,107 @@ package main import ( "flag" "fmt" + "time" - "knative.dev/eventing/pkg/tracing" - - "cloud.google.com/go/compute/metadata" - "github.com/google/knative-gcp/pkg/pubsub/adapter" - tracingconfig "github.com/google/knative-gcp/pkg/tracing" - "github.com/kelseyhightower/envconfig" "go.uber.org/zap" + "knative.dev/eventing/pkg/tracing" "knative.dev/pkg/logging" "knative.dev/pkg/metrics" "knative.dev/pkg/signals" + + metadataClient "github.com/google/knative-gcp/pkg/gclient/metadata" + . "github.com/google/knative-gcp/pkg/pubsub/adapter" + "github.com/google/knative-gcp/pkg/pubsub/adapter/converters" + tracingconfig "github.com/google/knative-gcp/pkg/tracing" + "github.com/google/knative-gcp/pkg/utils" + "github.com/google/knative-gcp/pkg/utils/appcredentials" + "github.com/google/knative-gcp/pkg/utils/clients" + "github.com/kelseyhightower/envconfig" ) const ( - component = "PullSubscription::ReceiveAdapter" + component = "receive_adapter" + + // TODO make this configurable + maxConnectionsPerHost = 1000 ) +// TODO we should refactor this and reduce the number of environment variables. +// most of them are due to metrics, which has to change anyways. +type envConfig struct { + // Environment variable containing project id. + Project string `envconfig:"PROJECT_ID"` + + // Environment variable containing the sink URI. + Sink string `envconfig:"SINK_URI" required:"true"` + + // Environment variable containing the transformer URI. + // This environment variable is only set if we configure both subscriber and reply + // in Channel's subscribers. + // If subscriber and reply are used, we map: + // Transformer to sub.subscriber + // Sink to sub.reply + // Otherwise, only Sink is used (for either the sub.reply or sub.reply) + Transformer string `envconfig:"TRANSFORMER_URI"` + + // Environment variable specifying the type of adapter to use. + // Used for CE conversion. + AdapterType string `envconfig:"ADAPTER_TYPE"` + + // Topic is the environment variable containing the PubSub Topic being + // subscribed to's name. In the form that is unique within the project. + // E.g. 'laconia', not 'projects/my-gcp-project/topics/laconia'. + Topic string `envconfig:"PUBSUB_TOPIC_ID" required:"true"` + + // Subscription is the environment variable containing the name of the + // subscription to use. + Subscription string `envconfig:"PUBSUB_SUBSCRIPTION_ID" required:"true"` + + // ExtensionsBase64 is a based64 encoded json string of a map of + // CloudEvents extensions (key-value pairs) override onto the outbound + // event. + ExtensionsBase64 string `envconfig:"K_CE_EXTENSIONS" required:"true"` + + // MetricsConfigJson is a json string of metrics.ExporterOptions. + // This is used to configure the metrics exporter options, the config is + // stored in a config map inside the controllers namespace and copied here. + MetricsConfigJson string `envconfig:"K_METRICS_CONFIG" required:"true"` + + // LoggingConfigJson is a json string of logging.Config. + // This is used to configure the logging config, the config is stored in + // a config map inside the controllers namespace and copied here. + LoggingConfigJson string `envconfig:"K_LOGGING_CONFIG" required:"true"` + + // TracingConfigJson is a JSON string of tracing.Config. This is used to configure tracing. The + // original config is stored in a ConfigMap inside the controller's namespace. Its value is + // copied here as a JSON string. + TracingConfigJson string `envconfig:"K_TRACING_CONFIG" required:"true"` + + // Environment variable containing the namespace. + Namespace string `envconfig:"NAMESPACE" required:"true"` + + // Environment variable containing the name. + Name string `envconfig:"NAME" required:"true"` + + // Environment variable containing the resource group. E.g., storages.events.cloud.google.com. + ResourceGroup string `envconfig:"RESOURCE_GROUP" default:"pullsubscriptions.internal.pubsub.cloud.google.com" required:"true"` +} + +// TODO try to use the common main from broker. func main() { + appcredentials.MustExistOrUnsetEnv() + flag.Parse() - startable := adapter.Adapter{} - if err := envconfig.Process("", &startable); err != nil { + var env envConfig + if err := envconfig.Process("", &env); err != nil { panic(fmt.Sprintf("Failed to process env var: %s", err)) } // Convert json logging.Config to logging.Config. - loggingConfig, err := logging.JsonToLoggingConfig(startable.LoggingConfigJson) + loggingConfig, err := logging.JsonToLoggingConfig(env.LoggingConfigJson) if err != nil { - fmt.Printf("[ERROR] filed to process logging config: %s", err.Error()) + fmt.Printf("Failed to process logging config: %s", err.Error()) // Use default logging config. if loggingConfig, err = logging.NewConfigFromMap(map[string]string{}); err != nil { // If this fails, there is no recovering. @@ -61,7 +133,7 @@ func main() { ctx := logging.WithLogger(signals.NewContext(), logger.Sugar()) // Convert json metrics.ExporterOptions to metrics.ExporterOptions. - metricsConfig, err := metrics.JsonToMetricsOptions(startable.MetricsConfigJson) + metricsConfig, err := metrics.JsonToMetricsOptions(env.MetricsConfigJson) if err != nil { logger.Error("Failed to process metrics options", zap.Error(err)) } @@ -72,7 +144,7 @@ func main() { } } - tracingConfig, err := tracingconfig.JSONToConfig(startable.TracingConfigJson) + tracingConfig, err := tracingconfig.JSONToConfig(env.TracingConfigJson) if err != nil { logger.Error("Failed to process tracing options", zap.Error(err)) } @@ -80,18 +152,50 @@ func main() { logger.Error("Failed to setup tracing", zap.Error(err), zap.Any("tracingConfig", tracingConfig)) } - if startable.Project == "" { - project, err := metadata.ProjectID() - if err != nil { - logger.Fatal("failed to find project id. ", zap.Error(err)) - } - startable.Project = project + projectID, err := utils.ProjectID(env.Project, metadataClient.NewDefaultMetadataClient()) + if err != nil { + logger.Fatal("Failed to retrieve project id", zap.Error(err)) + } + + // Convert base64 encoded json map to extensions map. + extensions, err := utils.Base64ToMap(env.ExtensionsBase64) + if err != nil { + logger.Error("Failed to convert base64 extensions to map: %v", zap.Error(err)) + } + + logger.Info("Initializing adapter", zap.String("projectID", projectID), zap.String("topicID", env.Topic), zap.String("subscriptionID", env.Subscription)) + + args := &AdapterArgs{ + TopicID: env.Topic, + ConverterType: converters.ConverterType(env.AdapterType), + SinkURI: env.Sink, + TransformerURI: env.Transformer, + Extensions: extensions, + } + + adapter, err := InitializeAdapter(ctx, + clients.MaxConnsPerHost(maxConnectionsPerHost), + clients.ProjectID(projectID), + SubscriptionID(env.Subscription), + Namespace(env.Namespace), + Name(env.Name), + ResourceGroup(env.ResourceGroup), + args) + + if err != nil { + logger.Fatal("Unable to create adapter", zap.Error(err)) } - logger.Info("Starting Pub/Sub Receive Adapter.", zap.Any("adapter", startable)) - if err := startable.Start(ctx); err != nil { - logger.Fatal("failed to start adapter: ", zap.Error(err)) + logger.Info("Starting Receive Adapter.", zap.String("projectID", projectID), zap.String("topicID", env.Topic), zap.String("subscriptionID", env.Subscription)) + if err := adapter.Start(ctx); err != nil { + logger.Error("Adapter has stopped with error", zap.String("projectID", projectID), zap.String("topicID", env.Topic), zap.String("subscriptionID", env.Subscription), zap.Error(err)) + } else { + logger.Error("Adapter has stopped", zap.String("projectID", projectID), zap.String("topicID", env.Topic), zap.String("subscriptionID", env.Subscription), zap.Error(err)) } + + // Wait a grace period for the handlers to shutdown. + time.Sleep(30 * time.Second) + logger.Info("Exiting...") } func flush(logger *zap.Logger) { diff --git a/cmd/pubsub/receive_adapter/wire.go b/cmd/pubsub/receive_adapter/wire.go new file mode 100644 index 0000000000..b7b83479db --- /dev/null +++ b/cmd/pubsub/receive_adapter/wire.go @@ -0,0 +1,42 @@ +// +build wireinject + +/* +Copyright 2020 Google LLC. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package main + +import ( + "context" + + "github.com/google/knative-gcp/pkg/pubsub/adapter" + "github.com/google/knative-gcp/pkg/utils/clients" + + "github.com/google/wire" +) + +func InitializeAdapter( + ctx context.Context, + maxConnsPerHost clients.MaxConnsPerHost, + projectID clients.ProjectID, + subscriptionID adapter.SubscriptionID, + namespace adapter.Namespace, + name adapter.Name, + resourceGroup adapter.ResourceGroup, + args *adapter.AdapterArgs) (*adapter.Adapter, error) { + panic(wire.Build( + adapter.AdapterSet, + )) +} diff --git a/cmd/pubsub/receive_adapter/wire_gen.go b/cmd/pubsub/receive_adapter/wire_gen.go new file mode 100644 index 0000000000..e78f6005c0 --- /dev/null +++ b/cmd/pubsub/receive_adapter/wire_gen.go @@ -0,0 +1,31 @@ +// Code generated by Wire. DO NOT EDIT. + +//go:generate wire +//+build !wireinject + +package main + +import ( + "context" + "github.com/google/knative-gcp/pkg/pubsub/adapter" + "github.com/google/knative-gcp/pkg/pubsub/adapter/converters" + "github.com/google/knative-gcp/pkg/utils/clients" +) + +// Injectors from wire.go: + +func InitializeAdapter(ctx context.Context, maxConnsPerHost clients.MaxConnsPerHost, projectID clients.ProjectID, subscriptionID adapter.SubscriptionID, namespace adapter.Namespace, name adapter.Name, resourceGroup adapter.ResourceGroup, args *adapter.AdapterArgs) (*adapter.Adapter, error) { + client, err := clients.NewPubsubClient(ctx, projectID) + if err != nil { + return nil, err + } + subscription := adapter.NewPubSubSubscription(ctx, client, subscriptionID) + httpClient := clients.NewHTTPClient(ctx, maxConnsPerHost) + converter := converters.NewPubSubConverter() + statsReporter, err := adapter.NewStatsReporter(name, namespace, resourceGroup) + if err != nil { + return nil, err + } + adapterAdapter := adapter.NewAdapter(ctx, projectID, namespace, name, resourceGroup, subscription, httpClient, converter, statsReporter, args) + return adapterAdapter, nil +} diff --git a/go.mod b/go.mod index 6938556a99..aa5c119999 100644 --- a/go.mod +++ b/go.mod @@ -30,10 +30,10 @@ require ( k8s.io/api v0.18.1 k8s.io/apimachinery v0.18.1 k8s.io/client-go v11.0.1-0.20190805182717-6502b5e7b1b5+incompatible - knative.dev/eventing v0.15.1-0.20200623095326-e1e5e1a81ca8 - knative.dev/pkg v0.0.0-20200623024526-fb0320d9287e - knative.dev/serving v0.15.1-0.20200623132926-f3cdbb37c9d3 - knative.dev/test-infra v0.0.0-20200623005026-1f7e5f05c52b // indirect + knative.dev/eventing v0.15.1-0.20200623172931-13e513727e77 + knative.dev/pkg v0.0.0-20200623173527-5658d93fb07e + knative.dev/serving v0.15.1-0.20200623190335-3459a76f9976 + knative.dev/test-infra v0.0.0-20200623184427-74a5e5b3bd23 // indirect sigs.k8s.io/yaml v1.2.0 ) diff --git a/go.sum b/go.sum index 5ebc2826c0..55a87af84c 100644 --- a/go.sum +++ b/go.sum @@ -1548,8 +1548,8 @@ k8s.io/utils v0.0.0-20200124190032-861946025e34/go.mod h1:sZAwmy6armz5eXlNoLmJcl knative.dev/caching v0.0.0-20190719140829-2032732871ff/go.mod h1:dHXFU6CGlLlbzaWc32g80cR92iuBSpsslDNBWI8C7eg= knative.dev/caching v0.0.0-20200116200605-67bca2c83dfa/go.mod h1:dHXFU6CGlLlbzaWc32g80cR92iuBSpsslDNBWI8C7eg= knative.dev/caching v0.0.0-20200606210318-787aec80f71c/go.mod h1:rWD+0zSqcE7L//jJyt866xtXsOi9hCdB0FoD4w2Rygg= -knative.dev/eventing v0.15.1-0.20200623095326-e1e5e1a81ca8 h1:z810IzK2xogISDuXgCSBtKeh5VJJg0Tz/h9PwwIOPhQ= -knative.dev/eventing v0.15.1-0.20200623095326-e1e5e1a81ca8/go.mod h1:JOWvyr9daR5Rdbf+FTKjFokzXJmTZq6IPNSePC/DbMU= +knative.dev/eventing v0.15.1-0.20200623172931-13e513727e77 h1:9HtCPVGLCzAZQQDCOKd1J5LNHEkGhJ539t49+uAMc5M= +knative.dev/eventing v0.15.1-0.20200623172931-13e513727e77/go.mod h1:BpLzl5yzbGvu5/qN4N/+PgR5LzAmW/UAbgX0EvbpWFs= knative.dev/eventing-contrib v0.6.1-0.20190723221543-5ce18048c08b/go.mod h1:SnXZgSGgMSMLNFTwTnpaOH7hXDzTFtw0J8OmHflNx3g= knative.dev/eventing-contrib v0.11.2/go.mod h1:SnXZgSGgMSMLNFTwTnpaOH7hXDzTFtw0J8OmHflNx3g= knative.dev/networking v0.0.0-20200622163826-421cd312c651 h1:k0diNnPM6Bh7kvnHOGFOtt5VGYjD2ksjh8gh7J8TSTU= @@ -1569,13 +1569,13 @@ knative.dev/pkg v0.0.0-20200603222317-b79e4a24ca50/go.mod h1:8IfPj/lpuKHHg82xZCl knative.dev/pkg v0.0.0-20200611204322-2ddcfef739a2/go.mod h1:rA+FklsrVahwF4a+D63NyHJlzDoAFH81K4J5CYuE3bA= knative.dev/pkg v0.0.0-20200619020725-7df8fc5d7743/go.mod h1:DquzK0hsLDcg2q63Sn+CngAyRwv4cKMpt5F19YzBfb0= knative.dev/pkg v0.0.0-20200622135826-98f8a949a106/go.mod h1:DquzK0hsLDcg2q63Sn+CngAyRwv4cKMpt5F19YzBfb0= -knative.dev/pkg v0.0.0-20200622150626-f0da4c9b6e79/go.mod h1:DquzK0hsLDcg2q63Sn+CngAyRwv4cKMpt5F19YzBfb0= -knative.dev/pkg v0.0.0-20200622193027-602857dcc5f4/go.mod h1:DquzK0hsLDcg2q63Sn+CngAyRwv4cKMpt5F19YzBfb0= knative.dev/pkg v0.0.0-20200623024526-fb0320d9287e h1:fmsw4i/We4S9yyaZadL2z8DKDIz7XzcY/v4yPGUmUA4= knative.dev/pkg v0.0.0-20200623024526-fb0320d9287e/go.mod h1:DquzK0hsLDcg2q63Sn+CngAyRwv4cKMpt5F19YzBfb0= +knative.dev/pkg v0.0.0-20200623173527-5658d93fb07e h1:MhQNsqYZ5BuDyZT/Q5MQMTMYTmkLcwq6MY+gGvPkymY= +knative.dev/pkg v0.0.0-20200623173527-5658d93fb07e/go.mod h1:DquzK0hsLDcg2q63Sn+CngAyRwv4cKMpt5F19YzBfb0= knative.dev/sample-controller v0.0.0-20200510050845-bf7c19498b7e/go.mod h1:D2ZDLrR9Dq9LiiVN7TatzI7WMcEPgk1MHbbhgBKE6W8= -knative.dev/serving v0.15.1-0.20200623132926-f3cdbb37c9d3 h1:9iZEJZRhk8fuC+IwFTlkV1gNMxF6Rh5RePpNTcYrWYM= -knative.dev/serving v0.15.1-0.20200623132926-f3cdbb37c9d3/go.mod h1:2YklL2M7E0ZPQv750Fxpiev9YFar6whHOmr4I2kAUgk= +knative.dev/serving v0.15.1-0.20200623190335-3459a76f9976 h1:6OJXcJicwoTg7U6/gXhLtxGLgy1ptmPGgWclWLn4fjU= +knative.dev/serving v0.15.1-0.20200623190335-3459a76f9976/go.mod h1:38aDwyUPrO1AY1LvUjd3Y7tbXunGbVeisByMRR4bjPY= knative.dev/test-infra v0.0.0-20200407185800-1b88cb3b45a5/go.mod h1:xcdUkMJrLlBswIZqL5zCuBFOC22WIPMQoVX1L35i0vQ= knative.dev/test-infra v0.0.0-20200505052144-5ea2f705bb55/go.mod h1:WqF1Azka+FxPZ20keR2zCNtiQA1MP9ZB4BH4HuI+SIU= knative.dev/test-infra v0.0.0-20200508015845-8d7d46a46176/go.mod h1:aMif0KXL4g19YCYwsy4Ocjjz5xgPlseYV+B95Oo4JGE= @@ -1589,9 +1589,10 @@ knative.dev/test-infra v0.0.0-20200617235125-6382dba95484 h1:5D1Fm6aA1T1QQXLb1Hk knative.dev/test-infra v0.0.0-20200617235125-6382dba95484/go.mod h1:+BfrTJpc++rH30gX/C0QY6NT2eYVzycll52uw6CrQnc= knative.dev/test-infra v0.0.0-20200619200026-0b0587234302 h1:nGw173QprRCSZab6KT4uSj0GTp3WNRo0nfk9Lpo3F1I= knative.dev/test-infra v0.0.0-20200619200026-0b0587234302/go.mod h1:H8QEB2Y35+vAuVtDbn7QBD+NQr9zQbbxNiovCLNH7F4= -knative.dev/test-infra v0.0.0-20200622185426-9cd9379661ea/go.mod h1:H8QEB2Y35+vAuVtDbn7QBD+NQr9zQbbxNiovCLNH7F4= knative.dev/test-infra v0.0.0-20200623005026-1f7e5f05c52b h1:qQTd9xCiV3/PVt2LsmELMVL2gT4eAScMaFrPqiQnt1I= knative.dev/test-infra v0.0.0-20200623005026-1f7e5f05c52b/go.mod h1:H8QEB2Y35+vAuVtDbn7QBD+NQr9zQbbxNiovCLNH7F4= +knative.dev/test-infra v0.0.0-20200623184427-74a5e5b3bd23 h1:Ijtvzv4vyoCNDFCocKgsVcT8z/tGuZ3plRmU7udBvoc= +knative.dev/test-infra v0.0.0-20200623184427-74a5e5b3bd23/go.mod h1:qKM6vO6hD6aa0ZYGDdyr5YiXPQMhbix1K8UWPUvVlIE= modernc.org/cc v1.0.0/go.mod h1:1Sk4//wdnYJiUIxnW8ddKpaOJCF37yAdqYnkxUpaYxw= modernc.org/golex v1.0.0/go.mod h1:b/QX9oBD/LhixY6NDh+IdGv17hgB+51fET1i2kPSmvk= modernc.org/mathutil v1.0.0/go.mod h1:wU0vUrJsVWBZ4P6e7xtFJEhFSNsfRLJ8H458uRjg03k= diff --git a/pkg/apis/broker/v1beta1/broker_types.go b/pkg/apis/broker/v1beta1/broker_types.go index dddd867e2f..cda538dc60 100644 --- a/pkg/apis/broker/v1beta1/broker_types.go +++ b/pkg/apis/broker/v1beta1/broker_types.go @@ -22,6 +22,7 @@ import ( "k8s.io/apimachinery/pkg/runtime/schema" eventingv1beta1 "knative.dev/eventing/pkg/apis/eventing/v1beta1" "knative.dev/pkg/apis" + duckv1 "knative.dev/pkg/apis/duck/v1" "knative.dev/pkg/kmeta" ) @@ -66,6 +67,9 @@ var ( // Check that we can create OwnerReferences to a Broker. _ kmeta.OwnerRefable = (*Broker)(nil) + + // Check that we implement KRShaped. + _ duckv1.KRShaped = (*Broker)(nil) ) // BrokerStatus represents the current state of a Broker. @@ -112,3 +116,13 @@ func (b *Broker) GetGroupVersionKind() schema.GroupVersionKind { func (b *Broker) GetUntypedSpec() interface{} { return b.Spec } + +// GetConditionSet retrieves the condition set for this resource. Implements the KRShaped interface. +func (*Broker) GetConditionSet() apis.ConditionSet { + return brokerCondSet +} + +// GetStatus retrieves the status of the Broker. Implements the KRShaped interface. +func (b *Broker) GetStatus() *duckv1.Status { + return &b.Status.Status +} diff --git a/pkg/apis/broker/v1beta1/broker_types_test.go b/pkg/apis/broker/v1beta1/broker_types_test.go index 9a9f34a3e6..11752bcfb1 100644 --- a/pkg/apis/broker/v1beta1/broker_types_test.go +++ b/pkg/apis/broker/v1beta1/broker_types_test.go @@ -22,6 +22,7 @@ import ( "github.com/google/go-cmp/cmp" "k8s.io/apimachinery/pkg/runtime/schema" eventingv1beta1 "knative.dev/eventing/pkg/apis/eventing/v1beta1" + "knative.dev/pkg/apis" ) func TestBroker_GetGroupVersionKind(t *testing.T) { @@ -46,3 +47,20 @@ func TestBroker_GetUntypedSpec(t *testing.T) { t.Errorf("untyped spec was not a BrokerSpec") } } + +func TestBroker_GetConditionSet(t *testing.T) { + b := &Broker{} + + if got, want := b.GetConditionSet().GetTopLevelConditionType(), apis.ConditionReady; got != want { + t.Errorf("GetTopLevelCondition=%v, want=%v", got, want) + } +} + +func TestBroker_GetStatus(t *testing.T) { + b := &Broker{ + Status: BrokerStatus{}, + } + if got, want := b.GetStatus(), &b.Status.Status; got != want { + t.Errorf("GetStatus=%v, want=%v", got, want) + } +} diff --git a/pkg/apis/broker/v1beta1/trigger_types.go b/pkg/apis/broker/v1beta1/trigger_types.go index 50f03f26d6..5ff048a0f9 100644 --- a/pkg/apis/broker/v1beta1/trigger_types.go +++ b/pkg/apis/broker/v1beta1/trigger_types.go @@ -22,6 +22,7 @@ import ( "k8s.io/apimachinery/pkg/runtime/schema" eventingv1beta1 "knative.dev/eventing/pkg/apis/eventing/v1beta1" "knative.dev/pkg/apis" + duckv1 "knative.dev/pkg/apis/duck/v1" "knative.dev/pkg/kmeta" ) @@ -66,6 +67,9 @@ var ( // Check that we can create OwnerReferences to a Trigger. _ kmeta.OwnerRefable = (*Trigger)(nil) + + // Check that we implement KRShaped. + _ duckv1.KRShaped = (*Trigger)(nil) ) // TriggerStatus represents the current state of a Trigger. @@ -109,3 +113,13 @@ func (t *Trigger) GetGroupVersionKind() schema.GroupVersionKind { func (t *Trigger) GetUntypedSpec() interface{} { return t.Spec } + +// GetConditionSet retrieves the condition set for this resource. Implements the KRShaped interface. +func (*Trigger) GetConditionSet() apis.ConditionSet { + return triggerCondSet +} + +// GetStatus retrieves the status of the Trigger. Implements the KRShaped interface. +func (t *Trigger) GetStatus() *duckv1.Status { + return &t.Status.Status +} diff --git a/pkg/apis/broker/v1beta1/trigger_types_test.go b/pkg/apis/broker/v1beta1/trigger_types_test.go index a3f316e931..f5fb303975 100644 --- a/pkg/apis/broker/v1beta1/trigger_types_test.go +++ b/pkg/apis/broker/v1beta1/trigger_types_test.go @@ -22,6 +22,7 @@ import ( "github.com/google/go-cmp/cmp" "k8s.io/apimachinery/pkg/runtime/schema" eventingv1beta1 "knative.dev/eventing/pkg/apis/eventing/v1beta1" + "knative.dev/pkg/apis" ) func TestTrigger_GetGroupVersionKind(t *testing.T) { @@ -46,3 +47,20 @@ func TestTrigger_GetUntypedSpec(t *testing.T) { t.Errorf("untyped spec was not a TriggerSpec") } } + +func TestTrigger_GetConditionSet(t *testing.T) { + tr := &Trigger{} + + if got, want := tr.GetConditionSet().GetTopLevelConditionType(), apis.ConditionReady; got != want { + t.Errorf("GetTopLevelCondition=%v, want=%v", got, want) + } +} + +func TestTrigger_GetStatus(t *testing.T) { + tr := &Trigger{ + Status: TriggerStatus{}, + } + if got, want := tr.GetStatus(), &tr.Status.Status; got != want { + t.Errorf("GetStatus=%v, want=%v", got, want) + } +} diff --git a/pkg/apis/events/v1alpha1/cloudauditlogssource_types.go b/pkg/apis/events/v1alpha1/cloudauditlogssource_types.go index 94b622ba43..97e3f5c2df 100644 --- a/pkg/apis/events/v1alpha1/cloudauditlogssource_types.go +++ b/pkg/apis/events/v1alpha1/cloudauditlogssource_types.go @@ -32,7 +32,6 @@ import ( ) // +genclient -// +genreconciler // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object // CloudAuditLogsSource is a specification for a Cloud Audit Log event source. diff --git a/pkg/apis/events/v1alpha1/cloudbuildsource_types.go b/pkg/apis/events/v1alpha1/cloudbuildsource_types.go index b3a4d91c12..8f9b1adc02 100644 --- a/pkg/apis/events/v1alpha1/cloudbuildsource_types.go +++ b/pkg/apis/events/v1alpha1/cloudbuildsource_types.go @@ -30,7 +30,6 @@ import ( // CloudBuildSource is a specification for a CloudBuildSource resource // +genclient -// +genreconciler // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object type CloudBuildSource struct { metav1.TypeMeta `json:",inline"` diff --git a/pkg/apis/events/v1alpha1/cloudpubsubsource_types.go b/pkg/apis/events/v1alpha1/cloudpubsubsource_types.go index f8a7a67c4a..3b50e20a81 100644 --- a/pkg/apis/events/v1alpha1/cloudpubsubsource_types.go +++ b/pkg/apis/events/v1alpha1/cloudpubsubsource_types.go @@ -33,7 +33,6 @@ import ( ) // +genclient -// +genreconciler // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object // CloudPubSubSource is a specification for a CloudPubSubSource resource diff --git a/pkg/apis/events/v1alpha1/cloudschedulersource_types.go b/pkg/apis/events/v1alpha1/cloudschedulersource_types.go index dfa7154ec3..c1d4d57177 100644 --- a/pkg/apis/events/v1alpha1/cloudschedulersource_types.go +++ b/pkg/apis/events/v1alpha1/cloudschedulersource_types.go @@ -32,7 +32,6 @@ import ( ) // +genclient -// +genreconciler // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object // CloudSchedulerSource is a specification for a CloudSchedulerSource resource diff --git a/pkg/apis/events/v1alpha1/cloudstoragesource_types.go b/pkg/apis/events/v1alpha1/cloudstoragesource_types.go index df63175b57..979f89c5d2 100644 --- a/pkg/apis/events/v1alpha1/cloudstoragesource_types.go +++ b/pkg/apis/events/v1alpha1/cloudstoragesource_types.go @@ -32,7 +32,6 @@ import ( ) // +genclient -// +genreconciler // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object // CloudStorageSource is a specification for a Google Cloud CloudStorageSource Source resource diff --git a/pkg/apis/events/v1beta1/cloudauditlogssource_types.go b/pkg/apis/events/v1beta1/cloudauditlogssource_types.go index adbd9646d5..ff0787cb9e 100644 --- a/pkg/apis/events/v1beta1/cloudauditlogssource_types.go +++ b/pkg/apis/events/v1beta1/cloudauditlogssource_types.go @@ -26,6 +26,7 @@ import ( "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" "knative.dev/pkg/apis" + duckv1 "knative.dev/pkg/apis/duck/v1" "knative.dev/pkg/kmeta" "knative.dev/pkg/webhook/resourcesemantics" ) @@ -53,6 +54,7 @@ var ( _ resourcesemantics.GenericCRD = (*CloudAuditLogsSource)(nil) _ kngcpduck.Identifiable = (*CloudAuditLogsSource)(nil) _ kngcpduck.PubSubable = (*CloudAuditLogsSource)(nil) + _ duckv1.KRShaped = (*CloudAuditLogsSource)(nil) ) const ( @@ -144,3 +146,13 @@ type CloudAuditLogsSourceList struct { Items []CloudAuditLogsSource `json:"items"` } + +// GetConditionSet retrieves the condition set for this resource. Implements the KRShaped interface. +func (*CloudAuditLogsSource) GetConditionSet() apis.ConditionSet { + return auditLogsSourceCondSet +} + +// GetStatus retrieves the status of the CloudAuditLogsSource. Implements the KRShaped interface. +func (s *CloudAuditLogsSource) GetStatus() *duckv1.Status { + return &s.Status.Status +} diff --git a/pkg/apis/events/v1beta1/cloudauditlogssource_types_test.go b/pkg/apis/events/v1beta1/cloudauditlogssource_types_test.go index 7ee88f194a..6f5f128b82 100644 --- a/pkg/apis/events/v1beta1/cloudauditlogssource_types_test.go +++ b/pkg/apis/events/v1beta1/cloudauditlogssource_types_test.go @@ -117,3 +117,20 @@ func TestCloudAuditLogsSourceIdentityStatus(t *testing.T) { t.Errorf("failed to get expected (-want, +got) = %v", diff) } } + +func TestCloudAuditLogsSource_GetConditionSet(t *testing.T) { + s := &CloudAuditLogsSource{} + + if got, want := s.GetConditionSet().GetTopLevelConditionType(), apis.ConditionReady; got != want { + t.Errorf("GetTopLevelCondition=%v, want=%v", got, want) + } +} + +func TestCloudAuditLogsSource_GetStatus(t *testing.T) { + s := &CloudAuditLogsSource{ + Status: CloudAuditLogsSourceStatus{}, + } + if got, want := s.GetStatus(), &s.Status.Status; got != want { + t.Errorf("GetStatus=%v, want=%v", got, want) + } +} diff --git a/pkg/apis/events/v1beta1/cloudbuildsource_types.go b/pkg/apis/events/v1beta1/cloudbuildsource_types.go index 72a52dbe33..bccba048c4 100644 --- a/pkg/apis/events/v1beta1/cloudbuildsource_types.go +++ b/pkg/apis/events/v1beta1/cloudbuildsource_types.go @@ -46,6 +46,7 @@ var ( _ kngcpduck.PubSubable = (*CloudBuildSource)(nil) _ kngcpduck.Identifiable = (*CloudBuildSource)(nil) _ = duck.VerifyType(&CloudBuildSource{}, &duckv1.Conditions{}) + _ duckv1.KRShaped = (*CloudBuildSource)(nil) ) // CloudBuildSourceSpec defines the desired state of the CloudBuildSource. @@ -123,3 +124,13 @@ func (bs *CloudBuildSource) PubSubStatus() *duckv1beta1.PubSubStatus { func (bs *CloudBuildSource) ConditionSet() *apis.ConditionSet { return &buildCondSet } + +// GetConditionSet retrieves the condition set for this resource. Implements the KRShaped interface. +func (*CloudBuildSource) GetConditionSet() apis.ConditionSet { + return buildCondSet +} + +// GetStatus retrieves the status of the CloudBuildSource. Implements the KRShaped interface. +func (s *CloudBuildSource) GetStatus() *duckv1.Status { + return &s.Status.Status +} diff --git a/pkg/apis/events/v1beta1/cloudbuildsource_types_test.go b/pkg/apis/events/v1beta1/cloudbuildsource_types_test.go index 170d0f7385..57a3853b29 100644 --- a/pkg/apis/events/v1beta1/cloudbuildsource_types_test.go +++ b/pkg/apis/events/v1beta1/cloudbuildsource_types_test.go @@ -100,3 +100,20 @@ func TestCloudBuildSourceConditionSet(t *testing.T) { t.Errorf("failed to get expected (-want, +got) = %v", diff) } } + +func TestCloudBuildSource_GetConditionSet(t *testing.T) { + s := &CloudBuildSource{} + + if got, want := s.GetConditionSet().GetTopLevelConditionType(), apis.ConditionReady; got != want { + t.Errorf("GetTopLevelCondition=%v, want=%v", got, want) + } +} + +func TestCloudBuildSource_GetStatus(t *testing.T) { + s := &CloudBuildSource{ + Status: CloudBuildSourceStatus{}, + } + if got, want := s.GetStatus(), &s.Status.Status; got != want { + t.Errorf("GetStatus=%v, want=%v", got, want) + } +} diff --git a/pkg/apis/events/v1beta1/cloudpubsubsource_types.go b/pkg/apis/events/v1beta1/cloudpubsubsource_types.go index 432190162c..0573f720d8 100644 --- a/pkg/apis/events/v1beta1/cloudpubsubsource_types.go +++ b/pkg/apis/events/v1beta1/cloudpubsubsource_types.go @@ -26,6 +26,7 @@ import ( "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" "knative.dev/pkg/apis" + duckv1 "knative.dev/pkg/apis/duck/v1" "knative.dev/pkg/kmeta" "knative.dev/pkg/webhook/resourcesemantics" ) @@ -54,6 +55,7 @@ var ( _ resourcesemantics.GenericCRD = (*CloudPubSubSource)(nil) _ kngcpduck.Identifiable = (*CloudPubSubSource)(nil) _ kngcpduck.PubSubable = (*CloudPubSubSource)(nil) + _ duckv1.KRShaped = (*CloudPubSubSource)(nil) ) // CloudPubSubSourceSpec defines the desired state of the CloudPubSubSource. @@ -174,3 +176,13 @@ func (ps *CloudPubSubSource) PubSubSpec() *duckv1beta1.PubSubSpec { func (s *CloudPubSubSource) PubSubStatus() *duckv1beta1.PubSubStatus { return &s.Status.PubSubStatus } + +// GetConditionSet retrieves the condition set for this resource. Implements the KRShaped interface. +func (*CloudPubSubSource) GetConditionSet() apis.ConditionSet { + return pubSubCondSet +} + +// GetStatus retrieves the status of the CloudPubSubSource. Implements the KRShaped interface. +func (s *CloudPubSubSource) GetStatus() *duckv1.Status { + return &s.Status.Status +} diff --git a/pkg/apis/events/v1beta1/cloudpubsubsource_types_test.go b/pkg/apis/events/v1beta1/cloudpubsubsource_types_test.go index 3be55e3ab6..d2b87caf7d 100644 --- a/pkg/apis/events/v1beta1/cloudpubsubsource_types_test.go +++ b/pkg/apis/events/v1beta1/cloudpubsubsource_types_test.go @@ -146,3 +146,20 @@ func TestCloudPubSubSourceConditionSet(t *testing.T) { t.Errorf("failed to get expected (-want, +got) = %v", diff) } } + +func TestCloudPubSubSource_GetConditionSet(t *testing.T) { + s := &CloudPubSubSource{} + + if got, want := s.GetConditionSet().GetTopLevelConditionType(), apis.ConditionReady; got != want { + t.Errorf("GetTopLevelCondition=%v, want=%v", got, want) + } +} + +func TestCloudPubSubSource_GetStatus(t *testing.T) { + s := &CloudPubSubSource{ + Status: CloudPubSubSourceStatus{}, + } + if got, want := s.GetStatus(), &s.Status.Status; got != want { + t.Errorf("GetStatus=%v, want=%v", got, want) + } +} \ No newline at end of file diff --git a/pkg/apis/events/v1beta1/cloudschedulersource_types.go b/pkg/apis/events/v1beta1/cloudschedulersource_types.go index db192a5b7e..d30b449317 100644 --- a/pkg/apis/events/v1beta1/cloudschedulersource_types.go +++ b/pkg/apis/events/v1beta1/cloudschedulersource_types.go @@ -25,6 +25,7 @@ import ( "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" "knative.dev/pkg/apis" + duckv1 "knative.dev/pkg/apis/duck/v1" "knative.dev/pkg/kmeta" "knative.dev/pkg/webhook/resourcesemantics" ) @@ -52,6 +53,7 @@ var ( _ resourcesemantics.GenericCRD = (*CloudSchedulerSource)(nil) _ kngcpduck.Identifiable = (*CloudSchedulerSource)(nil) _ kngcpduck.PubSubable = (*CloudSchedulerSource)(nil) + _ duckv1.KRShaped = (*CloudSchedulerSource)(nil) ) const ( @@ -148,3 +150,13 @@ type CloudSchedulerSourceList struct { Items []CloudSchedulerSource `json:"items"` } + +// GetConditionSet retrieves the condition set for this resource. Implements the KRShaped interface. +func (*CloudSchedulerSource) GetConditionSet() apis.ConditionSet { + return schedulerCondSet +} + +// GetStatus retrieves the status of the CloudSchedulerSource. Implements the KRShaped interface. +func (s *CloudSchedulerSource) GetStatus() *duckv1.Status { + return &s.Status.Status +} diff --git a/pkg/apis/events/v1beta1/cloudschedulersource_types_test.go b/pkg/apis/events/v1beta1/cloudschedulersource_types_test.go index e224ad63e0..c333a2adc7 100644 --- a/pkg/apis/events/v1beta1/cloudschedulersource_types_test.go +++ b/pkg/apis/events/v1beta1/cloudschedulersource_types_test.go @@ -107,3 +107,20 @@ func TestCloudSchedulerSourceIdentityStatus(t *testing.T) { t.Errorf("failed to get expected (-want, +got) = %v", diff) } } + +func TestCloudSchedulerSource_GetConditionSet(t *testing.T) { + s := &CloudSchedulerSource{} + + if got, want := s.GetConditionSet().GetTopLevelConditionType(), apis.ConditionReady; got != want { + t.Errorf("GetTopLevelCondition=%v, want=%v", got, want) + } +} + +func TestCloudSchedulerSource_GetStatus(t *testing.T) { + s := &CloudSchedulerSource{ + Status: CloudSchedulerSourceStatus{}, + } + if got, want := s.GetStatus(), &s.Status.Status; got != want { + t.Errorf("GetStatus=%v, want=%v", got, want) + } +} diff --git a/pkg/apis/events/v1beta1/cloudstoragesource_types.go b/pkg/apis/events/v1beta1/cloudstoragesource_types.go index f68f864a0e..4681a46c47 100644 --- a/pkg/apis/events/v1beta1/cloudstoragesource_types.go +++ b/pkg/apis/events/v1beta1/cloudstoragesource_types.go @@ -27,6 +27,8 @@ import ( "knative.dev/pkg/apis" "knative.dev/pkg/kmeta" "knative.dev/pkg/webhook/resourcesemantics" + + duckv1 "knative.dev/pkg/apis/duck/v1" ) // +genclient @@ -52,6 +54,7 @@ var ( _ resourcesemantics.GenericCRD = (*CloudStorageSource)(nil) _ kngcpduck.Identifiable = (*CloudStorageSource)(nil) _ kngcpduck.PubSubable = (*CloudStorageSource)(nil) + _ duckv1.KRShaped = (*CloudStorageSource)(nil) ) // CloudStorageSourceSpec is the spec for a CloudStorageSource resource @@ -158,3 +161,13 @@ type CloudStorageSourceList struct { Items []CloudStorageSource `json:"items"` } + +// GetConditionSet retrieves the condition set for this resource. Implements the KRShaped interface. +func (*CloudStorageSource) GetConditionSet() apis.ConditionSet { + return storageCondSet +} + +// GetStatus retrieves the status of the CloudStorageSource. Implements the KRShaped interface. +func (s *CloudStorageSource) GetStatus() *duckv1.Status { + return &s.Status.Status +} diff --git a/pkg/apis/events/v1beta1/cloudstoragesource_types_test.go b/pkg/apis/events/v1beta1/cloudstoragesource_types_test.go index 010c514f99..d4faef1bae 100644 --- a/pkg/apis/events/v1beta1/cloudstoragesource_types_test.go +++ b/pkg/apis/events/v1beta1/cloudstoragesource_types_test.go @@ -105,3 +105,20 @@ func TestCloudStorageSourceIdentityStatus(t *testing.T) { t.Errorf("failed to get expected (-want, +got) = %v", diff) } } + +func TestCloudStorageSource_GetConditionSet(t *testing.T) { + s := &CloudStorageSource{} + + if got, want := s.GetConditionSet().GetTopLevelConditionType(), apis.ConditionReady; got != want { + t.Errorf("GetTopLevelCondition=%v, want=%v", got, want) + } +} + +func TestCloudStorageSource_GetStatus(t *testing.T) { + s := &CloudStorageSource{ + Status: CloudStorageSourceStatus{}, + } + if got, want := s.GetStatus(), &s.Status.Status; got != want { + t.Errorf("GetStatus=%v, want=%v", got, want) + } +} diff --git a/pkg/apis/intevents/v1alpha1/brokercell_types.go b/pkg/apis/intevents/v1alpha1/brokercell_types.go index 8c478c4666..72dbe33494 100644 --- a/pkg/apis/intevents/v1alpha1/brokercell_types.go +++ b/pkg/apis/intevents/v1alpha1/brokercell_types.go @@ -63,6 +63,9 @@ var ( // Check that we can create OwnerReferences to a BrokerCell. _ kmeta.OwnerRefable = (*BrokerCell)(nil) + + // Check that BrokerCell implements the KRShaped duck type. + _ duckv1.KRShaped = (*BrokerCell)(nil) ) // BrokerCellSpec defines the desired state of a Brokercell. @@ -103,3 +106,13 @@ func (bc *BrokerCell) GetGroupVersionKind() schema.GroupVersionKind { func (bc *BrokerCell) GetUntypedSpec() interface{} { return bc.Spec } + +// GetConditionSet retrieves the condition set for this resource. Implements the KRShaped interface. +func (*BrokerCell) GetConditionSet() apis.ConditionSet { + return brokerCellCondSet +} + +// GetStatus retrieves the status of the BrokerCell. Implements the KRShaped interface. +func (bc *BrokerCell) GetStatus() *duckv1.Status { + return &bc.Status.Status +} diff --git a/pkg/apis/intevents/v1alpha1/brokercell_types_test.go b/pkg/apis/intevents/v1alpha1/brokercell_types_test.go index a16525afa1..9c194cd1a2 100644 --- a/pkg/apis/intevents/v1alpha1/brokercell_types_test.go +++ b/pkg/apis/intevents/v1alpha1/brokercell_types_test.go @@ -17,6 +17,7 @@ limitations under the License. package v1alpha1 import ( + "knative.dev/pkg/apis" "testing" "github.com/google/go-cmp/cmp" @@ -45,3 +46,20 @@ func TestBrokerCell_GetUntypedSpec(t *testing.T) { t.Errorf("untyped spec was not a BrokerSpec") } } + +func TestBrokerCell_GetConditionSet(t *testing.T) { + bc := &BrokerCell{} + + if got, want := bc.GetConditionSet().GetTopLevelConditionType(), apis.ConditionReady; got != want { + t.Errorf("GetTopLevelCondition=%v, want=%v", got, want) + } +} + +func TestBrokerCell_GetStatus(t *testing.T) { + bc := &BrokerCell{ + Status: BrokerCellStatus{}, + } + if got, want := bc.GetStatus(), &bc.Status.Status; got != want { + t.Errorf("GetStatus=%v, want=%v", got, want) + } +} diff --git a/pkg/apis/intevents/v1alpha1/pullsubscription_types.go b/pkg/apis/intevents/v1alpha1/pullsubscription_types.go index ef68609010..0a72bf6aed 100644 --- a/pkg/apis/intevents/v1alpha1/pullsubscription_types.go +++ b/pkg/apis/intevents/v1alpha1/pullsubscription_types.go @@ -30,7 +30,6 @@ import ( ) // +genclient -// +genreconciler // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object // PullSubscription is the Schema for the gcppullSubscriptions API. diff --git a/pkg/apis/intevents/v1alpha1/topic_types.go b/pkg/apis/intevents/v1alpha1/topic_types.go index 035fe4ebca..030777b5a3 100644 --- a/pkg/apis/intevents/v1alpha1/topic_types.go +++ b/pkg/apis/intevents/v1alpha1/topic_types.go @@ -31,7 +31,6 @@ import ( ) // +genclient -// +genreconciler // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object // Topic is a resource representing a Topic backed by Google Cloud Pub/Sub. diff --git a/pkg/apis/intevents/v1beta1/pullsubscription_types.go b/pkg/apis/intevents/v1beta1/pullsubscription_types.go index 7acc581217..b7b9e31e9a 100644 --- a/pkg/apis/intevents/v1beta1/pullsubscription_types.go +++ b/pkg/apis/intevents/v1beta1/pullsubscription_types.go @@ -43,11 +43,6 @@ type PullSubscription struct { Status PullSubscriptionStatus `json:"status,omitempty"` } -// PubSubMode returns the mode currently set for PullSubscription. -func (p *PullSubscription) PubSubMode() ModeType { - return p.Spec.Mode -} - // Check that PullSubscription can be converted to other versions. var _ apis.Convertible = (*PullSubscription)(nil) @@ -57,6 +52,10 @@ var _ runtime.Object = (*PullSubscription)(nil) // Check that PullSubscription implements the Conditions duck type. var _ = duck.VerifyType(&PullSubscription{}, &duckv1.Conditions{}) +// Check that PullSubscription implements the KRShaped duck type. +var _ duckv1.KRShaped = (*PullSubscription)(nil) + + // PullSubscriptionSpec defines the desired state of the PullSubscription. type PullSubscriptionSpec struct { v1beta1.PubSubSpec `json:",inline"` @@ -102,6 +101,11 @@ type PullSubscriptionSpec struct { AdapterType string `json:"adapterType,omitempty"` } +// PubSubMode returns the mode currently set for PullSubscription. +func (p *PullSubscription) PubSubMode() ModeType { + return p.Spec.Mode +} + // GetAckDeadline parses AckDeadline and returns the default if an error occurs. func (ps PullSubscriptionSpec) GetAckDeadline() time.Duration { if ps.AckDeadline != nil { @@ -215,3 +219,13 @@ func (s *PullSubscription) IdentityStatus() *v1beta1.IdentityStatus { func (*PullSubscription) ConditionSet() *apis.ConditionSet { return &pullSubscriptionCondSet } + +// GetConditionSet retrieves the condition set for this resource. Implements the KRShaped interface. +func (*PullSubscription) GetConditionSet() apis.ConditionSet { + return pullSubscriptionCondSet +} + +// GetStatus retrieves the status of the PullSubscription. Implements the KRShaped interface. +func (s *PullSubscription) GetStatus() *duckv1.Status { + return &s.Status.Status +} diff --git a/pkg/apis/intevents/v1beta1/pullsubscription_types_test.go b/pkg/apis/intevents/v1beta1/pullsubscription_types_test.go index ad292b58fd..bc10fdf31e 100644 --- a/pkg/apis/intevents/v1beta1/pullsubscription_types_test.go +++ b/pkg/apis/intevents/v1beta1/pullsubscription_types_test.go @@ -152,3 +152,20 @@ func TestPullSubscriptionConditionSet(t *testing.T) { t.Errorf("failed to get expected (-want, +got) = %v", diff) } } + +func TestPullSubscription_GetConditionSet(t *testing.T) { + s := &PullSubscription{} + + if got, want := s.GetConditionSet().GetTopLevelConditionType(), apis.ConditionReady; got != want { + t.Errorf("GetTopLevelCondition=%v, want=%v", got, want) + } +} + +func TestPullSubscription_GetStatus(t *testing.T) { + s := &PullSubscription{ + Status: PullSubscriptionStatus{}, + } + if got, want := s.GetStatus(), &s.Status.Status; got != want { + t.Errorf("GetStatus=%v, want=%v", got, want) + } +} diff --git a/pkg/apis/intevents/v1beta1/topic_types.go b/pkg/apis/intevents/v1beta1/topic_types.go index b9505ca650..23d9ee868b 100644 --- a/pkg/apis/intevents/v1beta1/topic_types.go +++ b/pkg/apis/intevents/v1beta1/topic_types.go @@ -59,6 +59,9 @@ var _ resourcesemantics.GenericCRD = (*Topic)(nil) // Check that Topic implements the Conditions duck type. var _ = duck.VerifyType(&Topic{}, &duckv1.Conditions{}) +// Check that Topic implements the KRShaped duck type. +var _ duckv1.KRShaped = (*Topic)(nil) + // TopicSpec defines parameters for creating or publishing to a Cloud Pub/Sub // Topic depending on the PropagationPolicy. type TopicSpec struct { @@ -169,16 +172,26 @@ func (t *Topic) GetGroupVersionKind() schema.GroupVersionKind { // Methods for identifiable interface. // IdentitySpec returns the IdentitySpec portion of the Spec. -func (s *Topic) IdentitySpec() *v1beta1.IdentitySpec { - return &s.Spec.IdentitySpec +func (t *Topic) IdentitySpec() *v1beta1.IdentitySpec { + return &t.Spec.IdentitySpec } // IdentityStatus returns the IdentityStatus portion of the Status. -func (s *Topic) IdentityStatus() *v1beta1.IdentityStatus { - return &s.Status.IdentityStatus +func (t *Topic) IdentityStatus() *v1beta1.IdentityStatus { + return &t.Status.IdentityStatus } // ConditionSet returns the apis.ConditionSet of the embedding object -func (ps *Topic) ConditionSet() *apis.ConditionSet { +func (t *Topic) ConditionSet() *apis.ConditionSet { return &topicCondSet } + +// GetConditionSet retrieves the condition set for this resource. Implements the KRShaped interface. +func (*Topic) GetConditionSet() apis.ConditionSet { + return topicCondSet +} + +// GetStatus retrieves the status of the Topic. Implements the KRShaped interface. +func (t *Topic) GetStatus() *duckv1.Status { + return &t.Status.Status +} diff --git a/pkg/apis/intevents/v1beta1/topic_types_test.go b/pkg/apis/intevents/v1beta1/topic_types_test.go index 65bbddbc9b..da1343d7b5 100644 --- a/pkg/apis/intevents/v1beta1/topic_types_test.go +++ b/pkg/apis/intevents/v1beta1/topic_types_test.go @@ -91,3 +91,20 @@ func TestTopicConditionSet(t *testing.T) { t.Errorf("failed to get expected (-want, +got) = %v", diff) } } + +func TestTopic_GetConditionSet(t *testing.T) { + tp := &Topic{} + + if got, want := tp.GetConditionSet().GetTopLevelConditionType(), apis.ConditionReady; got != want { + t.Errorf("GetTopLevelCondition=%v, want=%v", got, want) + } +} + +func TestTopic_GetStatus(t *testing.T) { + tp := &Topic{ + Status: TopicStatus{}, + } + if got, want := tp.GetStatus(), &tp.Status.Status; got != want { + t.Errorf("GetStatus=%v, want=%v", got, want) + } +} diff --git a/pkg/apis/messaging/v1alpha1/channel_types.go b/pkg/apis/messaging/v1alpha1/channel_types.go index a61899556f..9a2ba945a5 100644 --- a/pkg/apis/messaging/v1alpha1/channel_types.go +++ b/pkg/apis/messaging/v1alpha1/channel_types.go @@ -31,7 +31,6 @@ import ( ) // +genclient -// +genreconciler // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object // Channel is a resource representing an channel backed by Google Cloud Pub/Sub. diff --git a/pkg/apis/messaging/v1beta1/channel_types.go b/pkg/apis/messaging/v1beta1/channel_types.go index e0e1eb6de9..5cd8a37377 100644 --- a/pkg/apis/messaging/v1beta1/channel_types.go +++ b/pkg/apis/messaging/v1beta1/channel_types.go @@ -57,6 +57,7 @@ var ( _ runtime.Object = (*Channel)(nil) _ resourcesemantics.GenericCRD = (*Channel)(nil) _ kngcpduck.Identifiable = (*Channel)(nil) + _ duckv1.KRShaped = (*Channel)(nil) ) // ChannelSpec defines which subscribers have expressed interest in @@ -153,3 +154,13 @@ type ChannelList struct { func (c *Channel) GetGroupVersionKind() schema.GroupVersionKind { return SchemeGroupVersion.WithKind("Channel") } + +// GetConditionSet retrieves the condition set for this resource. Implements the KRShaped interface. +func (*Channel) GetConditionSet() apis.ConditionSet { + return channelCondSet +} + +// GetStatus retrieves the status of the Channel. Implements the KRShaped interface. +func (c *Channel) GetStatus() *duckv1.Status { + return &c.Status.Status +} diff --git a/pkg/apis/messaging/v1beta1/channel_types_test.go b/pkg/apis/messaging/v1beta1/channel_types_test.go index 4339593e13..f7a964a58c 100644 --- a/pkg/apis/messaging/v1beta1/channel_types_test.go +++ b/pkg/apis/messaging/v1beta1/channel_types_test.go @@ -94,3 +94,20 @@ func TestChannelConditionSet(t *testing.T) { t.Errorf("failed to get expected (-want, +got) = %v", diff) } } + +func TestChannel_GetConditionSet(t *testing.T) { + c := &Channel{} + + if got, want := c.GetConditionSet().GetTopLevelConditionType(), apis.ConditionReady; got != want { + t.Errorf("GetTopLevelCondition=%v, want=%v", got, want) + } +} + +func TestChannel_GetStatus(t *testing.T) { + c := &Channel{ + Status: ChannelStatus{}, + } + if got, want := c.GetStatus(), &c.Status.Status; got != want { + t.Errorf("GetStatus=%v, want=%v", got, want) + } +} diff --git a/pkg/broker/eventutil/hops.go b/pkg/broker/eventutil/hops.go index 09c7c7bf09..bfac22ccb6 100644 --- a/pkg/broker/eventutil/hops.go +++ b/pkg/broker/eventutil/hops.go @@ -19,9 +19,9 @@ package eventutil import ( "context" - cetypes "github.com/cloudevents/sdk-go/pkg/cloudevents/types" "github.com/cloudevents/sdk-go/v2/binding" "github.com/cloudevents/sdk-go/v2/event" + cetypes "github.com/cloudevents/sdk-go/v2/types" "go.uber.org/zap" "knative.dev/eventing/pkg/logging" ) diff --git a/pkg/broker/handler/fanout.go b/pkg/broker/handler/fanout.go index d4924c453b..7e008c2839 100644 --- a/pkg/broker/handler/fanout.go +++ b/pkg/broker/handler/fanout.go @@ -176,7 +176,6 @@ func (p *FanoutPool) SyncOnce(ctx context.Context) error { // Start the handler with broker key in context. hc.Start(handlerctx.WithBrokerKey(ctx, b.Key()), func(err error) { - // We will anyway get an error because of https://github.com/cloudevents/sdk-go/issues/470 if err != nil { logging.FromContext(ctx).Error("handler for broker has stopped with error", zap.String("broker", b.Key()), zap.Error(err)) } else { diff --git a/pkg/broker/handler/providers.go b/pkg/broker/handler/providers.go index 65f2bed7b6..4b425ae8f9 100644 --- a/pkg/broker/handler/providers.go +++ b/pkg/broker/handler/providers.go @@ -24,6 +24,7 @@ import ( "cloud.google.com/go/pubsub" cepubsub "github.com/cloudevents/sdk-go/protocol/pubsub/v2" ceclient "github.com/cloudevents/sdk-go/v2/client" + "github.com/google/knative-gcp/pkg/utils/clients" "github.com/google/wire" "go.opencensus.io/plugin/ochttp" "go.opencensus.io/plugin/ochttp/propagation/tracecontext" @@ -54,22 +55,14 @@ var ( ProviderSet = wire.NewSet( NewFanoutPool, NewRetryPool, - NewPubsubClient, + clients.NewPubsubClient, NewRetryClient, wire.Value(DefaultHTTPClient), wire.Value(DefaultCEClientOpts), ) ) -type ( - ProjectID string - RetryClient ceclient.Client -) - -// NewPubsubClient provides a pubsub client for the supplied project ID. -func NewPubsubClient(ctx context.Context, projectID ProjectID) (*pubsub.Client, error) { - return pubsub.NewClient(ctx, string(projectID)) -} +type RetryClient ceclient.Client // NewRetryClient provides a retry CE client from a PubSub client and list of CE client options. func NewRetryClient(ctx context.Context, client *pubsub.Client, opts ...ceclient.Option) (RetryClient, error) { diff --git a/pkg/broker/ingress/handler.go b/pkg/broker/ingress/handler.go index c2a30d6c48..5b9cf36f6c 100644 --- a/pkg/broker/ingress/handler.go +++ b/pkg/broker/ingress/handler.go @@ -31,6 +31,7 @@ import ( "github.com/cloudevents/sdk-go/v2/protocol/http" "github.com/google/knative-gcp/pkg/metrics" "github.com/google/knative-gcp/pkg/tracing" + "github.com/google/knative-gcp/pkg/utils/clients" "github.com/google/wire" "go.opencensus.io/trace" "go.uber.org/zap" @@ -57,11 +58,11 @@ const ( // HandlerSet provides a handler with a real HTTPMessageReceiver and pubsub MultiTopicDecoupleSink. var HandlerSet wire.ProviderSet = wire.NewSet( NewHandler, - NewHTTPMessageReceiver, + clients.NewHTTPMessageReceiver, wire.Bind(new(HttpMessageReceiver), new(*kncloudevents.HttpMessageReceiver)), NewMultiTopicDecoupleSink, wire.Bind(new(DecoupleSink), new(*multiTopicDecoupleSink)), - NewPubsubClient, + clients.NewPubsubClient, metrics.NewIngressReporter, ) diff --git a/pkg/client/injection/reconciler/broker/v1beta1/broker/reconciler.go b/pkg/client/injection/reconciler/broker/v1beta1/broker/reconciler.go index 9a65810428..0a144e8079 100644 --- a/pkg/client/injection/reconciler/broker/v1beta1/broker/reconciler.go +++ b/pkg/client/injection/reconciler/broker/v1beta1/broker/reconciler.go @@ -236,10 +236,14 @@ func (r *reconcilerImpl) Reconcile(ctx context.Context, key string) error { return fmt.Errorf("failed to set finalizers: %w", err) } + reconciler.PreProcessReconcile(ctx, resource) + // Reconcile this copy of the resource and then write back any status // updates regardless of whether the reconciliation errored out. reconcileEvent = r.reconciler.ReconcileKind(ctx, resource) + reconciler.PostProcessReconcile(ctx, resource, original) + } else if isROI { // Append the target method to the logger. logger = logger.With(zap.String("targetMethod", "ObserveKind")) diff --git a/pkg/client/injection/reconciler/broker/v1beta1/trigger/reconciler.go b/pkg/client/injection/reconciler/broker/v1beta1/trigger/reconciler.go index c5cbd65048..daa9235258 100644 --- a/pkg/client/injection/reconciler/broker/v1beta1/trigger/reconciler.go +++ b/pkg/client/injection/reconciler/broker/v1beta1/trigger/reconciler.go @@ -225,10 +225,14 @@ func (r *reconcilerImpl) Reconcile(ctx context.Context, key string) error { return fmt.Errorf("failed to set finalizers: %w", err) } + reconciler.PreProcessReconcile(ctx, resource) + // Reconcile this copy of the resource and then write back any status // updates regardless of whether the reconciliation errored out. reconcileEvent = r.reconciler.ReconcileKind(ctx, resource) + reconciler.PostProcessReconcile(ctx, resource, original) + } else if isROI { // Append the target method to the logger. logger = logger.With(zap.String("targetMethod", "ObserveKind")) diff --git a/pkg/client/injection/reconciler/events/v1alpha1/cloudauditlogssource/controller.go b/pkg/client/injection/reconciler/events/v1alpha1/cloudauditlogssource/controller.go deleted file mode 100644 index 1963e2de5c..0000000000 --- a/pkg/client/injection/reconciler/events/v1alpha1/cloudauditlogssource/controller.go +++ /dev/null @@ -1,139 +0,0 @@ -/* -Copyright 2020 Google LLC - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -// Code generated by injection-gen. DO NOT EDIT. - -package cloudauditlogssource - -import ( - context "context" - fmt "fmt" - reflect "reflect" - strings "strings" - - versionedscheme "github.com/google/knative-gcp/pkg/client/clientset/versioned/scheme" - client "github.com/google/knative-gcp/pkg/client/injection/client" - cloudauditlogssource "github.com/google/knative-gcp/pkg/client/injection/informers/events/v1alpha1/cloudauditlogssource" - corev1 "k8s.io/api/core/v1" - labels "k8s.io/apimachinery/pkg/labels" - types "k8s.io/apimachinery/pkg/types" - watch "k8s.io/apimachinery/pkg/watch" - scheme "k8s.io/client-go/kubernetes/scheme" - v1 "k8s.io/client-go/kubernetes/typed/core/v1" - record "k8s.io/client-go/tools/record" - kubeclient "knative.dev/pkg/client/injection/kube/client" - controller "knative.dev/pkg/controller" - logging "knative.dev/pkg/logging" - reconciler "knative.dev/pkg/reconciler" -) - -const ( - defaultControllerAgentName = "cloudauditlogssource-controller" - defaultFinalizerName = "cloudauditlogssources.events.cloud.google.com" -) - -// NewImpl returns a controller.Impl that handles queuing and feeding work from -// the queue through an implementation of controller.Reconciler, delegating to -// the provided Interface and optional Finalizer methods. OptionsFn is used to return -// controller.Options to be used but the internal reconciler. -func NewImpl(ctx context.Context, r Interface, optionsFns ...controller.OptionsFn) *controller.Impl { - logger := logging.FromContext(ctx) - - // Check the options function input. It should be 0 or 1. - if len(optionsFns) > 1 { - logger.Fatalf("up to one options function is supported, found %d", len(optionsFns)) - } - - cloudauditlogssourceInformer := cloudauditlogssource.Get(ctx) - - lister := cloudauditlogssourceInformer.Lister() - - rec := &reconcilerImpl{ - LeaderAwareFuncs: reconciler.LeaderAwareFuncs{ - PromoteFunc: func(bkt reconciler.Bucket, enq func(reconciler.Bucket, types.NamespacedName)) error { - all, err := lister.List(labels.Everything()) - if err != nil { - return err - } - for _, elt := range all { - // TODO: Consider letting users specify a filter in options. - enq(bkt, types.NamespacedName{ - Namespace: elt.GetNamespace(), - Name: elt.GetName(), - }) - } - return nil - }, - }, - Client: client.Get(ctx), - Lister: lister, - reconciler: r, - finalizerName: defaultFinalizerName, - } - - t := reflect.TypeOf(r).Elem() - queueName := fmt.Sprintf("%s.%s", strings.ReplaceAll(t.PkgPath(), "/", "-"), t.Name()) - - impl := controller.NewImpl(rec, logger, queueName) - agentName := defaultControllerAgentName - - // Pass impl to the options. Save any optional results. - for _, fn := range optionsFns { - opts := fn(impl) - if opts.ConfigStore != nil { - rec.configStore = opts.ConfigStore - } - if opts.FinalizerName != "" { - rec.finalizerName = opts.FinalizerName - } - if opts.AgentName != "" { - agentName = opts.AgentName - } - } - - rec.Recorder = createRecorder(ctx, agentName) - - return impl -} - -func createRecorder(ctx context.Context, agentName string) record.EventRecorder { - logger := logging.FromContext(ctx) - - recorder := controller.GetEventRecorder(ctx) - if recorder == nil { - // Create event broadcaster - logger.Debug("Creating event broadcaster") - eventBroadcaster := record.NewBroadcaster() - watches := []watch.Interface{ - eventBroadcaster.StartLogging(logger.Named("event-broadcaster").Infof), - eventBroadcaster.StartRecordingToSink( - &v1.EventSinkImpl{Interface: kubeclient.Get(ctx).CoreV1().Events("")}), - } - recorder = eventBroadcaster.NewRecorder(scheme.Scheme, corev1.EventSource{Component: agentName}) - go func() { - <-ctx.Done() - for _, w := range watches { - w.Stop() - } - }() - } - - return recorder -} - -func init() { - versionedscheme.AddToScheme(scheme.Scheme) -} diff --git a/pkg/client/injection/reconciler/events/v1alpha1/cloudauditlogssource/reconciler.go b/pkg/client/injection/reconciler/events/v1alpha1/cloudauditlogssource/reconciler.go deleted file mode 100644 index 0dc988f32e..0000000000 --- a/pkg/client/injection/reconciler/events/v1alpha1/cloudauditlogssource/reconciler.go +++ /dev/null @@ -1,430 +0,0 @@ -/* -Copyright 2020 Google LLC - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -// Code generated by injection-gen. DO NOT EDIT. - -package cloudauditlogssource - -import ( - context "context" - json "encoding/json" - fmt "fmt" - reflect "reflect" - - v1alpha1 "github.com/google/knative-gcp/pkg/apis/events/v1alpha1" - versioned "github.com/google/knative-gcp/pkg/client/clientset/versioned" - eventsv1alpha1 "github.com/google/knative-gcp/pkg/client/listers/events/v1alpha1" - zap "go.uber.org/zap" - v1 "k8s.io/api/core/v1" - equality "k8s.io/apimachinery/pkg/api/equality" - errors "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - labels "k8s.io/apimachinery/pkg/labels" - types "k8s.io/apimachinery/pkg/types" - sets "k8s.io/apimachinery/pkg/util/sets" - cache "k8s.io/client-go/tools/cache" - record "k8s.io/client-go/tools/record" - controller "knative.dev/pkg/controller" - logging "knative.dev/pkg/logging" - reconciler "knative.dev/pkg/reconciler" -) - -// Interface defines the strongly typed interfaces to be implemented by a -// controller reconciling v1alpha1.CloudAuditLogsSource. -type Interface interface { - // ReconcileKind implements custom logic to reconcile v1alpha1.CloudAuditLogsSource. Any changes - // to the objects .Status or .Finalizers will be propagated to the stored - // object. It is recommended that implementors do not call any update calls - // for the Kind inside of ReconcileKind, it is the responsibility of the calling - // controller to propagate those properties. The resource passed to ReconcileKind - // will always have an empty deletion timestamp. - ReconcileKind(ctx context.Context, o *v1alpha1.CloudAuditLogsSource) reconciler.Event -} - -// Finalizer defines the strongly typed interfaces to be implemented by a -// controller finalizing v1alpha1.CloudAuditLogsSource. -type Finalizer interface { - // FinalizeKind implements custom logic to finalize v1alpha1.CloudAuditLogsSource. Any changes - // to the objects .Status or .Finalizers will be ignored. Returning a nil or - // Normal type reconciler.Event will allow the finalizer to be deleted on - // the resource. The resource passed to FinalizeKind will always have a set - // deletion timestamp. - FinalizeKind(ctx context.Context, o *v1alpha1.CloudAuditLogsSource) reconciler.Event -} - -// ReadOnlyInterface defines the strongly typed interfaces to be implemented by a -// controller reconciling v1alpha1.CloudAuditLogsSource if they want to process resources for which -// they are not the leader. -type ReadOnlyInterface interface { - // ObserveKind implements logic to observe v1alpha1.CloudAuditLogsSource. - // This method should not write to the API. - ObserveKind(ctx context.Context, o *v1alpha1.CloudAuditLogsSource) reconciler.Event -} - -// ReadOnlyFinalizer defines the strongly typed interfaces to be implemented by a -// controller finalizing v1alpha1.CloudAuditLogsSource if they want to process tombstoned resources -// even when they are not the leader. Due to the nature of how finalizers are handled -// there are no guarantees that this will be called. -type ReadOnlyFinalizer interface { - // ObserveFinalizeKind implements custom logic to observe the final state of v1alpha1.CloudAuditLogsSource. - // This method should not write to the API. - ObserveFinalizeKind(ctx context.Context, o *v1alpha1.CloudAuditLogsSource) reconciler.Event -} - -// reconcilerImpl implements controller.Reconciler for v1alpha1.CloudAuditLogsSource resources. -type reconcilerImpl struct { - // LeaderAwareFuncs is inlined to help us implement reconciler.LeaderAware - reconciler.LeaderAwareFuncs - - // Client is used to write back status updates. - Client versioned.Interface - - // Listers index properties about resources - Lister eventsv1alpha1.CloudAuditLogsSourceLister - - // Recorder is an event recorder for recording Event resources to the - // Kubernetes API. - Recorder record.EventRecorder - - // configStore allows for decorating a context with config maps. - // +optional - configStore reconciler.ConfigStore - - // reconciler is the implementation of the business logic of the resource. - reconciler Interface - - // finalizerName is the name of the finalizer to reconcile. - finalizerName string -} - -// Check that our Reconciler implements controller.Reconciler -var _ controller.Reconciler = (*reconcilerImpl)(nil) - -// Check that our generated Reconciler is always LeaderAware. -var _ reconciler.LeaderAware = (*reconcilerImpl)(nil) - -func NewReconciler(ctx context.Context, logger *zap.SugaredLogger, client versioned.Interface, lister eventsv1alpha1.CloudAuditLogsSourceLister, recorder record.EventRecorder, r Interface, options ...controller.Options) controller.Reconciler { - // Check the options function input. It should be 0 or 1. - if len(options) > 1 { - logger.Fatalf("up to one options struct is supported, found %d", len(options)) - } - - // Fail fast when users inadvertently implement the other LeaderAware interface. - // For the typed reconcilers, Promote shouldn't take any arguments. - if _, ok := r.(reconciler.LeaderAware); ok { - logger.Fatalf("%T implements the incorrect LeaderAware interface. Promote() should not take an argument as genreconciler handles the enqueuing automatically.", r) - } - // TODO: Consider validating when folks implement ReadOnlyFinalizer, but not Finalizer. - - rec := &reconcilerImpl{ - LeaderAwareFuncs: reconciler.LeaderAwareFuncs{ - PromoteFunc: func(bkt reconciler.Bucket, enq func(reconciler.Bucket, types.NamespacedName)) error { - all, err := lister.List(labels.Everything()) - if err != nil { - return err - } - for _, elt := range all { - // TODO: Consider letting users specify a filter in options. - enq(bkt, types.NamespacedName{ - Namespace: elt.GetNamespace(), - Name: elt.GetName(), - }) - } - return nil - }, - }, - Client: client, - Lister: lister, - Recorder: recorder, - reconciler: r, - finalizerName: defaultFinalizerName, - } - - for _, opts := range options { - if opts.ConfigStore != nil { - rec.configStore = opts.ConfigStore - } - if opts.FinalizerName != "" { - rec.finalizerName = opts.FinalizerName - } - } - - return rec -} - -// Reconcile implements controller.Reconciler -func (r *reconcilerImpl) Reconcile(ctx context.Context, key string) error { - logger := logging.FromContext(ctx) - - // Convert the namespace/name string into a distinct namespace and name - namespace, name, err := cache.SplitMetaNamespaceKey(key) - if err != nil { - logger.Errorf("invalid resource key: %s", key) - return nil - } - // Establish whether we are the leader for use below. - isLeader := r.IsLeaderFor(types.NamespacedName{ - Namespace: namespace, - Name: name, - }) - roi, isROI := r.reconciler.(ReadOnlyInterface) - rof, isROF := r.reconciler.(ReadOnlyFinalizer) - if !isLeader && !isROI && !isROF { - // If we are not the leader, and we don't implement either ReadOnly - // interface, then take a fast-path out. - return nil - } - - // If configStore is set, attach the frozen configuration to the context. - if r.configStore != nil { - ctx = r.configStore.ToContext(ctx) - } - - // Add the recorder to context. - ctx = controller.WithEventRecorder(ctx, r.Recorder) - - // Get the resource with this namespace/name. - - getter := r.Lister.CloudAuditLogsSources(namespace) - - original, err := getter.Get(name) - - if errors.IsNotFound(err) { - // The resource may no longer exist, in which case we stop processing. - logger.Debugf("resource %q no longer exists", key) - return nil - } else if err != nil { - return err - } - - // Don't modify the informers copy. - resource := original.DeepCopy() - - var reconcileEvent reconciler.Event - if resource.GetDeletionTimestamp().IsZero() { - if isLeader { - // Append the target method to the logger. - logger = logger.With(zap.String("targetMethod", "ReconcileKind")) - - // Set and update the finalizer on resource if r.reconciler - // implements Finalizer. - if resource, err = r.setFinalizerIfFinalizer(ctx, resource); err != nil { - return fmt.Errorf("failed to set finalizers: %w", err) - } - - // Reconcile this copy of the resource and then write back any status - // updates regardless of whether the reconciliation errored out. - reconcileEvent = r.reconciler.ReconcileKind(ctx, resource) - - } else if isROI { - // Append the target method to the logger. - logger = logger.With(zap.String("targetMethod", "ObserveKind")) - - // Observe any changes to this resource, since we are not the leader. - reconcileEvent = roi.ObserveKind(ctx, resource) - } - } else if fin, ok := r.reconciler.(Finalizer); isLeader && ok { - // Append the target method to the logger. - logger = logger.With(zap.String("targetMethod", "FinalizeKind")) - - // For finalizing reconcilers, if this resource being marked for deletion - // and reconciled cleanly (nil or normal event), remove the finalizer. - reconcileEvent = fin.FinalizeKind(ctx, resource) - if resource, err = r.clearFinalizer(ctx, resource, reconcileEvent); err != nil { - return fmt.Errorf("failed to clear finalizers: %w", err) - } - } else if !isLeader && isROF { - // Append the target method to the logger. - logger = logger.With(zap.String("targetMethod", "ObserveFinalizeKind")) - - // For finalizing reconcilers, just observe when we aren't the leader. - reconcileEvent = rof.ObserveFinalizeKind(ctx, resource) - } - - // Synchronize the status. - if equality.Semantic.DeepEqual(original.Status, resource.Status) { - // If we didn't change anything then don't call updateStatus. - // This is important because the copy we loaded from the injectionInformer's - // cache may be stale and we don't want to overwrite a prior update - // to status with this stale state. - } else if !isLeader { - logger.Warn("Saw status changes when we aren't the leader!") - // TODO: Consider logging the diff at Debug? - } else if err = r.updateStatus(original, resource); err != nil { - logger.Warnw("Failed to update resource status", zap.Error(err)) - r.Recorder.Eventf(resource, v1.EventTypeWarning, "UpdateFailed", - "Failed to update status for %q: %v", resource.Name, err) - return err - } - - // Report the reconciler event, if any. - if reconcileEvent != nil { - var event *reconciler.ReconcilerEvent - if reconciler.EventAs(reconcileEvent, &event) { - logger.Infow("Returned an event", zap.Any("event", reconcileEvent)) - r.Recorder.Eventf(resource, event.EventType, event.Reason, event.Format, event.Args...) - - // the event was wrapped inside an error, consider the reconciliation as failed - if _, isEvent := reconcileEvent.(*reconciler.ReconcilerEvent); !isEvent { - return reconcileEvent - } - return nil - } - - logger.Errorw("Returned an error", zap.Error(reconcileEvent)) - r.Recorder.Event(resource, v1.EventTypeWarning, "InternalError", reconcileEvent.Error()) - return reconcileEvent - } - - return nil -} - -func (r *reconcilerImpl) updateStatus(existing *v1alpha1.CloudAuditLogsSource, desired *v1alpha1.CloudAuditLogsSource) error { - existing = existing.DeepCopy() - return reconciler.RetryUpdateConflicts(func(attempts int) (err error) { - // The first iteration tries to use the injectionInformer's state, subsequent attempts fetch the latest state via API. - if attempts > 0 { - - getter := r.Client.EventsV1alpha1().CloudAuditLogsSources(desired.Namespace) - - existing, err = getter.Get(desired.Name, metav1.GetOptions{}) - if err != nil { - return err - } - } - - // If there's nothing to update, just return. - if reflect.DeepEqual(existing.Status, desired.Status) { - return nil - } - - existing.Status = desired.Status - - updater := r.Client.EventsV1alpha1().CloudAuditLogsSources(existing.Namespace) - - _, err = updater.UpdateStatus(existing) - return err - }) -} - -// updateFinalizersFiltered will update the Finalizers of the resource. -// TODO: this method could be generic and sync all finalizers. For now it only -// updates defaultFinalizerName or its override. -func (r *reconcilerImpl) updateFinalizersFiltered(ctx context.Context, resource *v1alpha1.CloudAuditLogsSource) (*v1alpha1.CloudAuditLogsSource, error) { - - getter := r.Lister.CloudAuditLogsSources(resource.Namespace) - - actual, err := getter.Get(resource.Name) - if err != nil { - return resource, err - } - - // Don't modify the informers copy. - existing := actual.DeepCopy() - - var finalizers []string - - // If there's nothing to update, just return. - existingFinalizers := sets.NewString(existing.Finalizers...) - desiredFinalizers := sets.NewString(resource.Finalizers...) - - if desiredFinalizers.Has(r.finalizerName) { - if existingFinalizers.Has(r.finalizerName) { - // Nothing to do. - return resource, nil - } - // Add the finalizer. - finalizers = append(existing.Finalizers, r.finalizerName) - } else { - if !existingFinalizers.Has(r.finalizerName) { - // Nothing to do. - return resource, nil - } - // Remove the finalizer. - existingFinalizers.Delete(r.finalizerName) - finalizers = existingFinalizers.List() - } - - mergePatch := map[string]interface{}{ - "metadata": map[string]interface{}{ - "finalizers": finalizers, - "resourceVersion": existing.ResourceVersion, - }, - } - - patch, err := json.Marshal(mergePatch) - if err != nil { - return resource, err - } - - patcher := r.Client.EventsV1alpha1().CloudAuditLogsSources(resource.Namespace) - - resourceName := resource.Name - resource, err = patcher.Patch(resourceName, types.MergePatchType, patch) - if err != nil { - r.Recorder.Eventf(resource, v1.EventTypeWarning, "FinalizerUpdateFailed", - "Failed to update finalizers for %q: %v", resourceName, err) - } else { - r.Recorder.Eventf(resource, v1.EventTypeNormal, "FinalizerUpdate", - "Updated %q finalizers", resource.GetName()) - } - return resource, err -} - -func (r *reconcilerImpl) setFinalizerIfFinalizer(ctx context.Context, resource *v1alpha1.CloudAuditLogsSource) (*v1alpha1.CloudAuditLogsSource, error) { - if _, ok := r.reconciler.(Finalizer); !ok { - return resource, nil - } - - finalizers := sets.NewString(resource.Finalizers...) - - // If this resource is not being deleted, mark the finalizer. - if resource.GetDeletionTimestamp().IsZero() { - finalizers.Insert(r.finalizerName) - } - - resource.Finalizers = finalizers.List() - - // Synchronize the finalizers filtered by r.finalizerName. - return r.updateFinalizersFiltered(ctx, resource) -} - -func (r *reconcilerImpl) clearFinalizer(ctx context.Context, resource *v1alpha1.CloudAuditLogsSource, reconcileEvent reconciler.Event) (*v1alpha1.CloudAuditLogsSource, error) { - if _, ok := r.reconciler.(Finalizer); !ok { - return resource, nil - } - if resource.GetDeletionTimestamp().IsZero() { - return resource, nil - } - - finalizers := sets.NewString(resource.Finalizers...) - - if reconcileEvent != nil { - var event *reconciler.ReconcilerEvent - if reconciler.EventAs(reconcileEvent, &event) { - if event.EventType == v1.EventTypeNormal { - finalizers.Delete(r.finalizerName) - } - } - } else { - finalizers.Delete(r.finalizerName) - } - - resource.Finalizers = finalizers.List() - - // Synchronize the finalizers filtered by r.finalizerName. - return r.updateFinalizersFiltered(ctx, resource) -} diff --git a/pkg/client/injection/reconciler/events/v1alpha1/cloudauditlogssource/stub/controller.go b/pkg/client/injection/reconciler/events/v1alpha1/cloudauditlogssource/stub/controller.go deleted file mode 100644 index e4c292ddea..0000000000 --- a/pkg/client/injection/reconciler/events/v1alpha1/cloudauditlogssource/stub/controller.go +++ /dev/null @@ -1,54 +0,0 @@ -/* -Copyright 2020 Google LLC - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -// Code generated by injection-gen. DO NOT EDIT. - -package cloudauditlogssource - -import ( - context "context" - - cloudauditlogssource "github.com/google/knative-gcp/pkg/client/injection/informers/events/v1alpha1/cloudauditlogssource" - v1alpha1cloudauditlogssource "github.com/google/knative-gcp/pkg/client/injection/reconciler/events/v1alpha1/cloudauditlogssource" - configmap "knative.dev/pkg/configmap" - controller "knative.dev/pkg/controller" - logging "knative.dev/pkg/logging" -) - -// TODO: PLEASE COPY AND MODIFY THIS FILE AS A STARTING POINT - -// NewController creates a Reconciler for CloudAuditLogsSource and returns the result of NewImpl. -func NewController( - ctx context.Context, - cmw configmap.Watcher, -) *controller.Impl { - logger := logging.FromContext(ctx) - - cloudauditlogssourceInformer := cloudauditlogssource.Get(ctx) - - // TODO: setup additional informers here. - - r := &Reconciler{} - impl := v1alpha1cloudauditlogssource.NewImpl(ctx, r) - - logger.Info("Setting up event handlers.") - - cloudauditlogssourceInformer.Informer().AddEventHandler(controller.HandleAll(impl.Enqueue)) - - // TODO: add additional informer event handlers here. - - return impl -} diff --git a/pkg/client/injection/reconciler/events/v1alpha1/cloudauditlogssource/stub/reconciler.go b/pkg/client/injection/reconciler/events/v1alpha1/cloudauditlogssource/stub/reconciler.go deleted file mode 100644 index 4ad50dc87f..0000000000 --- a/pkg/client/injection/reconciler/events/v1alpha1/cloudauditlogssource/stub/reconciler.go +++ /dev/null @@ -1,87 +0,0 @@ -/* -Copyright 2020 Google LLC - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -// Code generated by injection-gen. DO NOT EDIT. - -package cloudauditlogssource - -import ( - context "context" - - v1alpha1 "github.com/google/knative-gcp/pkg/apis/events/v1alpha1" - cloudauditlogssource "github.com/google/knative-gcp/pkg/client/injection/reconciler/events/v1alpha1/cloudauditlogssource" - v1 "k8s.io/api/core/v1" - reconciler "knative.dev/pkg/reconciler" -) - -// TODO: PLEASE COPY AND MODIFY THIS FILE AS A STARTING POINT - -// newReconciledNormal makes a new reconciler event with event type Normal, and -// reason CloudAuditLogsSourceReconciled. -func newReconciledNormal(namespace, name string) reconciler.Event { - return reconciler.NewEvent(v1.EventTypeNormal, "CloudAuditLogsSourceReconciled", "CloudAuditLogsSource reconciled: \"%s/%s\"", namespace, name) -} - -// Reconciler implements controller.Reconciler for CloudAuditLogsSource resources. -type Reconciler struct { - // TODO: add additional requirements here. -} - -// Check that our Reconciler implements Interface -var _ cloudauditlogssource.Interface = (*Reconciler)(nil) - -// Optionally check that our Reconciler implements Finalizer -//var _ cloudauditlogssource.Finalizer = (*Reconciler)(nil) - -// Optionally check that our Reconciler implements ReadOnlyInterface -// Implement this to observe resources even when we are not the leader. -//var _ cloudauditlogssource.ReadOnlyInterface = (*Reconciler)(nil) - -// Optionally check that our Reconciler implements ReadOnlyFinalizer -// Implement this to observe tombstoned resources even when we are not -// the leader (best effort). -//var _ cloudauditlogssource.ReadOnlyFinalizer = (*Reconciler)(nil) - -// ReconcileKind implements Interface.ReconcileKind. -func (r *Reconciler) ReconcileKind(ctx context.Context, o *v1alpha1.CloudAuditLogsSource) reconciler.Event { - // TODO: use this if the resource implements InitializeConditions. - // o.Status.InitializeConditions() - - // TODO: add custom reconciliation logic here. - - // TODO: use this if the object has .status.ObservedGeneration. - // o.Status.ObservedGeneration = o.Generation - return newReconciledNormal(o.Namespace, o.Name) -} - -// Optionally, use FinalizeKind to add finalizers. FinalizeKind will be called -// when the resource is deleted. -//func (r *Reconciler) FinalizeKind(ctx context.Context, o *v1alpha1.CloudAuditLogsSource) reconciler.Event { -// // TODO: add custom finalization logic here. -// return nil -//} - -// Optionally, use ObserveKind to observe the resource when we are not the leader. -// func (r *Reconciler) ObserveKind(ctx context.Context, o *v1alpha1.CloudAuditLogsSource) reconciler.Event { -// // TODO: add custom observation logic here. -// return nil -// } - -// Optionally, use ObserveFinalizeKind to observe resources being finalized when we are no the leader. -//func (r *Reconciler) ObserveFinalizeKind(ctx context.Context, o *v1alpha1.CloudAuditLogsSource) reconciler.Event { -// // TODO: add custom observation logic here. -// return nil -//} diff --git a/pkg/client/injection/reconciler/events/v1alpha1/cloudbuildsource/controller.go b/pkg/client/injection/reconciler/events/v1alpha1/cloudbuildsource/controller.go deleted file mode 100644 index 6fce4038c2..0000000000 --- a/pkg/client/injection/reconciler/events/v1alpha1/cloudbuildsource/controller.go +++ /dev/null @@ -1,139 +0,0 @@ -/* -Copyright 2020 Google LLC - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -// Code generated by injection-gen. DO NOT EDIT. - -package cloudbuildsource - -import ( - context "context" - fmt "fmt" - reflect "reflect" - strings "strings" - - versionedscheme "github.com/google/knative-gcp/pkg/client/clientset/versioned/scheme" - client "github.com/google/knative-gcp/pkg/client/injection/client" - cloudbuildsource "github.com/google/knative-gcp/pkg/client/injection/informers/events/v1alpha1/cloudbuildsource" - corev1 "k8s.io/api/core/v1" - labels "k8s.io/apimachinery/pkg/labels" - types "k8s.io/apimachinery/pkg/types" - watch "k8s.io/apimachinery/pkg/watch" - scheme "k8s.io/client-go/kubernetes/scheme" - v1 "k8s.io/client-go/kubernetes/typed/core/v1" - record "k8s.io/client-go/tools/record" - kubeclient "knative.dev/pkg/client/injection/kube/client" - controller "knative.dev/pkg/controller" - logging "knative.dev/pkg/logging" - reconciler "knative.dev/pkg/reconciler" -) - -const ( - defaultControllerAgentName = "cloudbuildsource-controller" - defaultFinalizerName = "cloudbuildsources.events.cloud.google.com" -) - -// NewImpl returns a controller.Impl that handles queuing and feeding work from -// the queue through an implementation of controller.Reconciler, delegating to -// the provided Interface and optional Finalizer methods. OptionsFn is used to return -// controller.Options to be used but the internal reconciler. -func NewImpl(ctx context.Context, r Interface, optionsFns ...controller.OptionsFn) *controller.Impl { - logger := logging.FromContext(ctx) - - // Check the options function input. It should be 0 or 1. - if len(optionsFns) > 1 { - logger.Fatalf("up to one options function is supported, found %d", len(optionsFns)) - } - - cloudbuildsourceInformer := cloudbuildsource.Get(ctx) - - lister := cloudbuildsourceInformer.Lister() - - rec := &reconcilerImpl{ - LeaderAwareFuncs: reconciler.LeaderAwareFuncs{ - PromoteFunc: func(bkt reconciler.Bucket, enq func(reconciler.Bucket, types.NamespacedName)) error { - all, err := lister.List(labels.Everything()) - if err != nil { - return err - } - for _, elt := range all { - // TODO: Consider letting users specify a filter in options. - enq(bkt, types.NamespacedName{ - Namespace: elt.GetNamespace(), - Name: elt.GetName(), - }) - } - return nil - }, - }, - Client: client.Get(ctx), - Lister: lister, - reconciler: r, - finalizerName: defaultFinalizerName, - } - - t := reflect.TypeOf(r).Elem() - queueName := fmt.Sprintf("%s.%s", strings.ReplaceAll(t.PkgPath(), "/", "-"), t.Name()) - - impl := controller.NewImpl(rec, logger, queueName) - agentName := defaultControllerAgentName - - // Pass impl to the options. Save any optional results. - for _, fn := range optionsFns { - opts := fn(impl) - if opts.ConfigStore != nil { - rec.configStore = opts.ConfigStore - } - if opts.FinalizerName != "" { - rec.finalizerName = opts.FinalizerName - } - if opts.AgentName != "" { - agentName = opts.AgentName - } - } - - rec.Recorder = createRecorder(ctx, agentName) - - return impl -} - -func createRecorder(ctx context.Context, agentName string) record.EventRecorder { - logger := logging.FromContext(ctx) - - recorder := controller.GetEventRecorder(ctx) - if recorder == nil { - // Create event broadcaster - logger.Debug("Creating event broadcaster") - eventBroadcaster := record.NewBroadcaster() - watches := []watch.Interface{ - eventBroadcaster.StartLogging(logger.Named("event-broadcaster").Infof), - eventBroadcaster.StartRecordingToSink( - &v1.EventSinkImpl{Interface: kubeclient.Get(ctx).CoreV1().Events("")}), - } - recorder = eventBroadcaster.NewRecorder(scheme.Scheme, corev1.EventSource{Component: agentName}) - go func() { - <-ctx.Done() - for _, w := range watches { - w.Stop() - } - }() - } - - return recorder -} - -func init() { - versionedscheme.AddToScheme(scheme.Scheme) -} diff --git a/pkg/client/injection/reconciler/events/v1alpha1/cloudbuildsource/reconciler.go b/pkg/client/injection/reconciler/events/v1alpha1/cloudbuildsource/reconciler.go deleted file mode 100644 index 9bb2603eee..0000000000 --- a/pkg/client/injection/reconciler/events/v1alpha1/cloudbuildsource/reconciler.go +++ /dev/null @@ -1,430 +0,0 @@ -/* -Copyright 2020 Google LLC - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -// Code generated by injection-gen. DO NOT EDIT. - -package cloudbuildsource - -import ( - context "context" - json "encoding/json" - fmt "fmt" - reflect "reflect" - - v1alpha1 "github.com/google/knative-gcp/pkg/apis/events/v1alpha1" - versioned "github.com/google/knative-gcp/pkg/client/clientset/versioned" - eventsv1alpha1 "github.com/google/knative-gcp/pkg/client/listers/events/v1alpha1" - zap "go.uber.org/zap" - v1 "k8s.io/api/core/v1" - equality "k8s.io/apimachinery/pkg/api/equality" - errors "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - labels "k8s.io/apimachinery/pkg/labels" - types "k8s.io/apimachinery/pkg/types" - sets "k8s.io/apimachinery/pkg/util/sets" - cache "k8s.io/client-go/tools/cache" - record "k8s.io/client-go/tools/record" - controller "knative.dev/pkg/controller" - logging "knative.dev/pkg/logging" - reconciler "knative.dev/pkg/reconciler" -) - -// Interface defines the strongly typed interfaces to be implemented by a -// controller reconciling v1alpha1.CloudBuildSource. -type Interface interface { - // ReconcileKind implements custom logic to reconcile v1alpha1.CloudBuildSource. Any changes - // to the objects .Status or .Finalizers will be propagated to the stored - // object. It is recommended that implementors do not call any update calls - // for the Kind inside of ReconcileKind, it is the responsibility of the calling - // controller to propagate those properties. The resource passed to ReconcileKind - // will always have an empty deletion timestamp. - ReconcileKind(ctx context.Context, o *v1alpha1.CloudBuildSource) reconciler.Event -} - -// Finalizer defines the strongly typed interfaces to be implemented by a -// controller finalizing v1alpha1.CloudBuildSource. -type Finalizer interface { - // FinalizeKind implements custom logic to finalize v1alpha1.CloudBuildSource. Any changes - // to the objects .Status or .Finalizers will be ignored. Returning a nil or - // Normal type reconciler.Event will allow the finalizer to be deleted on - // the resource. The resource passed to FinalizeKind will always have a set - // deletion timestamp. - FinalizeKind(ctx context.Context, o *v1alpha1.CloudBuildSource) reconciler.Event -} - -// ReadOnlyInterface defines the strongly typed interfaces to be implemented by a -// controller reconciling v1alpha1.CloudBuildSource if they want to process resources for which -// they are not the leader. -type ReadOnlyInterface interface { - // ObserveKind implements logic to observe v1alpha1.CloudBuildSource. - // This method should not write to the API. - ObserveKind(ctx context.Context, o *v1alpha1.CloudBuildSource) reconciler.Event -} - -// ReadOnlyFinalizer defines the strongly typed interfaces to be implemented by a -// controller finalizing v1alpha1.CloudBuildSource if they want to process tombstoned resources -// even when they are not the leader. Due to the nature of how finalizers are handled -// there are no guarantees that this will be called. -type ReadOnlyFinalizer interface { - // ObserveFinalizeKind implements custom logic to observe the final state of v1alpha1.CloudBuildSource. - // This method should not write to the API. - ObserveFinalizeKind(ctx context.Context, o *v1alpha1.CloudBuildSource) reconciler.Event -} - -// reconcilerImpl implements controller.Reconciler for v1alpha1.CloudBuildSource resources. -type reconcilerImpl struct { - // LeaderAwareFuncs is inlined to help us implement reconciler.LeaderAware - reconciler.LeaderAwareFuncs - - // Client is used to write back status updates. - Client versioned.Interface - - // Listers index properties about resources - Lister eventsv1alpha1.CloudBuildSourceLister - - // Recorder is an event recorder for recording Event resources to the - // Kubernetes API. - Recorder record.EventRecorder - - // configStore allows for decorating a context with config maps. - // +optional - configStore reconciler.ConfigStore - - // reconciler is the implementation of the business logic of the resource. - reconciler Interface - - // finalizerName is the name of the finalizer to reconcile. - finalizerName string -} - -// Check that our Reconciler implements controller.Reconciler -var _ controller.Reconciler = (*reconcilerImpl)(nil) - -// Check that our generated Reconciler is always LeaderAware. -var _ reconciler.LeaderAware = (*reconcilerImpl)(nil) - -func NewReconciler(ctx context.Context, logger *zap.SugaredLogger, client versioned.Interface, lister eventsv1alpha1.CloudBuildSourceLister, recorder record.EventRecorder, r Interface, options ...controller.Options) controller.Reconciler { - // Check the options function input. It should be 0 or 1. - if len(options) > 1 { - logger.Fatalf("up to one options struct is supported, found %d", len(options)) - } - - // Fail fast when users inadvertently implement the other LeaderAware interface. - // For the typed reconcilers, Promote shouldn't take any arguments. - if _, ok := r.(reconciler.LeaderAware); ok { - logger.Fatalf("%T implements the incorrect LeaderAware interface. Promote() should not take an argument as genreconciler handles the enqueuing automatically.", r) - } - // TODO: Consider validating when folks implement ReadOnlyFinalizer, but not Finalizer. - - rec := &reconcilerImpl{ - LeaderAwareFuncs: reconciler.LeaderAwareFuncs{ - PromoteFunc: func(bkt reconciler.Bucket, enq func(reconciler.Bucket, types.NamespacedName)) error { - all, err := lister.List(labels.Everything()) - if err != nil { - return err - } - for _, elt := range all { - // TODO: Consider letting users specify a filter in options. - enq(bkt, types.NamespacedName{ - Namespace: elt.GetNamespace(), - Name: elt.GetName(), - }) - } - return nil - }, - }, - Client: client, - Lister: lister, - Recorder: recorder, - reconciler: r, - finalizerName: defaultFinalizerName, - } - - for _, opts := range options { - if opts.ConfigStore != nil { - rec.configStore = opts.ConfigStore - } - if opts.FinalizerName != "" { - rec.finalizerName = opts.FinalizerName - } - } - - return rec -} - -// Reconcile implements controller.Reconciler -func (r *reconcilerImpl) Reconcile(ctx context.Context, key string) error { - logger := logging.FromContext(ctx) - - // Convert the namespace/name string into a distinct namespace and name - namespace, name, err := cache.SplitMetaNamespaceKey(key) - if err != nil { - logger.Errorf("invalid resource key: %s", key) - return nil - } - // Establish whether we are the leader for use below. - isLeader := r.IsLeaderFor(types.NamespacedName{ - Namespace: namespace, - Name: name, - }) - roi, isROI := r.reconciler.(ReadOnlyInterface) - rof, isROF := r.reconciler.(ReadOnlyFinalizer) - if !isLeader && !isROI && !isROF { - // If we are not the leader, and we don't implement either ReadOnly - // interface, then take a fast-path out. - return nil - } - - // If configStore is set, attach the frozen configuration to the context. - if r.configStore != nil { - ctx = r.configStore.ToContext(ctx) - } - - // Add the recorder to context. - ctx = controller.WithEventRecorder(ctx, r.Recorder) - - // Get the resource with this namespace/name. - - getter := r.Lister.CloudBuildSources(namespace) - - original, err := getter.Get(name) - - if errors.IsNotFound(err) { - // The resource may no longer exist, in which case we stop processing. - logger.Debugf("resource %q no longer exists", key) - return nil - } else if err != nil { - return err - } - - // Don't modify the informers copy. - resource := original.DeepCopy() - - var reconcileEvent reconciler.Event - if resource.GetDeletionTimestamp().IsZero() { - if isLeader { - // Append the target method to the logger. - logger = logger.With(zap.String("targetMethod", "ReconcileKind")) - - // Set and update the finalizer on resource if r.reconciler - // implements Finalizer. - if resource, err = r.setFinalizerIfFinalizer(ctx, resource); err != nil { - return fmt.Errorf("failed to set finalizers: %w", err) - } - - // Reconcile this copy of the resource and then write back any status - // updates regardless of whether the reconciliation errored out. - reconcileEvent = r.reconciler.ReconcileKind(ctx, resource) - - } else if isROI { - // Append the target method to the logger. - logger = logger.With(zap.String("targetMethod", "ObserveKind")) - - // Observe any changes to this resource, since we are not the leader. - reconcileEvent = roi.ObserveKind(ctx, resource) - } - } else if fin, ok := r.reconciler.(Finalizer); isLeader && ok { - // Append the target method to the logger. - logger = logger.With(zap.String("targetMethod", "FinalizeKind")) - - // For finalizing reconcilers, if this resource being marked for deletion - // and reconciled cleanly (nil or normal event), remove the finalizer. - reconcileEvent = fin.FinalizeKind(ctx, resource) - if resource, err = r.clearFinalizer(ctx, resource, reconcileEvent); err != nil { - return fmt.Errorf("failed to clear finalizers: %w", err) - } - } else if !isLeader && isROF { - // Append the target method to the logger. - logger = logger.With(zap.String("targetMethod", "ObserveFinalizeKind")) - - // For finalizing reconcilers, just observe when we aren't the leader. - reconcileEvent = rof.ObserveFinalizeKind(ctx, resource) - } - - // Synchronize the status. - if equality.Semantic.DeepEqual(original.Status, resource.Status) { - // If we didn't change anything then don't call updateStatus. - // This is important because the copy we loaded from the injectionInformer's - // cache may be stale and we don't want to overwrite a prior update - // to status with this stale state. - } else if !isLeader { - logger.Warn("Saw status changes when we aren't the leader!") - // TODO: Consider logging the diff at Debug? - } else if err = r.updateStatus(original, resource); err != nil { - logger.Warnw("Failed to update resource status", zap.Error(err)) - r.Recorder.Eventf(resource, v1.EventTypeWarning, "UpdateFailed", - "Failed to update status for %q: %v", resource.Name, err) - return err - } - - // Report the reconciler event, if any. - if reconcileEvent != nil { - var event *reconciler.ReconcilerEvent - if reconciler.EventAs(reconcileEvent, &event) { - logger.Infow("Returned an event", zap.Any("event", reconcileEvent)) - r.Recorder.Eventf(resource, event.EventType, event.Reason, event.Format, event.Args...) - - // the event was wrapped inside an error, consider the reconciliation as failed - if _, isEvent := reconcileEvent.(*reconciler.ReconcilerEvent); !isEvent { - return reconcileEvent - } - return nil - } - - logger.Errorw("Returned an error", zap.Error(reconcileEvent)) - r.Recorder.Event(resource, v1.EventTypeWarning, "InternalError", reconcileEvent.Error()) - return reconcileEvent - } - - return nil -} - -func (r *reconcilerImpl) updateStatus(existing *v1alpha1.CloudBuildSource, desired *v1alpha1.CloudBuildSource) error { - existing = existing.DeepCopy() - return reconciler.RetryUpdateConflicts(func(attempts int) (err error) { - // The first iteration tries to use the injectionInformer's state, subsequent attempts fetch the latest state via API. - if attempts > 0 { - - getter := r.Client.EventsV1alpha1().CloudBuildSources(desired.Namespace) - - existing, err = getter.Get(desired.Name, metav1.GetOptions{}) - if err != nil { - return err - } - } - - // If there's nothing to update, just return. - if reflect.DeepEqual(existing.Status, desired.Status) { - return nil - } - - existing.Status = desired.Status - - updater := r.Client.EventsV1alpha1().CloudBuildSources(existing.Namespace) - - _, err = updater.UpdateStatus(existing) - return err - }) -} - -// updateFinalizersFiltered will update the Finalizers of the resource. -// TODO: this method could be generic and sync all finalizers. For now it only -// updates defaultFinalizerName or its override. -func (r *reconcilerImpl) updateFinalizersFiltered(ctx context.Context, resource *v1alpha1.CloudBuildSource) (*v1alpha1.CloudBuildSource, error) { - - getter := r.Lister.CloudBuildSources(resource.Namespace) - - actual, err := getter.Get(resource.Name) - if err != nil { - return resource, err - } - - // Don't modify the informers copy. - existing := actual.DeepCopy() - - var finalizers []string - - // If there's nothing to update, just return. - existingFinalizers := sets.NewString(existing.Finalizers...) - desiredFinalizers := sets.NewString(resource.Finalizers...) - - if desiredFinalizers.Has(r.finalizerName) { - if existingFinalizers.Has(r.finalizerName) { - // Nothing to do. - return resource, nil - } - // Add the finalizer. - finalizers = append(existing.Finalizers, r.finalizerName) - } else { - if !existingFinalizers.Has(r.finalizerName) { - // Nothing to do. - return resource, nil - } - // Remove the finalizer. - existingFinalizers.Delete(r.finalizerName) - finalizers = existingFinalizers.List() - } - - mergePatch := map[string]interface{}{ - "metadata": map[string]interface{}{ - "finalizers": finalizers, - "resourceVersion": existing.ResourceVersion, - }, - } - - patch, err := json.Marshal(mergePatch) - if err != nil { - return resource, err - } - - patcher := r.Client.EventsV1alpha1().CloudBuildSources(resource.Namespace) - - resourceName := resource.Name - resource, err = patcher.Patch(resourceName, types.MergePatchType, patch) - if err != nil { - r.Recorder.Eventf(resource, v1.EventTypeWarning, "FinalizerUpdateFailed", - "Failed to update finalizers for %q: %v", resourceName, err) - } else { - r.Recorder.Eventf(resource, v1.EventTypeNormal, "FinalizerUpdate", - "Updated %q finalizers", resource.GetName()) - } - return resource, err -} - -func (r *reconcilerImpl) setFinalizerIfFinalizer(ctx context.Context, resource *v1alpha1.CloudBuildSource) (*v1alpha1.CloudBuildSource, error) { - if _, ok := r.reconciler.(Finalizer); !ok { - return resource, nil - } - - finalizers := sets.NewString(resource.Finalizers...) - - // If this resource is not being deleted, mark the finalizer. - if resource.GetDeletionTimestamp().IsZero() { - finalizers.Insert(r.finalizerName) - } - - resource.Finalizers = finalizers.List() - - // Synchronize the finalizers filtered by r.finalizerName. - return r.updateFinalizersFiltered(ctx, resource) -} - -func (r *reconcilerImpl) clearFinalizer(ctx context.Context, resource *v1alpha1.CloudBuildSource, reconcileEvent reconciler.Event) (*v1alpha1.CloudBuildSource, error) { - if _, ok := r.reconciler.(Finalizer); !ok { - return resource, nil - } - if resource.GetDeletionTimestamp().IsZero() { - return resource, nil - } - - finalizers := sets.NewString(resource.Finalizers...) - - if reconcileEvent != nil { - var event *reconciler.ReconcilerEvent - if reconciler.EventAs(reconcileEvent, &event) { - if event.EventType == v1.EventTypeNormal { - finalizers.Delete(r.finalizerName) - } - } - } else { - finalizers.Delete(r.finalizerName) - } - - resource.Finalizers = finalizers.List() - - // Synchronize the finalizers filtered by r.finalizerName. - return r.updateFinalizersFiltered(ctx, resource) -} diff --git a/pkg/client/injection/reconciler/events/v1alpha1/cloudbuildsource/stub/controller.go b/pkg/client/injection/reconciler/events/v1alpha1/cloudbuildsource/stub/controller.go deleted file mode 100644 index 224fa83c1d..0000000000 --- a/pkg/client/injection/reconciler/events/v1alpha1/cloudbuildsource/stub/controller.go +++ /dev/null @@ -1,54 +0,0 @@ -/* -Copyright 2020 Google LLC - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -// Code generated by injection-gen. DO NOT EDIT. - -package cloudbuildsource - -import ( - context "context" - - cloudbuildsource "github.com/google/knative-gcp/pkg/client/injection/informers/events/v1alpha1/cloudbuildsource" - v1alpha1cloudbuildsource "github.com/google/knative-gcp/pkg/client/injection/reconciler/events/v1alpha1/cloudbuildsource" - configmap "knative.dev/pkg/configmap" - controller "knative.dev/pkg/controller" - logging "knative.dev/pkg/logging" -) - -// TODO: PLEASE COPY AND MODIFY THIS FILE AS A STARTING POINT - -// NewController creates a Reconciler for CloudBuildSource and returns the result of NewImpl. -func NewController( - ctx context.Context, - cmw configmap.Watcher, -) *controller.Impl { - logger := logging.FromContext(ctx) - - cloudbuildsourceInformer := cloudbuildsource.Get(ctx) - - // TODO: setup additional informers here. - - r := &Reconciler{} - impl := v1alpha1cloudbuildsource.NewImpl(ctx, r) - - logger.Info("Setting up event handlers.") - - cloudbuildsourceInformer.Informer().AddEventHandler(controller.HandleAll(impl.Enqueue)) - - // TODO: add additional informer event handlers here. - - return impl -} diff --git a/pkg/client/injection/reconciler/events/v1alpha1/cloudbuildsource/stub/reconciler.go b/pkg/client/injection/reconciler/events/v1alpha1/cloudbuildsource/stub/reconciler.go deleted file mode 100644 index ca34968718..0000000000 --- a/pkg/client/injection/reconciler/events/v1alpha1/cloudbuildsource/stub/reconciler.go +++ /dev/null @@ -1,87 +0,0 @@ -/* -Copyright 2020 Google LLC - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -// Code generated by injection-gen. DO NOT EDIT. - -package cloudbuildsource - -import ( - context "context" - - v1alpha1 "github.com/google/knative-gcp/pkg/apis/events/v1alpha1" - cloudbuildsource "github.com/google/knative-gcp/pkg/client/injection/reconciler/events/v1alpha1/cloudbuildsource" - v1 "k8s.io/api/core/v1" - reconciler "knative.dev/pkg/reconciler" -) - -// TODO: PLEASE COPY AND MODIFY THIS FILE AS A STARTING POINT - -// newReconciledNormal makes a new reconciler event with event type Normal, and -// reason CloudBuildSourceReconciled. -func newReconciledNormal(namespace, name string) reconciler.Event { - return reconciler.NewEvent(v1.EventTypeNormal, "CloudBuildSourceReconciled", "CloudBuildSource reconciled: \"%s/%s\"", namespace, name) -} - -// Reconciler implements controller.Reconciler for CloudBuildSource resources. -type Reconciler struct { - // TODO: add additional requirements here. -} - -// Check that our Reconciler implements Interface -var _ cloudbuildsource.Interface = (*Reconciler)(nil) - -// Optionally check that our Reconciler implements Finalizer -//var _ cloudbuildsource.Finalizer = (*Reconciler)(nil) - -// Optionally check that our Reconciler implements ReadOnlyInterface -// Implement this to observe resources even when we are not the leader. -//var _ cloudbuildsource.ReadOnlyInterface = (*Reconciler)(nil) - -// Optionally check that our Reconciler implements ReadOnlyFinalizer -// Implement this to observe tombstoned resources even when we are not -// the leader (best effort). -//var _ cloudbuildsource.ReadOnlyFinalizer = (*Reconciler)(nil) - -// ReconcileKind implements Interface.ReconcileKind. -func (r *Reconciler) ReconcileKind(ctx context.Context, o *v1alpha1.CloudBuildSource) reconciler.Event { - // TODO: use this if the resource implements InitializeConditions. - // o.Status.InitializeConditions() - - // TODO: add custom reconciliation logic here. - - // TODO: use this if the object has .status.ObservedGeneration. - // o.Status.ObservedGeneration = o.Generation - return newReconciledNormal(o.Namespace, o.Name) -} - -// Optionally, use FinalizeKind to add finalizers. FinalizeKind will be called -// when the resource is deleted. -//func (r *Reconciler) FinalizeKind(ctx context.Context, o *v1alpha1.CloudBuildSource) reconciler.Event { -// // TODO: add custom finalization logic here. -// return nil -//} - -// Optionally, use ObserveKind to observe the resource when we are not the leader. -// func (r *Reconciler) ObserveKind(ctx context.Context, o *v1alpha1.CloudBuildSource) reconciler.Event { -// // TODO: add custom observation logic here. -// return nil -// } - -// Optionally, use ObserveFinalizeKind to observe resources being finalized when we are no the leader. -//func (r *Reconciler) ObserveFinalizeKind(ctx context.Context, o *v1alpha1.CloudBuildSource) reconciler.Event { -// // TODO: add custom observation logic here. -// return nil -//} diff --git a/pkg/client/injection/reconciler/events/v1alpha1/cloudpubsubsource/controller.go b/pkg/client/injection/reconciler/events/v1alpha1/cloudpubsubsource/controller.go deleted file mode 100644 index 1e5311d9b4..0000000000 --- a/pkg/client/injection/reconciler/events/v1alpha1/cloudpubsubsource/controller.go +++ /dev/null @@ -1,139 +0,0 @@ -/* -Copyright 2020 Google LLC - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -// Code generated by injection-gen. DO NOT EDIT. - -package cloudpubsubsource - -import ( - context "context" - fmt "fmt" - reflect "reflect" - strings "strings" - - versionedscheme "github.com/google/knative-gcp/pkg/client/clientset/versioned/scheme" - client "github.com/google/knative-gcp/pkg/client/injection/client" - cloudpubsubsource "github.com/google/knative-gcp/pkg/client/injection/informers/events/v1alpha1/cloudpubsubsource" - corev1 "k8s.io/api/core/v1" - labels "k8s.io/apimachinery/pkg/labels" - types "k8s.io/apimachinery/pkg/types" - watch "k8s.io/apimachinery/pkg/watch" - scheme "k8s.io/client-go/kubernetes/scheme" - v1 "k8s.io/client-go/kubernetes/typed/core/v1" - record "k8s.io/client-go/tools/record" - kubeclient "knative.dev/pkg/client/injection/kube/client" - controller "knative.dev/pkg/controller" - logging "knative.dev/pkg/logging" - reconciler "knative.dev/pkg/reconciler" -) - -const ( - defaultControllerAgentName = "cloudpubsubsource-controller" - defaultFinalizerName = "cloudpubsubsources.events.cloud.google.com" -) - -// NewImpl returns a controller.Impl that handles queuing and feeding work from -// the queue through an implementation of controller.Reconciler, delegating to -// the provided Interface and optional Finalizer methods. OptionsFn is used to return -// controller.Options to be used but the internal reconciler. -func NewImpl(ctx context.Context, r Interface, optionsFns ...controller.OptionsFn) *controller.Impl { - logger := logging.FromContext(ctx) - - // Check the options function input. It should be 0 or 1. - if len(optionsFns) > 1 { - logger.Fatalf("up to one options function is supported, found %d", len(optionsFns)) - } - - cloudpubsubsourceInformer := cloudpubsubsource.Get(ctx) - - lister := cloudpubsubsourceInformer.Lister() - - rec := &reconcilerImpl{ - LeaderAwareFuncs: reconciler.LeaderAwareFuncs{ - PromoteFunc: func(bkt reconciler.Bucket, enq func(reconciler.Bucket, types.NamespacedName)) error { - all, err := lister.List(labels.Everything()) - if err != nil { - return err - } - for _, elt := range all { - // TODO: Consider letting users specify a filter in options. - enq(bkt, types.NamespacedName{ - Namespace: elt.GetNamespace(), - Name: elt.GetName(), - }) - } - return nil - }, - }, - Client: client.Get(ctx), - Lister: lister, - reconciler: r, - finalizerName: defaultFinalizerName, - } - - t := reflect.TypeOf(r).Elem() - queueName := fmt.Sprintf("%s.%s", strings.ReplaceAll(t.PkgPath(), "/", "-"), t.Name()) - - impl := controller.NewImpl(rec, logger, queueName) - agentName := defaultControllerAgentName - - // Pass impl to the options. Save any optional results. - for _, fn := range optionsFns { - opts := fn(impl) - if opts.ConfigStore != nil { - rec.configStore = opts.ConfigStore - } - if opts.FinalizerName != "" { - rec.finalizerName = opts.FinalizerName - } - if opts.AgentName != "" { - agentName = opts.AgentName - } - } - - rec.Recorder = createRecorder(ctx, agentName) - - return impl -} - -func createRecorder(ctx context.Context, agentName string) record.EventRecorder { - logger := logging.FromContext(ctx) - - recorder := controller.GetEventRecorder(ctx) - if recorder == nil { - // Create event broadcaster - logger.Debug("Creating event broadcaster") - eventBroadcaster := record.NewBroadcaster() - watches := []watch.Interface{ - eventBroadcaster.StartLogging(logger.Named("event-broadcaster").Infof), - eventBroadcaster.StartRecordingToSink( - &v1.EventSinkImpl{Interface: kubeclient.Get(ctx).CoreV1().Events("")}), - } - recorder = eventBroadcaster.NewRecorder(scheme.Scheme, corev1.EventSource{Component: agentName}) - go func() { - <-ctx.Done() - for _, w := range watches { - w.Stop() - } - }() - } - - return recorder -} - -func init() { - versionedscheme.AddToScheme(scheme.Scheme) -} diff --git a/pkg/client/injection/reconciler/events/v1alpha1/cloudpubsubsource/reconciler.go b/pkg/client/injection/reconciler/events/v1alpha1/cloudpubsubsource/reconciler.go deleted file mode 100644 index af85bc269a..0000000000 --- a/pkg/client/injection/reconciler/events/v1alpha1/cloudpubsubsource/reconciler.go +++ /dev/null @@ -1,430 +0,0 @@ -/* -Copyright 2020 Google LLC - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -// Code generated by injection-gen. DO NOT EDIT. - -package cloudpubsubsource - -import ( - context "context" - json "encoding/json" - fmt "fmt" - reflect "reflect" - - v1alpha1 "github.com/google/knative-gcp/pkg/apis/events/v1alpha1" - versioned "github.com/google/knative-gcp/pkg/client/clientset/versioned" - eventsv1alpha1 "github.com/google/knative-gcp/pkg/client/listers/events/v1alpha1" - zap "go.uber.org/zap" - v1 "k8s.io/api/core/v1" - equality "k8s.io/apimachinery/pkg/api/equality" - errors "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - labels "k8s.io/apimachinery/pkg/labels" - types "k8s.io/apimachinery/pkg/types" - sets "k8s.io/apimachinery/pkg/util/sets" - cache "k8s.io/client-go/tools/cache" - record "k8s.io/client-go/tools/record" - controller "knative.dev/pkg/controller" - logging "knative.dev/pkg/logging" - reconciler "knative.dev/pkg/reconciler" -) - -// Interface defines the strongly typed interfaces to be implemented by a -// controller reconciling v1alpha1.CloudPubSubSource. -type Interface interface { - // ReconcileKind implements custom logic to reconcile v1alpha1.CloudPubSubSource. Any changes - // to the objects .Status or .Finalizers will be propagated to the stored - // object. It is recommended that implementors do not call any update calls - // for the Kind inside of ReconcileKind, it is the responsibility of the calling - // controller to propagate those properties. The resource passed to ReconcileKind - // will always have an empty deletion timestamp. - ReconcileKind(ctx context.Context, o *v1alpha1.CloudPubSubSource) reconciler.Event -} - -// Finalizer defines the strongly typed interfaces to be implemented by a -// controller finalizing v1alpha1.CloudPubSubSource. -type Finalizer interface { - // FinalizeKind implements custom logic to finalize v1alpha1.CloudPubSubSource. Any changes - // to the objects .Status or .Finalizers will be ignored. Returning a nil or - // Normal type reconciler.Event will allow the finalizer to be deleted on - // the resource. The resource passed to FinalizeKind will always have a set - // deletion timestamp. - FinalizeKind(ctx context.Context, o *v1alpha1.CloudPubSubSource) reconciler.Event -} - -// ReadOnlyInterface defines the strongly typed interfaces to be implemented by a -// controller reconciling v1alpha1.CloudPubSubSource if they want to process resources for which -// they are not the leader. -type ReadOnlyInterface interface { - // ObserveKind implements logic to observe v1alpha1.CloudPubSubSource. - // This method should not write to the API. - ObserveKind(ctx context.Context, o *v1alpha1.CloudPubSubSource) reconciler.Event -} - -// ReadOnlyFinalizer defines the strongly typed interfaces to be implemented by a -// controller finalizing v1alpha1.CloudPubSubSource if they want to process tombstoned resources -// even when they are not the leader. Due to the nature of how finalizers are handled -// there are no guarantees that this will be called. -type ReadOnlyFinalizer interface { - // ObserveFinalizeKind implements custom logic to observe the final state of v1alpha1.CloudPubSubSource. - // This method should not write to the API. - ObserveFinalizeKind(ctx context.Context, o *v1alpha1.CloudPubSubSource) reconciler.Event -} - -// reconcilerImpl implements controller.Reconciler for v1alpha1.CloudPubSubSource resources. -type reconcilerImpl struct { - // LeaderAwareFuncs is inlined to help us implement reconciler.LeaderAware - reconciler.LeaderAwareFuncs - - // Client is used to write back status updates. - Client versioned.Interface - - // Listers index properties about resources - Lister eventsv1alpha1.CloudPubSubSourceLister - - // Recorder is an event recorder for recording Event resources to the - // Kubernetes API. - Recorder record.EventRecorder - - // configStore allows for decorating a context with config maps. - // +optional - configStore reconciler.ConfigStore - - // reconciler is the implementation of the business logic of the resource. - reconciler Interface - - // finalizerName is the name of the finalizer to reconcile. - finalizerName string -} - -// Check that our Reconciler implements controller.Reconciler -var _ controller.Reconciler = (*reconcilerImpl)(nil) - -// Check that our generated Reconciler is always LeaderAware. -var _ reconciler.LeaderAware = (*reconcilerImpl)(nil) - -func NewReconciler(ctx context.Context, logger *zap.SugaredLogger, client versioned.Interface, lister eventsv1alpha1.CloudPubSubSourceLister, recorder record.EventRecorder, r Interface, options ...controller.Options) controller.Reconciler { - // Check the options function input. It should be 0 or 1. - if len(options) > 1 { - logger.Fatalf("up to one options struct is supported, found %d", len(options)) - } - - // Fail fast when users inadvertently implement the other LeaderAware interface. - // For the typed reconcilers, Promote shouldn't take any arguments. - if _, ok := r.(reconciler.LeaderAware); ok { - logger.Fatalf("%T implements the incorrect LeaderAware interface. Promote() should not take an argument as genreconciler handles the enqueuing automatically.", r) - } - // TODO: Consider validating when folks implement ReadOnlyFinalizer, but not Finalizer. - - rec := &reconcilerImpl{ - LeaderAwareFuncs: reconciler.LeaderAwareFuncs{ - PromoteFunc: func(bkt reconciler.Bucket, enq func(reconciler.Bucket, types.NamespacedName)) error { - all, err := lister.List(labels.Everything()) - if err != nil { - return err - } - for _, elt := range all { - // TODO: Consider letting users specify a filter in options. - enq(bkt, types.NamespacedName{ - Namespace: elt.GetNamespace(), - Name: elt.GetName(), - }) - } - return nil - }, - }, - Client: client, - Lister: lister, - Recorder: recorder, - reconciler: r, - finalizerName: defaultFinalizerName, - } - - for _, opts := range options { - if opts.ConfigStore != nil { - rec.configStore = opts.ConfigStore - } - if opts.FinalizerName != "" { - rec.finalizerName = opts.FinalizerName - } - } - - return rec -} - -// Reconcile implements controller.Reconciler -func (r *reconcilerImpl) Reconcile(ctx context.Context, key string) error { - logger := logging.FromContext(ctx) - - // Convert the namespace/name string into a distinct namespace and name - namespace, name, err := cache.SplitMetaNamespaceKey(key) - if err != nil { - logger.Errorf("invalid resource key: %s", key) - return nil - } - // Establish whether we are the leader for use below. - isLeader := r.IsLeaderFor(types.NamespacedName{ - Namespace: namespace, - Name: name, - }) - roi, isROI := r.reconciler.(ReadOnlyInterface) - rof, isROF := r.reconciler.(ReadOnlyFinalizer) - if !isLeader && !isROI && !isROF { - // If we are not the leader, and we don't implement either ReadOnly - // interface, then take a fast-path out. - return nil - } - - // If configStore is set, attach the frozen configuration to the context. - if r.configStore != nil { - ctx = r.configStore.ToContext(ctx) - } - - // Add the recorder to context. - ctx = controller.WithEventRecorder(ctx, r.Recorder) - - // Get the resource with this namespace/name. - - getter := r.Lister.CloudPubSubSources(namespace) - - original, err := getter.Get(name) - - if errors.IsNotFound(err) { - // The resource may no longer exist, in which case we stop processing. - logger.Debugf("resource %q no longer exists", key) - return nil - } else if err != nil { - return err - } - - // Don't modify the informers copy. - resource := original.DeepCopy() - - var reconcileEvent reconciler.Event - if resource.GetDeletionTimestamp().IsZero() { - if isLeader { - // Append the target method to the logger. - logger = logger.With(zap.String("targetMethod", "ReconcileKind")) - - // Set and update the finalizer on resource if r.reconciler - // implements Finalizer. - if resource, err = r.setFinalizerIfFinalizer(ctx, resource); err != nil { - return fmt.Errorf("failed to set finalizers: %w", err) - } - - // Reconcile this copy of the resource and then write back any status - // updates regardless of whether the reconciliation errored out. - reconcileEvent = r.reconciler.ReconcileKind(ctx, resource) - - } else if isROI { - // Append the target method to the logger. - logger = logger.With(zap.String("targetMethod", "ObserveKind")) - - // Observe any changes to this resource, since we are not the leader. - reconcileEvent = roi.ObserveKind(ctx, resource) - } - } else if fin, ok := r.reconciler.(Finalizer); isLeader && ok { - // Append the target method to the logger. - logger = logger.With(zap.String("targetMethod", "FinalizeKind")) - - // For finalizing reconcilers, if this resource being marked for deletion - // and reconciled cleanly (nil or normal event), remove the finalizer. - reconcileEvent = fin.FinalizeKind(ctx, resource) - if resource, err = r.clearFinalizer(ctx, resource, reconcileEvent); err != nil { - return fmt.Errorf("failed to clear finalizers: %w", err) - } - } else if !isLeader && isROF { - // Append the target method to the logger. - logger = logger.With(zap.String("targetMethod", "ObserveFinalizeKind")) - - // For finalizing reconcilers, just observe when we aren't the leader. - reconcileEvent = rof.ObserveFinalizeKind(ctx, resource) - } - - // Synchronize the status. - if equality.Semantic.DeepEqual(original.Status, resource.Status) { - // If we didn't change anything then don't call updateStatus. - // This is important because the copy we loaded from the injectionInformer's - // cache may be stale and we don't want to overwrite a prior update - // to status with this stale state. - } else if !isLeader { - logger.Warn("Saw status changes when we aren't the leader!") - // TODO: Consider logging the diff at Debug? - } else if err = r.updateStatus(original, resource); err != nil { - logger.Warnw("Failed to update resource status", zap.Error(err)) - r.Recorder.Eventf(resource, v1.EventTypeWarning, "UpdateFailed", - "Failed to update status for %q: %v", resource.Name, err) - return err - } - - // Report the reconciler event, if any. - if reconcileEvent != nil { - var event *reconciler.ReconcilerEvent - if reconciler.EventAs(reconcileEvent, &event) { - logger.Infow("Returned an event", zap.Any("event", reconcileEvent)) - r.Recorder.Eventf(resource, event.EventType, event.Reason, event.Format, event.Args...) - - // the event was wrapped inside an error, consider the reconciliation as failed - if _, isEvent := reconcileEvent.(*reconciler.ReconcilerEvent); !isEvent { - return reconcileEvent - } - return nil - } - - logger.Errorw("Returned an error", zap.Error(reconcileEvent)) - r.Recorder.Event(resource, v1.EventTypeWarning, "InternalError", reconcileEvent.Error()) - return reconcileEvent - } - - return nil -} - -func (r *reconcilerImpl) updateStatus(existing *v1alpha1.CloudPubSubSource, desired *v1alpha1.CloudPubSubSource) error { - existing = existing.DeepCopy() - return reconciler.RetryUpdateConflicts(func(attempts int) (err error) { - // The first iteration tries to use the injectionInformer's state, subsequent attempts fetch the latest state via API. - if attempts > 0 { - - getter := r.Client.EventsV1alpha1().CloudPubSubSources(desired.Namespace) - - existing, err = getter.Get(desired.Name, metav1.GetOptions{}) - if err != nil { - return err - } - } - - // If there's nothing to update, just return. - if reflect.DeepEqual(existing.Status, desired.Status) { - return nil - } - - existing.Status = desired.Status - - updater := r.Client.EventsV1alpha1().CloudPubSubSources(existing.Namespace) - - _, err = updater.UpdateStatus(existing) - return err - }) -} - -// updateFinalizersFiltered will update the Finalizers of the resource. -// TODO: this method could be generic and sync all finalizers. For now it only -// updates defaultFinalizerName or its override. -func (r *reconcilerImpl) updateFinalizersFiltered(ctx context.Context, resource *v1alpha1.CloudPubSubSource) (*v1alpha1.CloudPubSubSource, error) { - - getter := r.Lister.CloudPubSubSources(resource.Namespace) - - actual, err := getter.Get(resource.Name) - if err != nil { - return resource, err - } - - // Don't modify the informers copy. - existing := actual.DeepCopy() - - var finalizers []string - - // If there's nothing to update, just return. - existingFinalizers := sets.NewString(existing.Finalizers...) - desiredFinalizers := sets.NewString(resource.Finalizers...) - - if desiredFinalizers.Has(r.finalizerName) { - if existingFinalizers.Has(r.finalizerName) { - // Nothing to do. - return resource, nil - } - // Add the finalizer. - finalizers = append(existing.Finalizers, r.finalizerName) - } else { - if !existingFinalizers.Has(r.finalizerName) { - // Nothing to do. - return resource, nil - } - // Remove the finalizer. - existingFinalizers.Delete(r.finalizerName) - finalizers = existingFinalizers.List() - } - - mergePatch := map[string]interface{}{ - "metadata": map[string]interface{}{ - "finalizers": finalizers, - "resourceVersion": existing.ResourceVersion, - }, - } - - patch, err := json.Marshal(mergePatch) - if err != nil { - return resource, err - } - - patcher := r.Client.EventsV1alpha1().CloudPubSubSources(resource.Namespace) - - resourceName := resource.Name - resource, err = patcher.Patch(resourceName, types.MergePatchType, patch) - if err != nil { - r.Recorder.Eventf(resource, v1.EventTypeWarning, "FinalizerUpdateFailed", - "Failed to update finalizers for %q: %v", resourceName, err) - } else { - r.Recorder.Eventf(resource, v1.EventTypeNormal, "FinalizerUpdate", - "Updated %q finalizers", resource.GetName()) - } - return resource, err -} - -func (r *reconcilerImpl) setFinalizerIfFinalizer(ctx context.Context, resource *v1alpha1.CloudPubSubSource) (*v1alpha1.CloudPubSubSource, error) { - if _, ok := r.reconciler.(Finalizer); !ok { - return resource, nil - } - - finalizers := sets.NewString(resource.Finalizers...) - - // If this resource is not being deleted, mark the finalizer. - if resource.GetDeletionTimestamp().IsZero() { - finalizers.Insert(r.finalizerName) - } - - resource.Finalizers = finalizers.List() - - // Synchronize the finalizers filtered by r.finalizerName. - return r.updateFinalizersFiltered(ctx, resource) -} - -func (r *reconcilerImpl) clearFinalizer(ctx context.Context, resource *v1alpha1.CloudPubSubSource, reconcileEvent reconciler.Event) (*v1alpha1.CloudPubSubSource, error) { - if _, ok := r.reconciler.(Finalizer); !ok { - return resource, nil - } - if resource.GetDeletionTimestamp().IsZero() { - return resource, nil - } - - finalizers := sets.NewString(resource.Finalizers...) - - if reconcileEvent != nil { - var event *reconciler.ReconcilerEvent - if reconciler.EventAs(reconcileEvent, &event) { - if event.EventType == v1.EventTypeNormal { - finalizers.Delete(r.finalizerName) - } - } - } else { - finalizers.Delete(r.finalizerName) - } - - resource.Finalizers = finalizers.List() - - // Synchronize the finalizers filtered by r.finalizerName. - return r.updateFinalizersFiltered(ctx, resource) -} diff --git a/pkg/client/injection/reconciler/events/v1alpha1/cloudpubsubsource/stub/controller.go b/pkg/client/injection/reconciler/events/v1alpha1/cloudpubsubsource/stub/controller.go deleted file mode 100644 index 80a186bf02..0000000000 --- a/pkg/client/injection/reconciler/events/v1alpha1/cloudpubsubsource/stub/controller.go +++ /dev/null @@ -1,54 +0,0 @@ -/* -Copyright 2020 Google LLC - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -// Code generated by injection-gen. DO NOT EDIT. - -package cloudpubsubsource - -import ( - context "context" - - cloudpubsubsource "github.com/google/knative-gcp/pkg/client/injection/informers/events/v1alpha1/cloudpubsubsource" - v1alpha1cloudpubsubsource "github.com/google/knative-gcp/pkg/client/injection/reconciler/events/v1alpha1/cloudpubsubsource" - configmap "knative.dev/pkg/configmap" - controller "knative.dev/pkg/controller" - logging "knative.dev/pkg/logging" -) - -// TODO: PLEASE COPY AND MODIFY THIS FILE AS A STARTING POINT - -// NewController creates a Reconciler for CloudPubSubSource and returns the result of NewImpl. -func NewController( - ctx context.Context, - cmw configmap.Watcher, -) *controller.Impl { - logger := logging.FromContext(ctx) - - cloudpubsubsourceInformer := cloudpubsubsource.Get(ctx) - - // TODO: setup additional informers here. - - r := &Reconciler{} - impl := v1alpha1cloudpubsubsource.NewImpl(ctx, r) - - logger.Info("Setting up event handlers.") - - cloudpubsubsourceInformer.Informer().AddEventHandler(controller.HandleAll(impl.Enqueue)) - - // TODO: add additional informer event handlers here. - - return impl -} diff --git a/pkg/client/injection/reconciler/events/v1alpha1/cloudpubsubsource/stub/reconciler.go b/pkg/client/injection/reconciler/events/v1alpha1/cloudpubsubsource/stub/reconciler.go deleted file mode 100644 index b1696da828..0000000000 --- a/pkg/client/injection/reconciler/events/v1alpha1/cloudpubsubsource/stub/reconciler.go +++ /dev/null @@ -1,87 +0,0 @@ -/* -Copyright 2020 Google LLC - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -// Code generated by injection-gen. DO NOT EDIT. - -package cloudpubsubsource - -import ( - context "context" - - v1alpha1 "github.com/google/knative-gcp/pkg/apis/events/v1alpha1" - cloudpubsubsource "github.com/google/knative-gcp/pkg/client/injection/reconciler/events/v1alpha1/cloudpubsubsource" - v1 "k8s.io/api/core/v1" - reconciler "knative.dev/pkg/reconciler" -) - -// TODO: PLEASE COPY AND MODIFY THIS FILE AS A STARTING POINT - -// newReconciledNormal makes a new reconciler event with event type Normal, and -// reason CloudPubSubSourceReconciled. -func newReconciledNormal(namespace, name string) reconciler.Event { - return reconciler.NewEvent(v1.EventTypeNormal, "CloudPubSubSourceReconciled", "CloudPubSubSource reconciled: \"%s/%s\"", namespace, name) -} - -// Reconciler implements controller.Reconciler for CloudPubSubSource resources. -type Reconciler struct { - // TODO: add additional requirements here. -} - -// Check that our Reconciler implements Interface -var _ cloudpubsubsource.Interface = (*Reconciler)(nil) - -// Optionally check that our Reconciler implements Finalizer -//var _ cloudpubsubsource.Finalizer = (*Reconciler)(nil) - -// Optionally check that our Reconciler implements ReadOnlyInterface -// Implement this to observe resources even when we are not the leader. -//var _ cloudpubsubsource.ReadOnlyInterface = (*Reconciler)(nil) - -// Optionally check that our Reconciler implements ReadOnlyFinalizer -// Implement this to observe tombstoned resources even when we are not -// the leader (best effort). -//var _ cloudpubsubsource.ReadOnlyFinalizer = (*Reconciler)(nil) - -// ReconcileKind implements Interface.ReconcileKind. -func (r *Reconciler) ReconcileKind(ctx context.Context, o *v1alpha1.CloudPubSubSource) reconciler.Event { - // TODO: use this if the resource implements InitializeConditions. - // o.Status.InitializeConditions() - - // TODO: add custom reconciliation logic here. - - // TODO: use this if the object has .status.ObservedGeneration. - // o.Status.ObservedGeneration = o.Generation - return newReconciledNormal(o.Namespace, o.Name) -} - -// Optionally, use FinalizeKind to add finalizers. FinalizeKind will be called -// when the resource is deleted. -//func (r *Reconciler) FinalizeKind(ctx context.Context, o *v1alpha1.CloudPubSubSource) reconciler.Event { -// // TODO: add custom finalization logic here. -// return nil -//} - -// Optionally, use ObserveKind to observe the resource when we are not the leader. -// func (r *Reconciler) ObserveKind(ctx context.Context, o *v1alpha1.CloudPubSubSource) reconciler.Event { -// // TODO: add custom observation logic here. -// return nil -// } - -// Optionally, use ObserveFinalizeKind to observe resources being finalized when we are no the leader. -//func (r *Reconciler) ObserveFinalizeKind(ctx context.Context, o *v1alpha1.CloudPubSubSource) reconciler.Event { -// // TODO: add custom observation logic here. -// return nil -//} diff --git a/pkg/client/injection/reconciler/events/v1alpha1/cloudschedulersource/controller.go b/pkg/client/injection/reconciler/events/v1alpha1/cloudschedulersource/controller.go deleted file mode 100644 index e350a053e7..0000000000 --- a/pkg/client/injection/reconciler/events/v1alpha1/cloudschedulersource/controller.go +++ /dev/null @@ -1,139 +0,0 @@ -/* -Copyright 2020 Google LLC - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -// Code generated by injection-gen. DO NOT EDIT. - -package cloudschedulersource - -import ( - context "context" - fmt "fmt" - reflect "reflect" - strings "strings" - - versionedscheme "github.com/google/knative-gcp/pkg/client/clientset/versioned/scheme" - client "github.com/google/knative-gcp/pkg/client/injection/client" - cloudschedulersource "github.com/google/knative-gcp/pkg/client/injection/informers/events/v1alpha1/cloudschedulersource" - corev1 "k8s.io/api/core/v1" - labels "k8s.io/apimachinery/pkg/labels" - types "k8s.io/apimachinery/pkg/types" - watch "k8s.io/apimachinery/pkg/watch" - scheme "k8s.io/client-go/kubernetes/scheme" - v1 "k8s.io/client-go/kubernetes/typed/core/v1" - record "k8s.io/client-go/tools/record" - kubeclient "knative.dev/pkg/client/injection/kube/client" - controller "knative.dev/pkg/controller" - logging "knative.dev/pkg/logging" - reconciler "knative.dev/pkg/reconciler" -) - -const ( - defaultControllerAgentName = "cloudschedulersource-controller" - defaultFinalizerName = "cloudschedulersources.events.cloud.google.com" -) - -// NewImpl returns a controller.Impl that handles queuing and feeding work from -// the queue through an implementation of controller.Reconciler, delegating to -// the provided Interface and optional Finalizer methods. OptionsFn is used to return -// controller.Options to be used but the internal reconciler. -func NewImpl(ctx context.Context, r Interface, optionsFns ...controller.OptionsFn) *controller.Impl { - logger := logging.FromContext(ctx) - - // Check the options function input. It should be 0 or 1. - if len(optionsFns) > 1 { - logger.Fatalf("up to one options function is supported, found %d", len(optionsFns)) - } - - cloudschedulersourceInformer := cloudschedulersource.Get(ctx) - - lister := cloudschedulersourceInformer.Lister() - - rec := &reconcilerImpl{ - LeaderAwareFuncs: reconciler.LeaderAwareFuncs{ - PromoteFunc: func(bkt reconciler.Bucket, enq func(reconciler.Bucket, types.NamespacedName)) error { - all, err := lister.List(labels.Everything()) - if err != nil { - return err - } - for _, elt := range all { - // TODO: Consider letting users specify a filter in options. - enq(bkt, types.NamespacedName{ - Namespace: elt.GetNamespace(), - Name: elt.GetName(), - }) - } - return nil - }, - }, - Client: client.Get(ctx), - Lister: lister, - reconciler: r, - finalizerName: defaultFinalizerName, - } - - t := reflect.TypeOf(r).Elem() - queueName := fmt.Sprintf("%s.%s", strings.ReplaceAll(t.PkgPath(), "/", "-"), t.Name()) - - impl := controller.NewImpl(rec, logger, queueName) - agentName := defaultControllerAgentName - - // Pass impl to the options. Save any optional results. - for _, fn := range optionsFns { - opts := fn(impl) - if opts.ConfigStore != nil { - rec.configStore = opts.ConfigStore - } - if opts.FinalizerName != "" { - rec.finalizerName = opts.FinalizerName - } - if opts.AgentName != "" { - agentName = opts.AgentName - } - } - - rec.Recorder = createRecorder(ctx, agentName) - - return impl -} - -func createRecorder(ctx context.Context, agentName string) record.EventRecorder { - logger := logging.FromContext(ctx) - - recorder := controller.GetEventRecorder(ctx) - if recorder == nil { - // Create event broadcaster - logger.Debug("Creating event broadcaster") - eventBroadcaster := record.NewBroadcaster() - watches := []watch.Interface{ - eventBroadcaster.StartLogging(logger.Named("event-broadcaster").Infof), - eventBroadcaster.StartRecordingToSink( - &v1.EventSinkImpl{Interface: kubeclient.Get(ctx).CoreV1().Events("")}), - } - recorder = eventBroadcaster.NewRecorder(scheme.Scheme, corev1.EventSource{Component: agentName}) - go func() { - <-ctx.Done() - for _, w := range watches { - w.Stop() - } - }() - } - - return recorder -} - -func init() { - versionedscheme.AddToScheme(scheme.Scheme) -} diff --git a/pkg/client/injection/reconciler/events/v1alpha1/cloudschedulersource/reconciler.go b/pkg/client/injection/reconciler/events/v1alpha1/cloudschedulersource/reconciler.go deleted file mode 100644 index d9ea685534..0000000000 --- a/pkg/client/injection/reconciler/events/v1alpha1/cloudschedulersource/reconciler.go +++ /dev/null @@ -1,430 +0,0 @@ -/* -Copyright 2020 Google LLC - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -// Code generated by injection-gen. DO NOT EDIT. - -package cloudschedulersource - -import ( - context "context" - json "encoding/json" - fmt "fmt" - reflect "reflect" - - v1alpha1 "github.com/google/knative-gcp/pkg/apis/events/v1alpha1" - versioned "github.com/google/knative-gcp/pkg/client/clientset/versioned" - eventsv1alpha1 "github.com/google/knative-gcp/pkg/client/listers/events/v1alpha1" - zap "go.uber.org/zap" - v1 "k8s.io/api/core/v1" - equality "k8s.io/apimachinery/pkg/api/equality" - errors "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - labels "k8s.io/apimachinery/pkg/labels" - types "k8s.io/apimachinery/pkg/types" - sets "k8s.io/apimachinery/pkg/util/sets" - cache "k8s.io/client-go/tools/cache" - record "k8s.io/client-go/tools/record" - controller "knative.dev/pkg/controller" - logging "knative.dev/pkg/logging" - reconciler "knative.dev/pkg/reconciler" -) - -// Interface defines the strongly typed interfaces to be implemented by a -// controller reconciling v1alpha1.CloudSchedulerSource. -type Interface interface { - // ReconcileKind implements custom logic to reconcile v1alpha1.CloudSchedulerSource. Any changes - // to the objects .Status or .Finalizers will be propagated to the stored - // object. It is recommended that implementors do not call any update calls - // for the Kind inside of ReconcileKind, it is the responsibility of the calling - // controller to propagate those properties. The resource passed to ReconcileKind - // will always have an empty deletion timestamp. - ReconcileKind(ctx context.Context, o *v1alpha1.CloudSchedulerSource) reconciler.Event -} - -// Finalizer defines the strongly typed interfaces to be implemented by a -// controller finalizing v1alpha1.CloudSchedulerSource. -type Finalizer interface { - // FinalizeKind implements custom logic to finalize v1alpha1.CloudSchedulerSource. Any changes - // to the objects .Status or .Finalizers will be ignored. Returning a nil or - // Normal type reconciler.Event will allow the finalizer to be deleted on - // the resource. The resource passed to FinalizeKind will always have a set - // deletion timestamp. - FinalizeKind(ctx context.Context, o *v1alpha1.CloudSchedulerSource) reconciler.Event -} - -// ReadOnlyInterface defines the strongly typed interfaces to be implemented by a -// controller reconciling v1alpha1.CloudSchedulerSource if they want to process resources for which -// they are not the leader. -type ReadOnlyInterface interface { - // ObserveKind implements logic to observe v1alpha1.CloudSchedulerSource. - // This method should not write to the API. - ObserveKind(ctx context.Context, o *v1alpha1.CloudSchedulerSource) reconciler.Event -} - -// ReadOnlyFinalizer defines the strongly typed interfaces to be implemented by a -// controller finalizing v1alpha1.CloudSchedulerSource if they want to process tombstoned resources -// even when they are not the leader. Due to the nature of how finalizers are handled -// there are no guarantees that this will be called. -type ReadOnlyFinalizer interface { - // ObserveFinalizeKind implements custom logic to observe the final state of v1alpha1.CloudSchedulerSource. - // This method should not write to the API. - ObserveFinalizeKind(ctx context.Context, o *v1alpha1.CloudSchedulerSource) reconciler.Event -} - -// reconcilerImpl implements controller.Reconciler for v1alpha1.CloudSchedulerSource resources. -type reconcilerImpl struct { - // LeaderAwareFuncs is inlined to help us implement reconciler.LeaderAware - reconciler.LeaderAwareFuncs - - // Client is used to write back status updates. - Client versioned.Interface - - // Listers index properties about resources - Lister eventsv1alpha1.CloudSchedulerSourceLister - - // Recorder is an event recorder for recording Event resources to the - // Kubernetes API. - Recorder record.EventRecorder - - // configStore allows for decorating a context with config maps. - // +optional - configStore reconciler.ConfigStore - - // reconciler is the implementation of the business logic of the resource. - reconciler Interface - - // finalizerName is the name of the finalizer to reconcile. - finalizerName string -} - -// Check that our Reconciler implements controller.Reconciler -var _ controller.Reconciler = (*reconcilerImpl)(nil) - -// Check that our generated Reconciler is always LeaderAware. -var _ reconciler.LeaderAware = (*reconcilerImpl)(nil) - -func NewReconciler(ctx context.Context, logger *zap.SugaredLogger, client versioned.Interface, lister eventsv1alpha1.CloudSchedulerSourceLister, recorder record.EventRecorder, r Interface, options ...controller.Options) controller.Reconciler { - // Check the options function input. It should be 0 or 1. - if len(options) > 1 { - logger.Fatalf("up to one options struct is supported, found %d", len(options)) - } - - // Fail fast when users inadvertently implement the other LeaderAware interface. - // For the typed reconcilers, Promote shouldn't take any arguments. - if _, ok := r.(reconciler.LeaderAware); ok { - logger.Fatalf("%T implements the incorrect LeaderAware interface. Promote() should not take an argument as genreconciler handles the enqueuing automatically.", r) - } - // TODO: Consider validating when folks implement ReadOnlyFinalizer, but not Finalizer. - - rec := &reconcilerImpl{ - LeaderAwareFuncs: reconciler.LeaderAwareFuncs{ - PromoteFunc: func(bkt reconciler.Bucket, enq func(reconciler.Bucket, types.NamespacedName)) error { - all, err := lister.List(labels.Everything()) - if err != nil { - return err - } - for _, elt := range all { - // TODO: Consider letting users specify a filter in options. - enq(bkt, types.NamespacedName{ - Namespace: elt.GetNamespace(), - Name: elt.GetName(), - }) - } - return nil - }, - }, - Client: client, - Lister: lister, - Recorder: recorder, - reconciler: r, - finalizerName: defaultFinalizerName, - } - - for _, opts := range options { - if opts.ConfigStore != nil { - rec.configStore = opts.ConfigStore - } - if opts.FinalizerName != "" { - rec.finalizerName = opts.FinalizerName - } - } - - return rec -} - -// Reconcile implements controller.Reconciler -func (r *reconcilerImpl) Reconcile(ctx context.Context, key string) error { - logger := logging.FromContext(ctx) - - // Convert the namespace/name string into a distinct namespace and name - namespace, name, err := cache.SplitMetaNamespaceKey(key) - if err != nil { - logger.Errorf("invalid resource key: %s", key) - return nil - } - // Establish whether we are the leader for use below. - isLeader := r.IsLeaderFor(types.NamespacedName{ - Namespace: namespace, - Name: name, - }) - roi, isROI := r.reconciler.(ReadOnlyInterface) - rof, isROF := r.reconciler.(ReadOnlyFinalizer) - if !isLeader && !isROI && !isROF { - // If we are not the leader, and we don't implement either ReadOnly - // interface, then take a fast-path out. - return nil - } - - // If configStore is set, attach the frozen configuration to the context. - if r.configStore != nil { - ctx = r.configStore.ToContext(ctx) - } - - // Add the recorder to context. - ctx = controller.WithEventRecorder(ctx, r.Recorder) - - // Get the resource with this namespace/name. - - getter := r.Lister.CloudSchedulerSources(namespace) - - original, err := getter.Get(name) - - if errors.IsNotFound(err) { - // The resource may no longer exist, in which case we stop processing. - logger.Debugf("resource %q no longer exists", key) - return nil - } else if err != nil { - return err - } - - // Don't modify the informers copy. - resource := original.DeepCopy() - - var reconcileEvent reconciler.Event - if resource.GetDeletionTimestamp().IsZero() { - if isLeader { - // Append the target method to the logger. - logger = logger.With(zap.String("targetMethod", "ReconcileKind")) - - // Set and update the finalizer on resource if r.reconciler - // implements Finalizer. - if resource, err = r.setFinalizerIfFinalizer(ctx, resource); err != nil { - return fmt.Errorf("failed to set finalizers: %w", err) - } - - // Reconcile this copy of the resource and then write back any status - // updates regardless of whether the reconciliation errored out. - reconcileEvent = r.reconciler.ReconcileKind(ctx, resource) - - } else if isROI { - // Append the target method to the logger. - logger = logger.With(zap.String("targetMethod", "ObserveKind")) - - // Observe any changes to this resource, since we are not the leader. - reconcileEvent = roi.ObserveKind(ctx, resource) - } - } else if fin, ok := r.reconciler.(Finalizer); isLeader && ok { - // Append the target method to the logger. - logger = logger.With(zap.String("targetMethod", "FinalizeKind")) - - // For finalizing reconcilers, if this resource being marked for deletion - // and reconciled cleanly (nil or normal event), remove the finalizer. - reconcileEvent = fin.FinalizeKind(ctx, resource) - if resource, err = r.clearFinalizer(ctx, resource, reconcileEvent); err != nil { - return fmt.Errorf("failed to clear finalizers: %w", err) - } - } else if !isLeader && isROF { - // Append the target method to the logger. - logger = logger.With(zap.String("targetMethod", "ObserveFinalizeKind")) - - // For finalizing reconcilers, just observe when we aren't the leader. - reconcileEvent = rof.ObserveFinalizeKind(ctx, resource) - } - - // Synchronize the status. - if equality.Semantic.DeepEqual(original.Status, resource.Status) { - // If we didn't change anything then don't call updateStatus. - // This is important because the copy we loaded from the injectionInformer's - // cache may be stale and we don't want to overwrite a prior update - // to status with this stale state. - } else if !isLeader { - logger.Warn("Saw status changes when we aren't the leader!") - // TODO: Consider logging the diff at Debug? - } else if err = r.updateStatus(original, resource); err != nil { - logger.Warnw("Failed to update resource status", zap.Error(err)) - r.Recorder.Eventf(resource, v1.EventTypeWarning, "UpdateFailed", - "Failed to update status for %q: %v", resource.Name, err) - return err - } - - // Report the reconciler event, if any. - if reconcileEvent != nil { - var event *reconciler.ReconcilerEvent - if reconciler.EventAs(reconcileEvent, &event) { - logger.Infow("Returned an event", zap.Any("event", reconcileEvent)) - r.Recorder.Eventf(resource, event.EventType, event.Reason, event.Format, event.Args...) - - // the event was wrapped inside an error, consider the reconciliation as failed - if _, isEvent := reconcileEvent.(*reconciler.ReconcilerEvent); !isEvent { - return reconcileEvent - } - return nil - } - - logger.Errorw("Returned an error", zap.Error(reconcileEvent)) - r.Recorder.Event(resource, v1.EventTypeWarning, "InternalError", reconcileEvent.Error()) - return reconcileEvent - } - - return nil -} - -func (r *reconcilerImpl) updateStatus(existing *v1alpha1.CloudSchedulerSource, desired *v1alpha1.CloudSchedulerSource) error { - existing = existing.DeepCopy() - return reconciler.RetryUpdateConflicts(func(attempts int) (err error) { - // The first iteration tries to use the injectionInformer's state, subsequent attempts fetch the latest state via API. - if attempts > 0 { - - getter := r.Client.EventsV1alpha1().CloudSchedulerSources(desired.Namespace) - - existing, err = getter.Get(desired.Name, metav1.GetOptions{}) - if err != nil { - return err - } - } - - // If there's nothing to update, just return. - if reflect.DeepEqual(existing.Status, desired.Status) { - return nil - } - - existing.Status = desired.Status - - updater := r.Client.EventsV1alpha1().CloudSchedulerSources(existing.Namespace) - - _, err = updater.UpdateStatus(existing) - return err - }) -} - -// updateFinalizersFiltered will update the Finalizers of the resource. -// TODO: this method could be generic and sync all finalizers. For now it only -// updates defaultFinalizerName or its override. -func (r *reconcilerImpl) updateFinalizersFiltered(ctx context.Context, resource *v1alpha1.CloudSchedulerSource) (*v1alpha1.CloudSchedulerSource, error) { - - getter := r.Lister.CloudSchedulerSources(resource.Namespace) - - actual, err := getter.Get(resource.Name) - if err != nil { - return resource, err - } - - // Don't modify the informers copy. - existing := actual.DeepCopy() - - var finalizers []string - - // If there's nothing to update, just return. - existingFinalizers := sets.NewString(existing.Finalizers...) - desiredFinalizers := sets.NewString(resource.Finalizers...) - - if desiredFinalizers.Has(r.finalizerName) { - if existingFinalizers.Has(r.finalizerName) { - // Nothing to do. - return resource, nil - } - // Add the finalizer. - finalizers = append(existing.Finalizers, r.finalizerName) - } else { - if !existingFinalizers.Has(r.finalizerName) { - // Nothing to do. - return resource, nil - } - // Remove the finalizer. - existingFinalizers.Delete(r.finalizerName) - finalizers = existingFinalizers.List() - } - - mergePatch := map[string]interface{}{ - "metadata": map[string]interface{}{ - "finalizers": finalizers, - "resourceVersion": existing.ResourceVersion, - }, - } - - patch, err := json.Marshal(mergePatch) - if err != nil { - return resource, err - } - - patcher := r.Client.EventsV1alpha1().CloudSchedulerSources(resource.Namespace) - - resourceName := resource.Name - resource, err = patcher.Patch(resourceName, types.MergePatchType, patch) - if err != nil { - r.Recorder.Eventf(resource, v1.EventTypeWarning, "FinalizerUpdateFailed", - "Failed to update finalizers for %q: %v", resourceName, err) - } else { - r.Recorder.Eventf(resource, v1.EventTypeNormal, "FinalizerUpdate", - "Updated %q finalizers", resource.GetName()) - } - return resource, err -} - -func (r *reconcilerImpl) setFinalizerIfFinalizer(ctx context.Context, resource *v1alpha1.CloudSchedulerSource) (*v1alpha1.CloudSchedulerSource, error) { - if _, ok := r.reconciler.(Finalizer); !ok { - return resource, nil - } - - finalizers := sets.NewString(resource.Finalizers...) - - // If this resource is not being deleted, mark the finalizer. - if resource.GetDeletionTimestamp().IsZero() { - finalizers.Insert(r.finalizerName) - } - - resource.Finalizers = finalizers.List() - - // Synchronize the finalizers filtered by r.finalizerName. - return r.updateFinalizersFiltered(ctx, resource) -} - -func (r *reconcilerImpl) clearFinalizer(ctx context.Context, resource *v1alpha1.CloudSchedulerSource, reconcileEvent reconciler.Event) (*v1alpha1.CloudSchedulerSource, error) { - if _, ok := r.reconciler.(Finalizer); !ok { - return resource, nil - } - if resource.GetDeletionTimestamp().IsZero() { - return resource, nil - } - - finalizers := sets.NewString(resource.Finalizers...) - - if reconcileEvent != nil { - var event *reconciler.ReconcilerEvent - if reconciler.EventAs(reconcileEvent, &event) { - if event.EventType == v1.EventTypeNormal { - finalizers.Delete(r.finalizerName) - } - } - } else { - finalizers.Delete(r.finalizerName) - } - - resource.Finalizers = finalizers.List() - - // Synchronize the finalizers filtered by r.finalizerName. - return r.updateFinalizersFiltered(ctx, resource) -} diff --git a/pkg/client/injection/reconciler/events/v1alpha1/cloudschedulersource/stub/controller.go b/pkg/client/injection/reconciler/events/v1alpha1/cloudschedulersource/stub/controller.go deleted file mode 100644 index f2df5e236d..0000000000 --- a/pkg/client/injection/reconciler/events/v1alpha1/cloudschedulersource/stub/controller.go +++ /dev/null @@ -1,54 +0,0 @@ -/* -Copyright 2020 Google LLC - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -// Code generated by injection-gen. DO NOT EDIT. - -package cloudschedulersource - -import ( - context "context" - - cloudschedulersource "github.com/google/knative-gcp/pkg/client/injection/informers/events/v1alpha1/cloudschedulersource" - v1alpha1cloudschedulersource "github.com/google/knative-gcp/pkg/client/injection/reconciler/events/v1alpha1/cloudschedulersource" - configmap "knative.dev/pkg/configmap" - controller "knative.dev/pkg/controller" - logging "knative.dev/pkg/logging" -) - -// TODO: PLEASE COPY AND MODIFY THIS FILE AS A STARTING POINT - -// NewController creates a Reconciler for CloudSchedulerSource and returns the result of NewImpl. -func NewController( - ctx context.Context, - cmw configmap.Watcher, -) *controller.Impl { - logger := logging.FromContext(ctx) - - cloudschedulersourceInformer := cloudschedulersource.Get(ctx) - - // TODO: setup additional informers here. - - r := &Reconciler{} - impl := v1alpha1cloudschedulersource.NewImpl(ctx, r) - - logger.Info("Setting up event handlers.") - - cloudschedulersourceInformer.Informer().AddEventHandler(controller.HandleAll(impl.Enqueue)) - - // TODO: add additional informer event handlers here. - - return impl -} diff --git a/pkg/client/injection/reconciler/events/v1alpha1/cloudschedulersource/stub/reconciler.go b/pkg/client/injection/reconciler/events/v1alpha1/cloudschedulersource/stub/reconciler.go deleted file mode 100644 index 9d0e2604ee..0000000000 --- a/pkg/client/injection/reconciler/events/v1alpha1/cloudschedulersource/stub/reconciler.go +++ /dev/null @@ -1,87 +0,0 @@ -/* -Copyright 2020 Google LLC - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -// Code generated by injection-gen. DO NOT EDIT. - -package cloudschedulersource - -import ( - context "context" - - v1alpha1 "github.com/google/knative-gcp/pkg/apis/events/v1alpha1" - cloudschedulersource "github.com/google/knative-gcp/pkg/client/injection/reconciler/events/v1alpha1/cloudschedulersource" - v1 "k8s.io/api/core/v1" - reconciler "knative.dev/pkg/reconciler" -) - -// TODO: PLEASE COPY AND MODIFY THIS FILE AS A STARTING POINT - -// newReconciledNormal makes a new reconciler event with event type Normal, and -// reason CloudSchedulerSourceReconciled. -func newReconciledNormal(namespace, name string) reconciler.Event { - return reconciler.NewEvent(v1.EventTypeNormal, "CloudSchedulerSourceReconciled", "CloudSchedulerSource reconciled: \"%s/%s\"", namespace, name) -} - -// Reconciler implements controller.Reconciler for CloudSchedulerSource resources. -type Reconciler struct { - // TODO: add additional requirements here. -} - -// Check that our Reconciler implements Interface -var _ cloudschedulersource.Interface = (*Reconciler)(nil) - -// Optionally check that our Reconciler implements Finalizer -//var _ cloudschedulersource.Finalizer = (*Reconciler)(nil) - -// Optionally check that our Reconciler implements ReadOnlyInterface -// Implement this to observe resources even when we are not the leader. -//var _ cloudschedulersource.ReadOnlyInterface = (*Reconciler)(nil) - -// Optionally check that our Reconciler implements ReadOnlyFinalizer -// Implement this to observe tombstoned resources even when we are not -// the leader (best effort). -//var _ cloudschedulersource.ReadOnlyFinalizer = (*Reconciler)(nil) - -// ReconcileKind implements Interface.ReconcileKind. -func (r *Reconciler) ReconcileKind(ctx context.Context, o *v1alpha1.CloudSchedulerSource) reconciler.Event { - // TODO: use this if the resource implements InitializeConditions. - // o.Status.InitializeConditions() - - // TODO: add custom reconciliation logic here. - - // TODO: use this if the object has .status.ObservedGeneration. - // o.Status.ObservedGeneration = o.Generation - return newReconciledNormal(o.Namespace, o.Name) -} - -// Optionally, use FinalizeKind to add finalizers. FinalizeKind will be called -// when the resource is deleted. -//func (r *Reconciler) FinalizeKind(ctx context.Context, o *v1alpha1.CloudSchedulerSource) reconciler.Event { -// // TODO: add custom finalization logic here. -// return nil -//} - -// Optionally, use ObserveKind to observe the resource when we are not the leader. -// func (r *Reconciler) ObserveKind(ctx context.Context, o *v1alpha1.CloudSchedulerSource) reconciler.Event { -// // TODO: add custom observation logic here. -// return nil -// } - -// Optionally, use ObserveFinalizeKind to observe resources being finalized when we are no the leader. -//func (r *Reconciler) ObserveFinalizeKind(ctx context.Context, o *v1alpha1.CloudSchedulerSource) reconciler.Event { -// // TODO: add custom observation logic here. -// return nil -//} diff --git a/pkg/client/injection/reconciler/events/v1alpha1/cloudstoragesource/controller.go b/pkg/client/injection/reconciler/events/v1alpha1/cloudstoragesource/controller.go deleted file mode 100644 index 51dcfa63d1..0000000000 --- a/pkg/client/injection/reconciler/events/v1alpha1/cloudstoragesource/controller.go +++ /dev/null @@ -1,139 +0,0 @@ -/* -Copyright 2020 Google LLC - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -// Code generated by injection-gen. DO NOT EDIT. - -package cloudstoragesource - -import ( - context "context" - fmt "fmt" - reflect "reflect" - strings "strings" - - versionedscheme "github.com/google/knative-gcp/pkg/client/clientset/versioned/scheme" - client "github.com/google/knative-gcp/pkg/client/injection/client" - cloudstoragesource "github.com/google/knative-gcp/pkg/client/injection/informers/events/v1alpha1/cloudstoragesource" - corev1 "k8s.io/api/core/v1" - labels "k8s.io/apimachinery/pkg/labels" - types "k8s.io/apimachinery/pkg/types" - watch "k8s.io/apimachinery/pkg/watch" - scheme "k8s.io/client-go/kubernetes/scheme" - v1 "k8s.io/client-go/kubernetes/typed/core/v1" - record "k8s.io/client-go/tools/record" - kubeclient "knative.dev/pkg/client/injection/kube/client" - controller "knative.dev/pkg/controller" - logging "knative.dev/pkg/logging" - reconciler "knative.dev/pkg/reconciler" -) - -const ( - defaultControllerAgentName = "cloudstoragesource-controller" - defaultFinalizerName = "cloudstoragesources.events.cloud.google.com" -) - -// NewImpl returns a controller.Impl that handles queuing and feeding work from -// the queue through an implementation of controller.Reconciler, delegating to -// the provided Interface and optional Finalizer methods. OptionsFn is used to return -// controller.Options to be used but the internal reconciler. -func NewImpl(ctx context.Context, r Interface, optionsFns ...controller.OptionsFn) *controller.Impl { - logger := logging.FromContext(ctx) - - // Check the options function input. It should be 0 or 1. - if len(optionsFns) > 1 { - logger.Fatalf("up to one options function is supported, found %d", len(optionsFns)) - } - - cloudstoragesourceInformer := cloudstoragesource.Get(ctx) - - lister := cloudstoragesourceInformer.Lister() - - rec := &reconcilerImpl{ - LeaderAwareFuncs: reconciler.LeaderAwareFuncs{ - PromoteFunc: func(bkt reconciler.Bucket, enq func(reconciler.Bucket, types.NamespacedName)) error { - all, err := lister.List(labels.Everything()) - if err != nil { - return err - } - for _, elt := range all { - // TODO: Consider letting users specify a filter in options. - enq(bkt, types.NamespacedName{ - Namespace: elt.GetNamespace(), - Name: elt.GetName(), - }) - } - return nil - }, - }, - Client: client.Get(ctx), - Lister: lister, - reconciler: r, - finalizerName: defaultFinalizerName, - } - - t := reflect.TypeOf(r).Elem() - queueName := fmt.Sprintf("%s.%s", strings.ReplaceAll(t.PkgPath(), "/", "-"), t.Name()) - - impl := controller.NewImpl(rec, logger, queueName) - agentName := defaultControllerAgentName - - // Pass impl to the options. Save any optional results. - for _, fn := range optionsFns { - opts := fn(impl) - if opts.ConfigStore != nil { - rec.configStore = opts.ConfigStore - } - if opts.FinalizerName != "" { - rec.finalizerName = opts.FinalizerName - } - if opts.AgentName != "" { - agentName = opts.AgentName - } - } - - rec.Recorder = createRecorder(ctx, agentName) - - return impl -} - -func createRecorder(ctx context.Context, agentName string) record.EventRecorder { - logger := logging.FromContext(ctx) - - recorder := controller.GetEventRecorder(ctx) - if recorder == nil { - // Create event broadcaster - logger.Debug("Creating event broadcaster") - eventBroadcaster := record.NewBroadcaster() - watches := []watch.Interface{ - eventBroadcaster.StartLogging(logger.Named("event-broadcaster").Infof), - eventBroadcaster.StartRecordingToSink( - &v1.EventSinkImpl{Interface: kubeclient.Get(ctx).CoreV1().Events("")}), - } - recorder = eventBroadcaster.NewRecorder(scheme.Scheme, corev1.EventSource{Component: agentName}) - go func() { - <-ctx.Done() - for _, w := range watches { - w.Stop() - } - }() - } - - return recorder -} - -func init() { - versionedscheme.AddToScheme(scheme.Scheme) -} diff --git a/pkg/client/injection/reconciler/events/v1alpha1/cloudstoragesource/reconciler.go b/pkg/client/injection/reconciler/events/v1alpha1/cloudstoragesource/reconciler.go deleted file mode 100644 index 35fd177849..0000000000 --- a/pkg/client/injection/reconciler/events/v1alpha1/cloudstoragesource/reconciler.go +++ /dev/null @@ -1,430 +0,0 @@ -/* -Copyright 2020 Google LLC - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -// Code generated by injection-gen. DO NOT EDIT. - -package cloudstoragesource - -import ( - context "context" - json "encoding/json" - fmt "fmt" - reflect "reflect" - - v1alpha1 "github.com/google/knative-gcp/pkg/apis/events/v1alpha1" - versioned "github.com/google/knative-gcp/pkg/client/clientset/versioned" - eventsv1alpha1 "github.com/google/knative-gcp/pkg/client/listers/events/v1alpha1" - zap "go.uber.org/zap" - v1 "k8s.io/api/core/v1" - equality "k8s.io/apimachinery/pkg/api/equality" - errors "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - labels "k8s.io/apimachinery/pkg/labels" - types "k8s.io/apimachinery/pkg/types" - sets "k8s.io/apimachinery/pkg/util/sets" - cache "k8s.io/client-go/tools/cache" - record "k8s.io/client-go/tools/record" - controller "knative.dev/pkg/controller" - logging "knative.dev/pkg/logging" - reconciler "knative.dev/pkg/reconciler" -) - -// Interface defines the strongly typed interfaces to be implemented by a -// controller reconciling v1alpha1.CloudStorageSource. -type Interface interface { - // ReconcileKind implements custom logic to reconcile v1alpha1.CloudStorageSource. Any changes - // to the objects .Status or .Finalizers will be propagated to the stored - // object. It is recommended that implementors do not call any update calls - // for the Kind inside of ReconcileKind, it is the responsibility of the calling - // controller to propagate those properties. The resource passed to ReconcileKind - // will always have an empty deletion timestamp. - ReconcileKind(ctx context.Context, o *v1alpha1.CloudStorageSource) reconciler.Event -} - -// Finalizer defines the strongly typed interfaces to be implemented by a -// controller finalizing v1alpha1.CloudStorageSource. -type Finalizer interface { - // FinalizeKind implements custom logic to finalize v1alpha1.CloudStorageSource. Any changes - // to the objects .Status or .Finalizers will be ignored. Returning a nil or - // Normal type reconciler.Event will allow the finalizer to be deleted on - // the resource. The resource passed to FinalizeKind will always have a set - // deletion timestamp. - FinalizeKind(ctx context.Context, o *v1alpha1.CloudStorageSource) reconciler.Event -} - -// ReadOnlyInterface defines the strongly typed interfaces to be implemented by a -// controller reconciling v1alpha1.CloudStorageSource if they want to process resources for which -// they are not the leader. -type ReadOnlyInterface interface { - // ObserveKind implements logic to observe v1alpha1.CloudStorageSource. - // This method should not write to the API. - ObserveKind(ctx context.Context, o *v1alpha1.CloudStorageSource) reconciler.Event -} - -// ReadOnlyFinalizer defines the strongly typed interfaces to be implemented by a -// controller finalizing v1alpha1.CloudStorageSource if they want to process tombstoned resources -// even when they are not the leader. Due to the nature of how finalizers are handled -// there are no guarantees that this will be called. -type ReadOnlyFinalizer interface { - // ObserveFinalizeKind implements custom logic to observe the final state of v1alpha1.CloudStorageSource. - // This method should not write to the API. - ObserveFinalizeKind(ctx context.Context, o *v1alpha1.CloudStorageSource) reconciler.Event -} - -// reconcilerImpl implements controller.Reconciler for v1alpha1.CloudStorageSource resources. -type reconcilerImpl struct { - // LeaderAwareFuncs is inlined to help us implement reconciler.LeaderAware - reconciler.LeaderAwareFuncs - - // Client is used to write back status updates. - Client versioned.Interface - - // Listers index properties about resources - Lister eventsv1alpha1.CloudStorageSourceLister - - // Recorder is an event recorder for recording Event resources to the - // Kubernetes API. - Recorder record.EventRecorder - - // configStore allows for decorating a context with config maps. - // +optional - configStore reconciler.ConfigStore - - // reconciler is the implementation of the business logic of the resource. - reconciler Interface - - // finalizerName is the name of the finalizer to reconcile. - finalizerName string -} - -// Check that our Reconciler implements controller.Reconciler -var _ controller.Reconciler = (*reconcilerImpl)(nil) - -// Check that our generated Reconciler is always LeaderAware. -var _ reconciler.LeaderAware = (*reconcilerImpl)(nil) - -func NewReconciler(ctx context.Context, logger *zap.SugaredLogger, client versioned.Interface, lister eventsv1alpha1.CloudStorageSourceLister, recorder record.EventRecorder, r Interface, options ...controller.Options) controller.Reconciler { - // Check the options function input. It should be 0 or 1. - if len(options) > 1 { - logger.Fatalf("up to one options struct is supported, found %d", len(options)) - } - - // Fail fast when users inadvertently implement the other LeaderAware interface. - // For the typed reconcilers, Promote shouldn't take any arguments. - if _, ok := r.(reconciler.LeaderAware); ok { - logger.Fatalf("%T implements the incorrect LeaderAware interface. Promote() should not take an argument as genreconciler handles the enqueuing automatically.", r) - } - // TODO: Consider validating when folks implement ReadOnlyFinalizer, but not Finalizer. - - rec := &reconcilerImpl{ - LeaderAwareFuncs: reconciler.LeaderAwareFuncs{ - PromoteFunc: func(bkt reconciler.Bucket, enq func(reconciler.Bucket, types.NamespacedName)) error { - all, err := lister.List(labels.Everything()) - if err != nil { - return err - } - for _, elt := range all { - // TODO: Consider letting users specify a filter in options. - enq(bkt, types.NamespacedName{ - Namespace: elt.GetNamespace(), - Name: elt.GetName(), - }) - } - return nil - }, - }, - Client: client, - Lister: lister, - Recorder: recorder, - reconciler: r, - finalizerName: defaultFinalizerName, - } - - for _, opts := range options { - if opts.ConfigStore != nil { - rec.configStore = opts.ConfigStore - } - if opts.FinalizerName != "" { - rec.finalizerName = opts.FinalizerName - } - } - - return rec -} - -// Reconcile implements controller.Reconciler -func (r *reconcilerImpl) Reconcile(ctx context.Context, key string) error { - logger := logging.FromContext(ctx) - - // Convert the namespace/name string into a distinct namespace and name - namespace, name, err := cache.SplitMetaNamespaceKey(key) - if err != nil { - logger.Errorf("invalid resource key: %s", key) - return nil - } - // Establish whether we are the leader for use below. - isLeader := r.IsLeaderFor(types.NamespacedName{ - Namespace: namespace, - Name: name, - }) - roi, isROI := r.reconciler.(ReadOnlyInterface) - rof, isROF := r.reconciler.(ReadOnlyFinalizer) - if !isLeader && !isROI && !isROF { - // If we are not the leader, and we don't implement either ReadOnly - // interface, then take a fast-path out. - return nil - } - - // If configStore is set, attach the frozen configuration to the context. - if r.configStore != nil { - ctx = r.configStore.ToContext(ctx) - } - - // Add the recorder to context. - ctx = controller.WithEventRecorder(ctx, r.Recorder) - - // Get the resource with this namespace/name. - - getter := r.Lister.CloudStorageSources(namespace) - - original, err := getter.Get(name) - - if errors.IsNotFound(err) { - // The resource may no longer exist, in which case we stop processing. - logger.Debugf("resource %q no longer exists", key) - return nil - } else if err != nil { - return err - } - - // Don't modify the informers copy. - resource := original.DeepCopy() - - var reconcileEvent reconciler.Event - if resource.GetDeletionTimestamp().IsZero() { - if isLeader { - // Append the target method to the logger. - logger = logger.With(zap.String("targetMethod", "ReconcileKind")) - - // Set and update the finalizer on resource if r.reconciler - // implements Finalizer. - if resource, err = r.setFinalizerIfFinalizer(ctx, resource); err != nil { - return fmt.Errorf("failed to set finalizers: %w", err) - } - - // Reconcile this copy of the resource and then write back any status - // updates regardless of whether the reconciliation errored out. - reconcileEvent = r.reconciler.ReconcileKind(ctx, resource) - - } else if isROI { - // Append the target method to the logger. - logger = logger.With(zap.String("targetMethod", "ObserveKind")) - - // Observe any changes to this resource, since we are not the leader. - reconcileEvent = roi.ObserveKind(ctx, resource) - } - } else if fin, ok := r.reconciler.(Finalizer); isLeader && ok { - // Append the target method to the logger. - logger = logger.With(zap.String("targetMethod", "FinalizeKind")) - - // For finalizing reconcilers, if this resource being marked for deletion - // and reconciled cleanly (nil or normal event), remove the finalizer. - reconcileEvent = fin.FinalizeKind(ctx, resource) - if resource, err = r.clearFinalizer(ctx, resource, reconcileEvent); err != nil { - return fmt.Errorf("failed to clear finalizers: %w", err) - } - } else if !isLeader && isROF { - // Append the target method to the logger. - logger = logger.With(zap.String("targetMethod", "ObserveFinalizeKind")) - - // For finalizing reconcilers, just observe when we aren't the leader. - reconcileEvent = rof.ObserveFinalizeKind(ctx, resource) - } - - // Synchronize the status. - if equality.Semantic.DeepEqual(original.Status, resource.Status) { - // If we didn't change anything then don't call updateStatus. - // This is important because the copy we loaded from the injectionInformer's - // cache may be stale and we don't want to overwrite a prior update - // to status with this stale state. - } else if !isLeader { - logger.Warn("Saw status changes when we aren't the leader!") - // TODO: Consider logging the diff at Debug? - } else if err = r.updateStatus(original, resource); err != nil { - logger.Warnw("Failed to update resource status", zap.Error(err)) - r.Recorder.Eventf(resource, v1.EventTypeWarning, "UpdateFailed", - "Failed to update status for %q: %v", resource.Name, err) - return err - } - - // Report the reconciler event, if any. - if reconcileEvent != nil { - var event *reconciler.ReconcilerEvent - if reconciler.EventAs(reconcileEvent, &event) { - logger.Infow("Returned an event", zap.Any("event", reconcileEvent)) - r.Recorder.Eventf(resource, event.EventType, event.Reason, event.Format, event.Args...) - - // the event was wrapped inside an error, consider the reconciliation as failed - if _, isEvent := reconcileEvent.(*reconciler.ReconcilerEvent); !isEvent { - return reconcileEvent - } - return nil - } - - logger.Errorw("Returned an error", zap.Error(reconcileEvent)) - r.Recorder.Event(resource, v1.EventTypeWarning, "InternalError", reconcileEvent.Error()) - return reconcileEvent - } - - return nil -} - -func (r *reconcilerImpl) updateStatus(existing *v1alpha1.CloudStorageSource, desired *v1alpha1.CloudStorageSource) error { - existing = existing.DeepCopy() - return reconciler.RetryUpdateConflicts(func(attempts int) (err error) { - // The first iteration tries to use the injectionInformer's state, subsequent attempts fetch the latest state via API. - if attempts > 0 { - - getter := r.Client.EventsV1alpha1().CloudStorageSources(desired.Namespace) - - existing, err = getter.Get(desired.Name, metav1.GetOptions{}) - if err != nil { - return err - } - } - - // If there's nothing to update, just return. - if reflect.DeepEqual(existing.Status, desired.Status) { - return nil - } - - existing.Status = desired.Status - - updater := r.Client.EventsV1alpha1().CloudStorageSources(existing.Namespace) - - _, err = updater.UpdateStatus(existing) - return err - }) -} - -// updateFinalizersFiltered will update the Finalizers of the resource. -// TODO: this method could be generic and sync all finalizers. For now it only -// updates defaultFinalizerName or its override. -func (r *reconcilerImpl) updateFinalizersFiltered(ctx context.Context, resource *v1alpha1.CloudStorageSource) (*v1alpha1.CloudStorageSource, error) { - - getter := r.Lister.CloudStorageSources(resource.Namespace) - - actual, err := getter.Get(resource.Name) - if err != nil { - return resource, err - } - - // Don't modify the informers copy. - existing := actual.DeepCopy() - - var finalizers []string - - // If there's nothing to update, just return. - existingFinalizers := sets.NewString(existing.Finalizers...) - desiredFinalizers := sets.NewString(resource.Finalizers...) - - if desiredFinalizers.Has(r.finalizerName) { - if existingFinalizers.Has(r.finalizerName) { - // Nothing to do. - return resource, nil - } - // Add the finalizer. - finalizers = append(existing.Finalizers, r.finalizerName) - } else { - if !existingFinalizers.Has(r.finalizerName) { - // Nothing to do. - return resource, nil - } - // Remove the finalizer. - existingFinalizers.Delete(r.finalizerName) - finalizers = existingFinalizers.List() - } - - mergePatch := map[string]interface{}{ - "metadata": map[string]interface{}{ - "finalizers": finalizers, - "resourceVersion": existing.ResourceVersion, - }, - } - - patch, err := json.Marshal(mergePatch) - if err != nil { - return resource, err - } - - patcher := r.Client.EventsV1alpha1().CloudStorageSources(resource.Namespace) - - resourceName := resource.Name - resource, err = patcher.Patch(resourceName, types.MergePatchType, patch) - if err != nil { - r.Recorder.Eventf(resource, v1.EventTypeWarning, "FinalizerUpdateFailed", - "Failed to update finalizers for %q: %v", resourceName, err) - } else { - r.Recorder.Eventf(resource, v1.EventTypeNormal, "FinalizerUpdate", - "Updated %q finalizers", resource.GetName()) - } - return resource, err -} - -func (r *reconcilerImpl) setFinalizerIfFinalizer(ctx context.Context, resource *v1alpha1.CloudStorageSource) (*v1alpha1.CloudStorageSource, error) { - if _, ok := r.reconciler.(Finalizer); !ok { - return resource, nil - } - - finalizers := sets.NewString(resource.Finalizers...) - - // If this resource is not being deleted, mark the finalizer. - if resource.GetDeletionTimestamp().IsZero() { - finalizers.Insert(r.finalizerName) - } - - resource.Finalizers = finalizers.List() - - // Synchronize the finalizers filtered by r.finalizerName. - return r.updateFinalizersFiltered(ctx, resource) -} - -func (r *reconcilerImpl) clearFinalizer(ctx context.Context, resource *v1alpha1.CloudStorageSource, reconcileEvent reconciler.Event) (*v1alpha1.CloudStorageSource, error) { - if _, ok := r.reconciler.(Finalizer); !ok { - return resource, nil - } - if resource.GetDeletionTimestamp().IsZero() { - return resource, nil - } - - finalizers := sets.NewString(resource.Finalizers...) - - if reconcileEvent != nil { - var event *reconciler.ReconcilerEvent - if reconciler.EventAs(reconcileEvent, &event) { - if event.EventType == v1.EventTypeNormal { - finalizers.Delete(r.finalizerName) - } - } - } else { - finalizers.Delete(r.finalizerName) - } - - resource.Finalizers = finalizers.List() - - // Synchronize the finalizers filtered by r.finalizerName. - return r.updateFinalizersFiltered(ctx, resource) -} diff --git a/pkg/client/injection/reconciler/events/v1alpha1/cloudstoragesource/stub/controller.go b/pkg/client/injection/reconciler/events/v1alpha1/cloudstoragesource/stub/controller.go deleted file mode 100644 index 37b5c223b9..0000000000 --- a/pkg/client/injection/reconciler/events/v1alpha1/cloudstoragesource/stub/controller.go +++ /dev/null @@ -1,54 +0,0 @@ -/* -Copyright 2020 Google LLC - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -// Code generated by injection-gen. DO NOT EDIT. - -package cloudstoragesource - -import ( - context "context" - - cloudstoragesource "github.com/google/knative-gcp/pkg/client/injection/informers/events/v1alpha1/cloudstoragesource" - v1alpha1cloudstoragesource "github.com/google/knative-gcp/pkg/client/injection/reconciler/events/v1alpha1/cloudstoragesource" - configmap "knative.dev/pkg/configmap" - controller "knative.dev/pkg/controller" - logging "knative.dev/pkg/logging" -) - -// TODO: PLEASE COPY AND MODIFY THIS FILE AS A STARTING POINT - -// NewController creates a Reconciler for CloudStorageSource and returns the result of NewImpl. -func NewController( - ctx context.Context, - cmw configmap.Watcher, -) *controller.Impl { - logger := logging.FromContext(ctx) - - cloudstoragesourceInformer := cloudstoragesource.Get(ctx) - - // TODO: setup additional informers here. - - r := &Reconciler{} - impl := v1alpha1cloudstoragesource.NewImpl(ctx, r) - - logger.Info("Setting up event handlers.") - - cloudstoragesourceInformer.Informer().AddEventHandler(controller.HandleAll(impl.Enqueue)) - - // TODO: add additional informer event handlers here. - - return impl -} diff --git a/pkg/client/injection/reconciler/events/v1alpha1/cloudstoragesource/stub/reconciler.go b/pkg/client/injection/reconciler/events/v1alpha1/cloudstoragesource/stub/reconciler.go deleted file mode 100644 index cb0bb44fda..0000000000 --- a/pkg/client/injection/reconciler/events/v1alpha1/cloudstoragesource/stub/reconciler.go +++ /dev/null @@ -1,87 +0,0 @@ -/* -Copyright 2020 Google LLC - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -// Code generated by injection-gen. DO NOT EDIT. - -package cloudstoragesource - -import ( - context "context" - - v1alpha1 "github.com/google/knative-gcp/pkg/apis/events/v1alpha1" - cloudstoragesource "github.com/google/knative-gcp/pkg/client/injection/reconciler/events/v1alpha1/cloudstoragesource" - v1 "k8s.io/api/core/v1" - reconciler "knative.dev/pkg/reconciler" -) - -// TODO: PLEASE COPY AND MODIFY THIS FILE AS A STARTING POINT - -// newReconciledNormal makes a new reconciler event with event type Normal, and -// reason CloudStorageSourceReconciled. -func newReconciledNormal(namespace, name string) reconciler.Event { - return reconciler.NewEvent(v1.EventTypeNormal, "CloudStorageSourceReconciled", "CloudStorageSource reconciled: \"%s/%s\"", namespace, name) -} - -// Reconciler implements controller.Reconciler for CloudStorageSource resources. -type Reconciler struct { - // TODO: add additional requirements here. -} - -// Check that our Reconciler implements Interface -var _ cloudstoragesource.Interface = (*Reconciler)(nil) - -// Optionally check that our Reconciler implements Finalizer -//var _ cloudstoragesource.Finalizer = (*Reconciler)(nil) - -// Optionally check that our Reconciler implements ReadOnlyInterface -// Implement this to observe resources even when we are not the leader. -//var _ cloudstoragesource.ReadOnlyInterface = (*Reconciler)(nil) - -// Optionally check that our Reconciler implements ReadOnlyFinalizer -// Implement this to observe tombstoned resources even when we are not -// the leader (best effort). -//var _ cloudstoragesource.ReadOnlyFinalizer = (*Reconciler)(nil) - -// ReconcileKind implements Interface.ReconcileKind. -func (r *Reconciler) ReconcileKind(ctx context.Context, o *v1alpha1.CloudStorageSource) reconciler.Event { - // TODO: use this if the resource implements InitializeConditions. - // o.Status.InitializeConditions() - - // TODO: add custom reconciliation logic here. - - // TODO: use this if the object has .status.ObservedGeneration. - // o.Status.ObservedGeneration = o.Generation - return newReconciledNormal(o.Namespace, o.Name) -} - -// Optionally, use FinalizeKind to add finalizers. FinalizeKind will be called -// when the resource is deleted. -//func (r *Reconciler) FinalizeKind(ctx context.Context, o *v1alpha1.CloudStorageSource) reconciler.Event { -// // TODO: add custom finalization logic here. -// return nil -//} - -// Optionally, use ObserveKind to observe the resource when we are not the leader. -// func (r *Reconciler) ObserveKind(ctx context.Context, o *v1alpha1.CloudStorageSource) reconciler.Event { -// // TODO: add custom observation logic here. -// return nil -// } - -// Optionally, use ObserveFinalizeKind to observe resources being finalized when we are no the leader. -//func (r *Reconciler) ObserveFinalizeKind(ctx context.Context, o *v1alpha1.CloudStorageSource) reconciler.Event { -// // TODO: add custom observation logic here. -// return nil -//} diff --git a/pkg/client/injection/reconciler/events/v1beta1/cloudauditlogssource/reconciler.go b/pkg/client/injection/reconciler/events/v1beta1/cloudauditlogssource/reconciler.go index a680ea494c..3a223148d3 100644 --- a/pkg/client/injection/reconciler/events/v1beta1/cloudauditlogssource/reconciler.go +++ b/pkg/client/injection/reconciler/events/v1beta1/cloudauditlogssource/reconciler.go @@ -225,10 +225,14 @@ func (r *reconcilerImpl) Reconcile(ctx context.Context, key string) error { return fmt.Errorf("failed to set finalizers: %w", err) } + reconciler.PreProcessReconcile(ctx, resource) + // Reconcile this copy of the resource and then write back any status // updates regardless of whether the reconciliation errored out. reconcileEvent = r.reconciler.ReconcileKind(ctx, resource) + reconciler.PostProcessReconcile(ctx, resource, original) + } else if isROI { // Append the target method to the logger. logger = logger.With(zap.String("targetMethod", "ObserveKind")) diff --git a/pkg/client/injection/reconciler/events/v1beta1/cloudbuildsource/reconciler.go b/pkg/client/injection/reconciler/events/v1beta1/cloudbuildsource/reconciler.go index dce2547438..593364d264 100644 --- a/pkg/client/injection/reconciler/events/v1beta1/cloudbuildsource/reconciler.go +++ b/pkg/client/injection/reconciler/events/v1beta1/cloudbuildsource/reconciler.go @@ -225,10 +225,14 @@ func (r *reconcilerImpl) Reconcile(ctx context.Context, key string) error { return fmt.Errorf("failed to set finalizers: %w", err) } + reconciler.PreProcessReconcile(ctx, resource) + // Reconcile this copy of the resource and then write back any status // updates regardless of whether the reconciliation errored out. reconcileEvent = r.reconciler.ReconcileKind(ctx, resource) + reconciler.PostProcessReconcile(ctx, resource, original) + } else if isROI { // Append the target method to the logger. logger = logger.With(zap.String("targetMethod", "ObserveKind")) diff --git a/pkg/client/injection/reconciler/events/v1beta1/cloudpubsubsource/reconciler.go b/pkg/client/injection/reconciler/events/v1beta1/cloudpubsubsource/reconciler.go index f639374529..d535195667 100644 --- a/pkg/client/injection/reconciler/events/v1beta1/cloudpubsubsource/reconciler.go +++ b/pkg/client/injection/reconciler/events/v1beta1/cloudpubsubsource/reconciler.go @@ -225,10 +225,14 @@ func (r *reconcilerImpl) Reconcile(ctx context.Context, key string) error { return fmt.Errorf("failed to set finalizers: %w", err) } + reconciler.PreProcessReconcile(ctx, resource) + // Reconcile this copy of the resource and then write back any status // updates regardless of whether the reconciliation errored out. reconcileEvent = r.reconciler.ReconcileKind(ctx, resource) + reconciler.PostProcessReconcile(ctx, resource, original) + } else if isROI { // Append the target method to the logger. logger = logger.With(zap.String("targetMethod", "ObserveKind")) diff --git a/pkg/client/injection/reconciler/events/v1beta1/cloudschedulersource/reconciler.go b/pkg/client/injection/reconciler/events/v1beta1/cloudschedulersource/reconciler.go index ed5208a6cb..7367d6c8af 100644 --- a/pkg/client/injection/reconciler/events/v1beta1/cloudschedulersource/reconciler.go +++ b/pkg/client/injection/reconciler/events/v1beta1/cloudschedulersource/reconciler.go @@ -225,10 +225,14 @@ func (r *reconcilerImpl) Reconcile(ctx context.Context, key string) error { return fmt.Errorf("failed to set finalizers: %w", err) } + reconciler.PreProcessReconcile(ctx, resource) + // Reconcile this copy of the resource and then write back any status // updates regardless of whether the reconciliation errored out. reconcileEvent = r.reconciler.ReconcileKind(ctx, resource) + reconciler.PostProcessReconcile(ctx, resource, original) + } else if isROI { // Append the target method to the logger. logger = logger.With(zap.String("targetMethod", "ObserveKind")) diff --git a/pkg/client/injection/reconciler/events/v1beta1/cloudstoragesource/reconciler.go b/pkg/client/injection/reconciler/events/v1beta1/cloudstoragesource/reconciler.go index 5168d853a7..b6b7c06e52 100644 --- a/pkg/client/injection/reconciler/events/v1beta1/cloudstoragesource/reconciler.go +++ b/pkg/client/injection/reconciler/events/v1beta1/cloudstoragesource/reconciler.go @@ -225,10 +225,14 @@ func (r *reconcilerImpl) Reconcile(ctx context.Context, key string) error { return fmt.Errorf("failed to set finalizers: %w", err) } + reconciler.PreProcessReconcile(ctx, resource) + // Reconcile this copy of the resource and then write back any status // updates regardless of whether the reconciliation errored out. reconcileEvent = r.reconciler.ReconcileKind(ctx, resource) + reconciler.PostProcessReconcile(ctx, resource, original) + } else if isROI { // Append the target method to the logger. logger = logger.With(zap.String("targetMethod", "ObserveKind")) diff --git a/pkg/client/injection/reconciler/intevents/v1alpha1/brokercell/reconciler.go b/pkg/client/injection/reconciler/intevents/v1alpha1/brokercell/reconciler.go index bac50c286c..39d678c1b4 100644 --- a/pkg/client/injection/reconciler/intevents/v1alpha1/brokercell/reconciler.go +++ b/pkg/client/injection/reconciler/intevents/v1alpha1/brokercell/reconciler.go @@ -225,10 +225,14 @@ func (r *reconcilerImpl) Reconcile(ctx context.Context, key string) error { return fmt.Errorf("failed to set finalizers: %w", err) } + reconciler.PreProcessReconcile(ctx, resource) + // Reconcile this copy of the resource and then write back any status // updates regardless of whether the reconciliation errored out. reconcileEvent = r.reconciler.ReconcileKind(ctx, resource) + reconciler.PostProcessReconcile(ctx, resource, original) + } else if isROI { // Append the target method to the logger. logger = logger.With(zap.String("targetMethod", "ObserveKind")) diff --git a/pkg/client/injection/reconciler/intevents/v1alpha1/pullsubscription/controller.go b/pkg/client/injection/reconciler/intevents/v1alpha1/pullsubscription/controller.go deleted file mode 100644 index 94e941440c..0000000000 --- a/pkg/client/injection/reconciler/intevents/v1alpha1/pullsubscription/controller.go +++ /dev/null @@ -1,139 +0,0 @@ -/* -Copyright 2020 Google LLC - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -// Code generated by injection-gen. DO NOT EDIT. - -package pullsubscription - -import ( - context "context" - fmt "fmt" - reflect "reflect" - strings "strings" - - versionedscheme "github.com/google/knative-gcp/pkg/client/clientset/versioned/scheme" - client "github.com/google/knative-gcp/pkg/client/injection/client" - pullsubscription "github.com/google/knative-gcp/pkg/client/injection/informers/intevents/v1alpha1/pullsubscription" - corev1 "k8s.io/api/core/v1" - labels "k8s.io/apimachinery/pkg/labels" - types "k8s.io/apimachinery/pkg/types" - watch "k8s.io/apimachinery/pkg/watch" - scheme "k8s.io/client-go/kubernetes/scheme" - v1 "k8s.io/client-go/kubernetes/typed/core/v1" - record "k8s.io/client-go/tools/record" - kubeclient "knative.dev/pkg/client/injection/kube/client" - controller "knative.dev/pkg/controller" - logging "knative.dev/pkg/logging" - reconciler "knative.dev/pkg/reconciler" -) - -const ( - defaultControllerAgentName = "pullsubscription-controller" - defaultFinalizerName = "pullsubscriptions.internal.events.cloud.google.com" -) - -// NewImpl returns a controller.Impl that handles queuing and feeding work from -// the queue through an implementation of controller.Reconciler, delegating to -// the provided Interface and optional Finalizer methods. OptionsFn is used to return -// controller.Options to be used but the internal reconciler. -func NewImpl(ctx context.Context, r Interface, optionsFns ...controller.OptionsFn) *controller.Impl { - logger := logging.FromContext(ctx) - - // Check the options function input. It should be 0 or 1. - if len(optionsFns) > 1 { - logger.Fatalf("up to one options function is supported, found %d", len(optionsFns)) - } - - pullsubscriptionInformer := pullsubscription.Get(ctx) - - lister := pullsubscriptionInformer.Lister() - - rec := &reconcilerImpl{ - LeaderAwareFuncs: reconciler.LeaderAwareFuncs{ - PromoteFunc: func(bkt reconciler.Bucket, enq func(reconciler.Bucket, types.NamespacedName)) error { - all, err := lister.List(labels.Everything()) - if err != nil { - return err - } - for _, elt := range all { - // TODO: Consider letting users specify a filter in options. - enq(bkt, types.NamespacedName{ - Namespace: elt.GetNamespace(), - Name: elt.GetName(), - }) - } - return nil - }, - }, - Client: client.Get(ctx), - Lister: lister, - reconciler: r, - finalizerName: defaultFinalizerName, - } - - t := reflect.TypeOf(r).Elem() - queueName := fmt.Sprintf("%s.%s", strings.ReplaceAll(t.PkgPath(), "/", "-"), t.Name()) - - impl := controller.NewImpl(rec, logger, queueName) - agentName := defaultControllerAgentName - - // Pass impl to the options. Save any optional results. - for _, fn := range optionsFns { - opts := fn(impl) - if opts.ConfigStore != nil { - rec.configStore = opts.ConfigStore - } - if opts.FinalizerName != "" { - rec.finalizerName = opts.FinalizerName - } - if opts.AgentName != "" { - agentName = opts.AgentName - } - } - - rec.Recorder = createRecorder(ctx, agentName) - - return impl -} - -func createRecorder(ctx context.Context, agentName string) record.EventRecorder { - logger := logging.FromContext(ctx) - - recorder := controller.GetEventRecorder(ctx) - if recorder == nil { - // Create event broadcaster - logger.Debug("Creating event broadcaster") - eventBroadcaster := record.NewBroadcaster() - watches := []watch.Interface{ - eventBroadcaster.StartLogging(logger.Named("event-broadcaster").Infof), - eventBroadcaster.StartRecordingToSink( - &v1.EventSinkImpl{Interface: kubeclient.Get(ctx).CoreV1().Events("")}), - } - recorder = eventBroadcaster.NewRecorder(scheme.Scheme, corev1.EventSource{Component: agentName}) - go func() { - <-ctx.Done() - for _, w := range watches { - w.Stop() - } - }() - } - - return recorder -} - -func init() { - versionedscheme.AddToScheme(scheme.Scheme) -} diff --git a/pkg/client/injection/reconciler/intevents/v1alpha1/pullsubscription/reconciler.go b/pkg/client/injection/reconciler/intevents/v1alpha1/pullsubscription/reconciler.go deleted file mode 100644 index a786be75c5..0000000000 --- a/pkg/client/injection/reconciler/intevents/v1alpha1/pullsubscription/reconciler.go +++ /dev/null @@ -1,430 +0,0 @@ -/* -Copyright 2020 Google LLC - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -// Code generated by injection-gen. DO NOT EDIT. - -package pullsubscription - -import ( - context "context" - json "encoding/json" - fmt "fmt" - reflect "reflect" - - v1alpha1 "github.com/google/knative-gcp/pkg/apis/intevents/v1alpha1" - versioned "github.com/google/knative-gcp/pkg/client/clientset/versioned" - inteventsv1alpha1 "github.com/google/knative-gcp/pkg/client/listers/intevents/v1alpha1" - zap "go.uber.org/zap" - v1 "k8s.io/api/core/v1" - equality "k8s.io/apimachinery/pkg/api/equality" - errors "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - labels "k8s.io/apimachinery/pkg/labels" - types "k8s.io/apimachinery/pkg/types" - sets "k8s.io/apimachinery/pkg/util/sets" - cache "k8s.io/client-go/tools/cache" - record "k8s.io/client-go/tools/record" - controller "knative.dev/pkg/controller" - logging "knative.dev/pkg/logging" - reconciler "knative.dev/pkg/reconciler" -) - -// Interface defines the strongly typed interfaces to be implemented by a -// controller reconciling v1alpha1.PullSubscription. -type Interface interface { - // ReconcileKind implements custom logic to reconcile v1alpha1.PullSubscription. Any changes - // to the objects .Status or .Finalizers will be propagated to the stored - // object. It is recommended that implementors do not call any update calls - // for the Kind inside of ReconcileKind, it is the responsibility of the calling - // controller to propagate those properties. The resource passed to ReconcileKind - // will always have an empty deletion timestamp. - ReconcileKind(ctx context.Context, o *v1alpha1.PullSubscription) reconciler.Event -} - -// Finalizer defines the strongly typed interfaces to be implemented by a -// controller finalizing v1alpha1.PullSubscription. -type Finalizer interface { - // FinalizeKind implements custom logic to finalize v1alpha1.PullSubscription. Any changes - // to the objects .Status or .Finalizers will be ignored. Returning a nil or - // Normal type reconciler.Event will allow the finalizer to be deleted on - // the resource. The resource passed to FinalizeKind will always have a set - // deletion timestamp. - FinalizeKind(ctx context.Context, o *v1alpha1.PullSubscription) reconciler.Event -} - -// ReadOnlyInterface defines the strongly typed interfaces to be implemented by a -// controller reconciling v1alpha1.PullSubscription if they want to process resources for which -// they are not the leader. -type ReadOnlyInterface interface { - // ObserveKind implements logic to observe v1alpha1.PullSubscription. - // This method should not write to the API. - ObserveKind(ctx context.Context, o *v1alpha1.PullSubscription) reconciler.Event -} - -// ReadOnlyFinalizer defines the strongly typed interfaces to be implemented by a -// controller finalizing v1alpha1.PullSubscription if they want to process tombstoned resources -// even when they are not the leader. Due to the nature of how finalizers are handled -// there are no guarantees that this will be called. -type ReadOnlyFinalizer interface { - // ObserveFinalizeKind implements custom logic to observe the final state of v1alpha1.PullSubscription. - // This method should not write to the API. - ObserveFinalizeKind(ctx context.Context, o *v1alpha1.PullSubscription) reconciler.Event -} - -// reconcilerImpl implements controller.Reconciler for v1alpha1.PullSubscription resources. -type reconcilerImpl struct { - // LeaderAwareFuncs is inlined to help us implement reconciler.LeaderAware - reconciler.LeaderAwareFuncs - - // Client is used to write back status updates. - Client versioned.Interface - - // Listers index properties about resources - Lister inteventsv1alpha1.PullSubscriptionLister - - // Recorder is an event recorder for recording Event resources to the - // Kubernetes API. - Recorder record.EventRecorder - - // configStore allows for decorating a context with config maps. - // +optional - configStore reconciler.ConfigStore - - // reconciler is the implementation of the business logic of the resource. - reconciler Interface - - // finalizerName is the name of the finalizer to reconcile. - finalizerName string -} - -// Check that our Reconciler implements controller.Reconciler -var _ controller.Reconciler = (*reconcilerImpl)(nil) - -// Check that our generated Reconciler is always LeaderAware. -var _ reconciler.LeaderAware = (*reconcilerImpl)(nil) - -func NewReconciler(ctx context.Context, logger *zap.SugaredLogger, client versioned.Interface, lister inteventsv1alpha1.PullSubscriptionLister, recorder record.EventRecorder, r Interface, options ...controller.Options) controller.Reconciler { - // Check the options function input. It should be 0 or 1. - if len(options) > 1 { - logger.Fatalf("up to one options struct is supported, found %d", len(options)) - } - - // Fail fast when users inadvertently implement the other LeaderAware interface. - // For the typed reconcilers, Promote shouldn't take any arguments. - if _, ok := r.(reconciler.LeaderAware); ok { - logger.Fatalf("%T implements the incorrect LeaderAware interface. Promote() should not take an argument as genreconciler handles the enqueuing automatically.", r) - } - // TODO: Consider validating when folks implement ReadOnlyFinalizer, but not Finalizer. - - rec := &reconcilerImpl{ - LeaderAwareFuncs: reconciler.LeaderAwareFuncs{ - PromoteFunc: func(bkt reconciler.Bucket, enq func(reconciler.Bucket, types.NamespacedName)) error { - all, err := lister.List(labels.Everything()) - if err != nil { - return err - } - for _, elt := range all { - // TODO: Consider letting users specify a filter in options. - enq(bkt, types.NamespacedName{ - Namespace: elt.GetNamespace(), - Name: elt.GetName(), - }) - } - return nil - }, - }, - Client: client, - Lister: lister, - Recorder: recorder, - reconciler: r, - finalizerName: defaultFinalizerName, - } - - for _, opts := range options { - if opts.ConfigStore != nil { - rec.configStore = opts.ConfigStore - } - if opts.FinalizerName != "" { - rec.finalizerName = opts.FinalizerName - } - } - - return rec -} - -// Reconcile implements controller.Reconciler -func (r *reconcilerImpl) Reconcile(ctx context.Context, key string) error { - logger := logging.FromContext(ctx) - - // Convert the namespace/name string into a distinct namespace and name - namespace, name, err := cache.SplitMetaNamespaceKey(key) - if err != nil { - logger.Errorf("invalid resource key: %s", key) - return nil - } - // Establish whether we are the leader for use below. - isLeader := r.IsLeaderFor(types.NamespacedName{ - Namespace: namespace, - Name: name, - }) - roi, isROI := r.reconciler.(ReadOnlyInterface) - rof, isROF := r.reconciler.(ReadOnlyFinalizer) - if !isLeader && !isROI && !isROF { - // If we are not the leader, and we don't implement either ReadOnly - // interface, then take a fast-path out. - return nil - } - - // If configStore is set, attach the frozen configuration to the context. - if r.configStore != nil { - ctx = r.configStore.ToContext(ctx) - } - - // Add the recorder to context. - ctx = controller.WithEventRecorder(ctx, r.Recorder) - - // Get the resource with this namespace/name. - - getter := r.Lister.PullSubscriptions(namespace) - - original, err := getter.Get(name) - - if errors.IsNotFound(err) { - // The resource may no longer exist, in which case we stop processing. - logger.Debugf("resource %q no longer exists", key) - return nil - } else if err != nil { - return err - } - - // Don't modify the informers copy. - resource := original.DeepCopy() - - var reconcileEvent reconciler.Event - if resource.GetDeletionTimestamp().IsZero() { - if isLeader { - // Append the target method to the logger. - logger = logger.With(zap.String("targetMethod", "ReconcileKind")) - - // Set and update the finalizer on resource if r.reconciler - // implements Finalizer. - if resource, err = r.setFinalizerIfFinalizer(ctx, resource); err != nil { - return fmt.Errorf("failed to set finalizers: %w", err) - } - - // Reconcile this copy of the resource and then write back any status - // updates regardless of whether the reconciliation errored out. - reconcileEvent = r.reconciler.ReconcileKind(ctx, resource) - - } else if isROI { - // Append the target method to the logger. - logger = logger.With(zap.String("targetMethod", "ObserveKind")) - - // Observe any changes to this resource, since we are not the leader. - reconcileEvent = roi.ObserveKind(ctx, resource) - } - } else if fin, ok := r.reconciler.(Finalizer); isLeader && ok { - // Append the target method to the logger. - logger = logger.With(zap.String("targetMethod", "FinalizeKind")) - - // For finalizing reconcilers, if this resource being marked for deletion - // and reconciled cleanly (nil or normal event), remove the finalizer. - reconcileEvent = fin.FinalizeKind(ctx, resource) - if resource, err = r.clearFinalizer(ctx, resource, reconcileEvent); err != nil { - return fmt.Errorf("failed to clear finalizers: %w", err) - } - } else if !isLeader && isROF { - // Append the target method to the logger. - logger = logger.With(zap.String("targetMethod", "ObserveFinalizeKind")) - - // For finalizing reconcilers, just observe when we aren't the leader. - reconcileEvent = rof.ObserveFinalizeKind(ctx, resource) - } - - // Synchronize the status. - if equality.Semantic.DeepEqual(original.Status, resource.Status) { - // If we didn't change anything then don't call updateStatus. - // This is important because the copy we loaded from the injectionInformer's - // cache may be stale and we don't want to overwrite a prior update - // to status with this stale state. - } else if !isLeader { - logger.Warn("Saw status changes when we aren't the leader!") - // TODO: Consider logging the diff at Debug? - } else if err = r.updateStatus(original, resource); err != nil { - logger.Warnw("Failed to update resource status", zap.Error(err)) - r.Recorder.Eventf(resource, v1.EventTypeWarning, "UpdateFailed", - "Failed to update status for %q: %v", resource.Name, err) - return err - } - - // Report the reconciler event, if any. - if reconcileEvent != nil { - var event *reconciler.ReconcilerEvent - if reconciler.EventAs(reconcileEvent, &event) { - logger.Infow("Returned an event", zap.Any("event", reconcileEvent)) - r.Recorder.Eventf(resource, event.EventType, event.Reason, event.Format, event.Args...) - - // the event was wrapped inside an error, consider the reconciliation as failed - if _, isEvent := reconcileEvent.(*reconciler.ReconcilerEvent); !isEvent { - return reconcileEvent - } - return nil - } - - logger.Errorw("Returned an error", zap.Error(reconcileEvent)) - r.Recorder.Event(resource, v1.EventTypeWarning, "InternalError", reconcileEvent.Error()) - return reconcileEvent - } - - return nil -} - -func (r *reconcilerImpl) updateStatus(existing *v1alpha1.PullSubscription, desired *v1alpha1.PullSubscription) error { - existing = existing.DeepCopy() - return reconciler.RetryUpdateConflicts(func(attempts int) (err error) { - // The first iteration tries to use the injectionInformer's state, subsequent attempts fetch the latest state via API. - if attempts > 0 { - - getter := r.Client.InternalV1alpha1().PullSubscriptions(desired.Namespace) - - existing, err = getter.Get(desired.Name, metav1.GetOptions{}) - if err != nil { - return err - } - } - - // If there's nothing to update, just return. - if reflect.DeepEqual(existing.Status, desired.Status) { - return nil - } - - existing.Status = desired.Status - - updater := r.Client.InternalV1alpha1().PullSubscriptions(existing.Namespace) - - _, err = updater.UpdateStatus(existing) - return err - }) -} - -// updateFinalizersFiltered will update the Finalizers of the resource. -// TODO: this method could be generic and sync all finalizers. For now it only -// updates defaultFinalizerName or its override. -func (r *reconcilerImpl) updateFinalizersFiltered(ctx context.Context, resource *v1alpha1.PullSubscription) (*v1alpha1.PullSubscription, error) { - - getter := r.Lister.PullSubscriptions(resource.Namespace) - - actual, err := getter.Get(resource.Name) - if err != nil { - return resource, err - } - - // Don't modify the informers copy. - existing := actual.DeepCopy() - - var finalizers []string - - // If there's nothing to update, just return. - existingFinalizers := sets.NewString(existing.Finalizers...) - desiredFinalizers := sets.NewString(resource.Finalizers...) - - if desiredFinalizers.Has(r.finalizerName) { - if existingFinalizers.Has(r.finalizerName) { - // Nothing to do. - return resource, nil - } - // Add the finalizer. - finalizers = append(existing.Finalizers, r.finalizerName) - } else { - if !existingFinalizers.Has(r.finalizerName) { - // Nothing to do. - return resource, nil - } - // Remove the finalizer. - existingFinalizers.Delete(r.finalizerName) - finalizers = existingFinalizers.List() - } - - mergePatch := map[string]interface{}{ - "metadata": map[string]interface{}{ - "finalizers": finalizers, - "resourceVersion": existing.ResourceVersion, - }, - } - - patch, err := json.Marshal(mergePatch) - if err != nil { - return resource, err - } - - patcher := r.Client.InternalV1alpha1().PullSubscriptions(resource.Namespace) - - resourceName := resource.Name - resource, err = patcher.Patch(resourceName, types.MergePatchType, patch) - if err != nil { - r.Recorder.Eventf(resource, v1.EventTypeWarning, "FinalizerUpdateFailed", - "Failed to update finalizers for %q: %v", resourceName, err) - } else { - r.Recorder.Eventf(resource, v1.EventTypeNormal, "FinalizerUpdate", - "Updated %q finalizers", resource.GetName()) - } - return resource, err -} - -func (r *reconcilerImpl) setFinalizerIfFinalizer(ctx context.Context, resource *v1alpha1.PullSubscription) (*v1alpha1.PullSubscription, error) { - if _, ok := r.reconciler.(Finalizer); !ok { - return resource, nil - } - - finalizers := sets.NewString(resource.Finalizers...) - - // If this resource is not being deleted, mark the finalizer. - if resource.GetDeletionTimestamp().IsZero() { - finalizers.Insert(r.finalizerName) - } - - resource.Finalizers = finalizers.List() - - // Synchronize the finalizers filtered by r.finalizerName. - return r.updateFinalizersFiltered(ctx, resource) -} - -func (r *reconcilerImpl) clearFinalizer(ctx context.Context, resource *v1alpha1.PullSubscription, reconcileEvent reconciler.Event) (*v1alpha1.PullSubscription, error) { - if _, ok := r.reconciler.(Finalizer); !ok { - return resource, nil - } - if resource.GetDeletionTimestamp().IsZero() { - return resource, nil - } - - finalizers := sets.NewString(resource.Finalizers...) - - if reconcileEvent != nil { - var event *reconciler.ReconcilerEvent - if reconciler.EventAs(reconcileEvent, &event) { - if event.EventType == v1.EventTypeNormal { - finalizers.Delete(r.finalizerName) - } - } - } else { - finalizers.Delete(r.finalizerName) - } - - resource.Finalizers = finalizers.List() - - // Synchronize the finalizers filtered by r.finalizerName. - return r.updateFinalizersFiltered(ctx, resource) -} diff --git a/pkg/client/injection/reconciler/intevents/v1alpha1/pullsubscription/stub/controller.go b/pkg/client/injection/reconciler/intevents/v1alpha1/pullsubscription/stub/controller.go deleted file mode 100644 index 4e3c8b1724..0000000000 --- a/pkg/client/injection/reconciler/intevents/v1alpha1/pullsubscription/stub/controller.go +++ /dev/null @@ -1,54 +0,0 @@ -/* -Copyright 2020 Google LLC - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -// Code generated by injection-gen. DO NOT EDIT. - -package pullsubscription - -import ( - context "context" - - pullsubscription "github.com/google/knative-gcp/pkg/client/injection/informers/intevents/v1alpha1/pullsubscription" - v1alpha1pullsubscription "github.com/google/knative-gcp/pkg/client/injection/reconciler/intevents/v1alpha1/pullsubscription" - configmap "knative.dev/pkg/configmap" - controller "knative.dev/pkg/controller" - logging "knative.dev/pkg/logging" -) - -// TODO: PLEASE COPY AND MODIFY THIS FILE AS A STARTING POINT - -// NewController creates a Reconciler for PullSubscription and returns the result of NewImpl. -func NewController( - ctx context.Context, - cmw configmap.Watcher, -) *controller.Impl { - logger := logging.FromContext(ctx) - - pullsubscriptionInformer := pullsubscription.Get(ctx) - - // TODO: setup additional informers here. - - r := &Reconciler{} - impl := v1alpha1pullsubscription.NewImpl(ctx, r) - - logger.Info("Setting up event handlers.") - - pullsubscriptionInformer.Informer().AddEventHandler(controller.HandleAll(impl.Enqueue)) - - // TODO: add additional informer event handlers here. - - return impl -} diff --git a/pkg/client/injection/reconciler/intevents/v1alpha1/pullsubscription/stub/reconciler.go b/pkg/client/injection/reconciler/intevents/v1alpha1/pullsubscription/stub/reconciler.go deleted file mode 100644 index c1b6c82a61..0000000000 --- a/pkg/client/injection/reconciler/intevents/v1alpha1/pullsubscription/stub/reconciler.go +++ /dev/null @@ -1,87 +0,0 @@ -/* -Copyright 2020 Google LLC - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -// Code generated by injection-gen. DO NOT EDIT. - -package pullsubscription - -import ( - context "context" - - v1alpha1 "github.com/google/knative-gcp/pkg/apis/intevents/v1alpha1" - pullsubscription "github.com/google/knative-gcp/pkg/client/injection/reconciler/intevents/v1alpha1/pullsubscription" - v1 "k8s.io/api/core/v1" - reconciler "knative.dev/pkg/reconciler" -) - -// TODO: PLEASE COPY AND MODIFY THIS FILE AS A STARTING POINT - -// newReconciledNormal makes a new reconciler event with event type Normal, and -// reason PullSubscriptionReconciled. -func newReconciledNormal(namespace, name string) reconciler.Event { - return reconciler.NewEvent(v1.EventTypeNormal, "PullSubscriptionReconciled", "PullSubscription reconciled: \"%s/%s\"", namespace, name) -} - -// Reconciler implements controller.Reconciler for PullSubscription resources. -type Reconciler struct { - // TODO: add additional requirements here. -} - -// Check that our Reconciler implements Interface -var _ pullsubscription.Interface = (*Reconciler)(nil) - -// Optionally check that our Reconciler implements Finalizer -//var _ pullsubscription.Finalizer = (*Reconciler)(nil) - -// Optionally check that our Reconciler implements ReadOnlyInterface -// Implement this to observe resources even when we are not the leader. -//var _ pullsubscription.ReadOnlyInterface = (*Reconciler)(nil) - -// Optionally check that our Reconciler implements ReadOnlyFinalizer -// Implement this to observe tombstoned resources even when we are not -// the leader (best effort). -//var _ pullsubscription.ReadOnlyFinalizer = (*Reconciler)(nil) - -// ReconcileKind implements Interface.ReconcileKind. -func (r *Reconciler) ReconcileKind(ctx context.Context, o *v1alpha1.PullSubscription) reconciler.Event { - // TODO: use this if the resource implements InitializeConditions. - // o.Status.InitializeConditions() - - // TODO: add custom reconciliation logic here. - - // TODO: use this if the object has .status.ObservedGeneration. - // o.Status.ObservedGeneration = o.Generation - return newReconciledNormal(o.Namespace, o.Name) -} - -// Optionally, use FinalizeKind to add finalizers. FinalizeKind will be called -// when the resource is deleted. -//func (r *Reconciler) FinalizeKind(ctx context.Context, o *v1alpha1.PullSubscription) reconciler.Event { -// // TODO: add custom finalization logic here. -// return nil -//} - -// Optionally, use ObserveKind to observe the resource when we are not the leader. -// func (r *Reconciler) ObserveKind(ctx context.Context, o *v1alpha1.PullSubscription) reconciler.Event { -// // TODO: add custom observation logic here. -// return nil -// } - -// Optionally, use ObserveFinalizeKind to observe resources being finalized when we are no the leader. -//func (r *Reconciler) ObserveFinalizeKind(ctx context.Context, o *v1alpha1.PullSubscription) reconciler.Event { -// // TODO: add custom observation logic here. -// return nil -//} diff --git a/pkg/client/injection/reconciler/intevents/v1alpha1/topic/controller.go b/pkg/client/injection/reconciler/intevents/v1alpha1/topic/controller.go deleted file mode 100644 index 73f252b0c0..0000000000 --- a/pkg/client/injection/reconciler/intevents/v1alpha1/topic/controller.go +++ /dev/null @@ -1,139 +0,0 @@ -/* -Copyright 2020 Google LLC - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -// Code generated by injection-gen. DO NOT EDIT. - -package topic - -import ( - context "context" - fmt "fmt" - reflect "reflect" - strings "strings" - - versionedscheme "github.com/google/knative-gcp/pkg/client/clientset/versioned/scheme" - client "github.com/google/knative-gcp/pkg/client/injection/client" - topic "github.com/google/knative-gcp/pkg/client/injection/informers/intevents/v1alpha1/topic" - corev1 "k8s.io/api/core/v1" - labels "k8s.io/apimachinery/pkg/labels" - types "k8s.io/apimachinery/pkg/types" - watch "k8s.io/apimachinery/pkg/watch" - scheme "k8s.io/client-go/kubernetes/scheme" - v1 "k8s.io/client-go/kubernetes/typed/core/v1" - record "k8s.io/client-go/tools/record" - kubeclient "knative.dev/pkg/client/injection/kube/client" - controller "knative.dev/pkg/controller" - logging "knative.dev/pkg/logging" - reconciler "knative.dev/pkg/reconciler" -) - -const ( - defaultControllerAgentName = "topic-controller" - defaultFinalizerName = "topics.internal.events.cloud.google.com" -) - -// NewImpl returns a controller.Impl that handles queuing and feeding work from -// the queue through an implementation of controller.Reconciler, delegating to -// the provided Interface and optional Finalizer methods. OptionsFn is used to return -// controller.Options to be used but the internal reconciler. -func NewImpl(ctx context.Context, r Interface, optionsFns ...controller.OptionsFn) *controller.Impl { - logger := logging.FromContext(ctx) - - // Check the options function input. It should be 0 or 1. - if len(optionsFns) > 1 { - logger.Fatalf("up to one options function is supported, found %d", len(optionsFns)) - } - - topicInformer := topic.Get(ctx) - - lister := topicInformer.Lister() - - rec := &reconcilerImpl{ - LeaderAwareFuncs: reconciler.LeaderAwareFuncs{ - PromoteFunc: func(bkt reconciler.Bucket, enq func(reconciler.Bucket, types.NamespacedName)) error { - all, err := lister.List(labels.Everything()) - if err != nil { - return err - } - for _, elt := range all { - // TODO: Consider letting users specify a filter in options. - enq(bkt, types.NamespacedName{ - Namespace: elt.GetNamespace(), - Name: elt.GetName(), - }) - } - return nil - }, - }, - Client: client.Get(ctx), - Lister: lister, - reconciler: r, - finalizerName: defaultFinalizerName, - } - - t := reflect.TypeOf(r).Elem() - queueName := fmt.Sprintf("%s.%s", strings.ReplaceAll(t.PkgPath(), "/", "-"), t.Name()) - - impl := controller.NewImpl(rec, logger, queueName) - agentName := defaultControllerAgentName - - // Pass impl to the options. Save any optional results. - for _, fn := range optionsFns { - opts := fn(impl) - if opts.ConfigStore != nil { - rec.configStore = opts.ConfigStore - } - if opts.FinalizerName != "" { - rec.finalizerName = opts.FinalizerName - } - if opts.AgentName != "" { - agentName = opts.AgentName - } - } - - rec.Recorder = createRecorder(ctx, agentName) - - return impl -} - -func createRecorder(ctx context.Context, agentName string) record.EventRecorder { - logger := logging.FromContext(ctx) - - recorder := controller.GetEventRecorder(ctx) - if recorder == nil { - // Create event broadcaster - logger.Debug("Creating event broadcaster") - eventBroadcaster := record.NewBroadcaster() - watches := []watch.Interface{ - eventBroadcaster.StartLogging(logger.Named("event-broadcaster").Infof), - eventBroadcaster.StartRecordingToSink( - &v1.EventSinkImpl{Interface: kubeclient.Get(ctx).CoreV1().Events("")}), - } - recorder = eventBroadcaster.NewRecorder(scheme.Scheme, corev1.EventSource{Component: agentName}) - go func() { - <-ctx.Done() - for _, w := range watches { - w.Stop() - } - }() - } - - return recorder -} - -func init() { - versionedscheme.AddToScheme(scheme.Scheme) -} diff --git a/pkg/client/injection/reconciler/intevents/v1alpha1/topic/reconciler.go b/pkg/client/injection/reconciler/intevents/v1alpha1/topic/reconciler.go deleted file mode 100644 index 22187cd984..0000000000 --- a/pkg/client/injection/reconciler/intevents/v1alpha1/topic/reconciler.go +++ /dev/null @@ -1,430 +0,0 @@ -/* -Copyright 2020 Google LLC - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -// Code generated by injection-gen. DO NOT EDIT. - -package topic - -import ( - context "context" - json "encoding/json" - fmt "fmt" - reflect "reflect" - - v1alpha1 "github.com/google/knative-gcp/pkg/apis/intevents/v1alpha1" - versioned "github.com/google/knative-gcp/pkg/client/clientset/versioned" - inteventsv1alpha1 "github.com/google/knative-gcp/pkg/client/listers/intevents/v1alpha1" - zap "go.uber.org/zap" - v1 "k8s.io/api/core/v1" - equality "k8s.io/apimachinery/pkg/api/equality" - errors "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - labels "k8s.io/apimachinery/pkg/labels" - types "k8s.io/apimachinery/pkg/types" - sets "k8s.io/apimachinery/pkg/util/sets" - cache "k8s.io/client-go/tools/cache" - record "k8s.io/client-go/tools/record" - controller "knative.dev/pkg/controller" - logging "knative.dev/pkg/logging" - reconciler "knative.dev/pkg/reconciler" -) - -// Interface defines the strongly typed interfaces to be implemented by a -// controller reconciling v1alpha1.Topic. -type Interface interface { - // ReconcileKind implements custom logic to reconcile v1alpha1.Topic. Any changes - // to the objects .Status or .Finalizers will be propagated to the stored - // object. It is recommended that implementors do not call any update calls - // for the Kind inside of ReconcileKind, it is the responsibility of the calling - // controller to propagate those properties. The resource passed to ReconcileKind - // will always have an empty deletion timestamp. - ReconcileKind(ctx context.Context, o *v1alpha1.Topic) reconciler.Event -} - -// Finalizer defines the strongly typed interfaces to be implemented by a -// controller finalizing v1alpha1.Topic. -type Finalizer interface { - // FinalizeKind implements custom logic to finalize v1alpha1.Topic. Any changes - // to the objects .Status or .Finalizers will be ignored. Returning a nil or - // Normal type reconciler.Event will allow the finalizer to be deleted on - // the resource. The resource passed to FinalizeKind will always have a set - // deletion timestamp. - FinalizeKind(ctx context.Context, o *v1alpha1.Topic) reconciler.Event -} - -// ReadOnlyInterface defines the strongly typed interfaces to be implemented by a -// controller reconciling v1alpha1.Topic if they want to process resources for which -// they are not the leader. -type ReadOnlyInterface interface { - // ObserveKind implements logic to observe v1alpha1.Topic. - // This method should not write to the API. - ObserveKind(ctx context.Context, o *v1alpha1.Topic) reconciler.Event -} - -// ReadOnlyFinalizer defines the strongly typed interfaces to be implemented by a -// controller finalizing v1alpha1.Topic if they want to process tombstoned resources -// even when they are not the leader. Due to the nature of how finalizers are handled -// there are no guarantees that this will be called. -type ReadOnlyFinalizer interface { - // ObserveFinalizeKind implements custom logic to observe the final state of v1alpha1.Topic. - // This method should not write to the API. - ObserveFinalizeKind(ctx context.Context, o *v1alpha1.Topic) reconciler.Event -} - -// reconcilerImpl implements controller.Reconciler for v1alpha1.Topic resources. -type reconcilerImpl struct { - // LeaderAwareFuncs is inlined to help us implement reconciler.LeaderAware - reconciler.LeaderAwareFuncs - - // Client is used to write back status updates. - Client versioned.Interface - - // Listers index properties about resources - Lister inteventsv1alpha1.TopicLister - - // Recorder is an event recorder for recording Event resources to the - // Kubernetes API. - Recorder record.EventRecorder - - // configStore allows for decorating a context with config maps. - // +optional - configStore reconciler.ConfigStore - - // reconciler is the implementation of the business logic of the resource. - reconciler Interface - - // finalizerName is the name of the finalizer to reconcile. - finalizerName string -} - -// Check that our Reconciler implements controller.Reconciler -var _ controller.Reconciler = (*reconcilerImpl)(nil) - -// Check that our generated Reconciler is always LeaderAware. -var _ reconciler.LeaderAware = (*reconcilerImpl)(nil) - -func NewReconciler(ctx context.Context, logger *zap.SugaredLogger, client versioned.Interface, lister inteventsv1alpha1.TopicLister, recorder record.EventRecorder, r Interface, options ...controller.Options) controller.Reconciler { - // Check the options function input. It should be 0 or 1. - if len(options) > 1 { - logger.Fatalf("up to one options struct is supported, found %d", len(options)) - } - - // Fail fast when users inadvertently implement the other LeaderAware interface. - // For the typed reconcilers, Promote shouldn't take any arguments. - if _, ok := r.(reconciler.LeaderAware); ok { - logger.Fatalf("%T implements the incorrect LeaderAware interface. Promote() should not take an argument as genreconciler handles the enqueuing automatically.", r) - } - // TODO: Consider validating when folks implement ReadOnlyFinalizer, but not Finalizer. - - rec := &reconcilerImpl{ - LeaderAwareFuncs: reconciler.LeaderAwareFuncs{ - PromoteFunc: func(bkt reconciler.Bucket, enq func(reconciler.Bucket, types.NamespacedName)) error { - all, err := lister.List(labels.Everything()) - if err != nil { - return err - } - for _, elt := range all { - // TODO: Consider letting users specify a filter in options. - enq(bkt, types.NamespacedName{ - Namespace: elt.GetNamespace(), - Name: elt.GetName(), - }) - } - return nil - }, - }, - Client: client, - Lister: lister, - Recorder: recorder, - reconciler: r, - finalizerName: defaultFinalizerName, - } - - for _, opts := range options { - if opts.ConfigStore != nil { - rec.configStore = opts.ConfigStore - } - if opts.FinalizerName != "" { - rec.finalizerName = opts.FinalizerName - } - } - - return rec -} - -// Reconcile implements controller.Reconciler -func (r *reconcilerImpl) Reconcile(ctx context.Context, key string) error { - logger := logging.FromContext(ctx) - - // Convert the namespace/name string into a distinct namespace and name - namespace, name, err := cache.SplitMetaNamespaceKey(key) - if err != nil { - logger.Errorf("invalid resource key: %s", key) - return nil - } - // Establish whether we are the leader for use below. - isLeader := r.IsLeaderFor(types.NamespacedName{ - Namespace: namespace, - Name: name, - }) - roi, isROI := r.reconciler.(ReadOnlyInterface) - rof, isROF := r.reconciler.(ReadOnlyFinalizer) - if !isLeader && !isROI && !isROF { - // If we are not the leader, and we don't implement either ReadOnly - // interface, then take a fast-path out. - return nil - } - - // If configStore is set, attach the frozen configuration to the context. - if r.configStore != nil { - ctx = r.configStore.ToContext(ctx) - } - - // Add the recorder to context. - ctx = controller.WithEventRecorder(ctx, r.Recorder) - - // Get the resource with this namespace/name. - - getter := r.Lister.Topics(namespace) - - original, err := getter.Get(name) - - if errors.IsNotFound(err) { - // The resource may no longer exist, in which case we stop processing. - logger.Debugf("resource %q no longer exists", key) - return nil - } else if err != nil { - return err - } - - // Don't modify the informers copy. - resource := original.DeepCopy() - - var reconcileEvent reconciler.Event - if resource.GetDeletionTimestamp().IsZero() { - if isLeader { - // Append the target method to the logger. - logger = logger.With(zap.String("targetMethod", "ReconcileKind")) - - // Set and update the finalizer on resource if r.reconciler - // implements Finalizer. - if resource, err = r.setFinalizerIfFinalizer(ctx, resource); err != nil { - return fmt.Errorf("failed to set finalizers: %w", err) - } - - // Reconcile this copy of the resource and then write back any status - // updates regardless of whether the reconciliation errored out. - reconcileEvent = r.reconciler.ReconcileKind(ctx, resource) - - } else if isROI { - // Append the target method to the logger. - logger = logger.With(zap.String("targetMethod", "ObserveKind")) - - // Observe any changes to this resource, since we are not the leader. - reconcileEvent = roi.ObserveKind(ctx, resource) - } - } else if fin, ok := r.reconciler.(Finalizer); isLeader && ok { - // Append the target method to the logger. - logger = logger.With(zap.String("targetMethod", "FinalizeKind")) - - // For finalizing reconcilers, if this resource being marked for deletion - // and reconciled cleanly (nil or normal event), remove the finalizer. - reconcileEvent = fin.FinalizeKind(ctx, resource) - if resource, err = r.clearFinalizer(ctx, resource, reconcileEvent); err != nil { - return fmt.Errorf("failed to clear finalizers: %w", err) - } - } else if !isLeader && isROF { - // Append the target method to the logger. - logger = logger.With(zap.String("targetMethod", "ObserveFinalizeKind")) - - // For finalizing reconcilers, just observe when we aren't the leader. - reconcileEvent = rof.ObserveFinalizeKind(ctx, resource) - } - - // Synchronize the status. - if equality.Semantic.DeepEqual(original.Status, resource.Status) { - // If we didn't change anything then don't call updateStatus. - // This is important because the copy we loaded from the injectionInformer's - // cache may be stale and we don't want to overwrite a prior update - // to status with this stale state. - } else if !isLeader { - logger.Warn("Saw status changes when we aren't the leader!") - // TODO: Consider logging the diff at Debug? - } else if err = r.updateStatus(original, resource); err != nil { - logger.Warnw("Failed to update resource status", zap.Error(err)) - r.Recorder.Eventf(resource, v1.EventTypeWarning, "UpdateFailed", - "Failed to update status for %q: %v", resource.Name, err) - return err - } - - // Report the reconciler event, if any. - if reconcileEvent != nil { - var event *reconciler.ReconcilerEvent - if reconciler.EventAs(reconcileEvent, &event) { - logger.Infow("Returned an event", zap.Any("event", reconcileEvent)) - r.Recorder.Eventf(resource, event.EventType, event.Reason, event.Format, event.Args...) - - // the event was wrapped inside an error, consider the reconciliation as failed - if _, isEvent := reconcileEvent.(*reconciler.ReconcilerEvent); !isEvent { - return reconcileEvent - } - return nil - } - - logger.Errorw("Returned an error", zap.Error(reconcileEvent)) - r.Recorder.Event(resource, v1.EventTypeWarning, "InternalError", reconcileEvent.Error()) - return reconcileEvent - } - - return nil -} - -func (r *reconcilerImpl) updateStatus(existing *v1alpha1.Topic, desired *v1alpha1.Topic) error { - existing = existing.DeepCopy() - return reconciler.RetryUpdateConflicts(func(attempts int) (err error) { - // The first iteration tries to use the injectionInformer's state, subsequent attempts fetch the latest state via API. - if attempts > 0 { - - getter := r.Client.InternalV1alpha1().Topics(desired.Namespace) - - existing, err = getter.Get(desired.Name, metav1.GetOptions{}) - if err != nil { - return err - } - } - - // If there's nothing to update, just return. - if reflect.DeepEqual(existing.Status, desired.Status) { - return nil - } - - existing.Status = desired.Status - - updater := r.Client.InternalV1alpha1().Topics(existing.Namespace) - - _, err = updater.UpdateStatus(existing) - return err - }) -} - -// updateFinalizersFiltered will update the Finalizers of the resource. -// TODO: this method could be generic and sync all finalizers. For now it only -// updates defaultFinalizerName or its override. -func (r *reconcilerImpl) updateFinalizersFiltered(ctx context.Context, resource *v1alpha1.Topic) (*v1alpha1.Topic, error) { - - getter := r.Lister.Topics(resource.Namespace) - - actual, err := getter.Get(resource.Name) - if err != nil { - return resource, err - } - - // Don't modify the informers copy. - existing := actual.DeepCopy() - - var finalizers []string - - // If there's nothing to update, just return. - existingFinalizers := sets.NewString(existing.Finalizers...) - desiredFinalizers := sets.NewString(resource.Finalizers...) - - if desiredFinalizers.Has(r.finalizerName) { - if existingFinalizers.Has(r.finalizerName) { - // Nothing to do. - return resource, nil - } - // Add the finalizer. - finalizers = append(existing.Finalizers, r.finalizerName) - } else { - if !existingFinalizers.Has(r.finalizerName) { - // Nothing to do. - return resource, nil - } - // Remove the finalizer. - existingFinalizers.Delete(r.finalizerName) - finalizers = existingFinalizers.List() - } - - mergePatch := map[string]interface{}{ - "metadata": map[string]interface{}{ - "finalizers": finalizers, - "resourceVersion": existing.ResourceVersion, - }, - } - - patch, err := json.Marshal(mergePatch) - if err != nil { - return resource, err - } - - patcher := r.Client.InternalV1alpha1().Topics(resource.Namespace) - - resourceName := resource.Name - resource, err = patcher.Patch(resourceName, types.MergePatchType, patch) - if err != nil { - r.Recorder.Eventf(resource, v1.EventTypeWarning, "FinalizerUpdateFailed", - "Failed to update finalizers for %q: %v", resourceName, err) - } else { - r.Recorder.Eventf(resource, v1.EventTypeNormal, "FinalizerUpdate", - "Updated %q finalizers", resource.GetName()) - } - return resource, err -} - -func (r *reconcilerImpl) setFinalizerIfFinalizer(ctx context.Context, resource *v1alpha1.Topic) (*v1alpha1.Topic, error) { - if _, ok := r.reconciler.(Finalizer); !ok { - return resource, nil - } - - finalizers := sets.NewString(resource.Finalizers...) - - // If this resource is not being deleted, mark the finalizer. - if resource.GetDeletionTimestamp().IsZero() { - finalizers.Insert(r.finalizerName) - } - - resource.Finalizers = finalizers.List() - - // Synchronize the finalizers filtered by r.finalizerName. - return r.updateFinalizersFiltered(ctx, resource) -} - -func (r *reconcilerImpl) clearFinalizer(ctx context.Context, resource *v1alpha1.Topic, reconcileEvent reconciler.Event) (*v1alpha1.Topic, error) { - if _, ok := r.reconciler.(Finalizer); !ok { - return resource, nil - } - if resource.GetDeletionTimestamp().IsZero() { - return resource, nil - } - - finalizers := sets.NewString(resource.Finalizers...) - - if reconcileEvent != nil { - var event *reconciler.ReconcilerEvent - if reconciler.EventAs(reconcileEvent, &event) { - if event.EventType == v1.EventTypeNormal { - finalizers.Delete(r.finalizerName) - } - } - } else { - finalizers.Delete(r.finalizerName) - } - - resource.Finalizers = finalizers.List() - - // Synchronize the finalizers filtered by r.finalizerName. - return r.updateFinalizersFiltered(ctx, resource) -} diff --git a/pkg/client/injection/reconciler/intevents/v1alpha1/topic/stub/controller.go b/pkg/client/injection/reconciler/intevents/v1alpha1/topic/stub/controller.go deleted file mode 100644 index 1c02b0380c..0000000000 --- a/pkg/client/injection/reconciler/intevents/v1alpha1/topic/stub/controller.go +++ /dev/null @@ -1,54 +0,0 @@ -/* -Copyright 2020 Google LLC - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -// Code generated by injection-gen. DO NOT EDIT. - -package topic - -import ( - context "context" - - topic "github.com/google/knative-gcp/pkg/client/injection/informers/intevents/v1alpha1/topic" - v1alpha1topic "github.com/google/knative-gcp/pkg/client/injection/reconciler/intevents/v1alpha1/topic" - configmap "knative.dev/pkg/configmap" - controller "knative.dev/pkg/controller" - logging "knative.dev/pkg/logging" -) - -// TODO: PLEASE COPY AND MODIFY THIS FILE AS A STARTING POINT - -// NewController creates a Reconciler for Topic and returns the result of NewImpl. -func NewController( - ctx context.Context, - cmw configmap.Watcher, -) *controller.Impl { - logger := logging.FromContext(ctx) - - topicInformer := topic.Get(ctx) - - // TODO: setup additional informers here. - - r := &Reconciler{} - impl := v1alpha1topic.NewImpl(ctx, r) - - logger.Info("Setting up event handlers.") - - topicInformer.Informer().AddEventHandler(controller.HandleAll(impl.Enqueue)) - - // TODO: add additional informer event handlers here. - - return impl -} diff --git a/pkg/client/injection/reconciler/intevents/v1alpha1/topic/stub/reconciler.go b/pkg/client/injection/reconciler/intevents/v1alpha1/topic/stub/reconciler.go deleted file mode 100644 index 0d4dc830f6..0000000000 --- a/pkg/client/injection/reconciler/intevents/v1alpha1/topic/stub/reconciler.go +++ /dev/null @@ -1,87 +0,0 @@ -/* -Copyright 2020 Google LLC - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -// Code generated by injection-gen. DO NOT EDIT. - -package topic - -import ( - context "context" - - v1alpha1 "github.com/google/knative-gcp/pkg/apis/intevents/v1alpha1" - topic "github.com/google/knative-gcp/pkg/client/injection/reconciler/intevents/v1alpha1/topic" - v1 "k8s.io/api/core/v1" - reconciler "knative.dev/pkg/reconciler" -) - -// TODO: PLEASE COPY AND MODIFY THIS FILE AS A STARTING POINT - -// newReconciledNormal makes a new reconciler event with event type Normal, and -// reason TopicReconciled. -func newReconciledNormal(namespace, name string) reconciler.Event { - return reconciler.NewEvent(v1.EventTypeNormal, "TopicReconciled", "Topic reconciled: \"%s/%s\"", namespace, name) -} - -// Reconciler implements controller.Reconciler for Topic resources. -type Reconciler struct { - // TODO: add additional requirements here. -} - -// Check that our Reconciler implements Interface -var _ topic.Interface = (*Reconciler)(nil) - -// Optionally check that our Reconciler implements Finalizer -//var _ topic.Finalizer = (*Reconciler)(nil) - -// Optionally check that our Reconciler implements ReadOnlyInterface -// Implement this to observe resources even when we are not the leader. -//var _ topic.ReadOnlyInterface = (*Reconciler)(nil) - -// Optionally check that our Reconciler implements ReadOnlyFinalizer -// Implement this to observe tombstoned resources even when we are not -// the leader (best effort). -//var _ topic.ReadOnlyFinalizer = (*Reconciler)(nil) - -// ReconcileKind implements Interface.ReconcileKind. -func (r *Reconciler) ReconcileKind(ctx context.Context, o *v1alpha1.Topic) reconciler.Event { - // TODO: use this if the resource implements InitializeConditions. - // o.Status.InitializeConditions() - - // TODO: add custom reconciliation logic here. - - // TODO: use this if the object has .status.ObservedGeneration. - // o.Status.ObservedGeneration = o.Generation - return newReconciledNormal(o.Namespace, o.Name) -} - -// Optionally, use FinalizeKind to add finalizers. FinalizeKind will be called -// when the resource is deleted. -//func (r *Reconciler) FinalizeKind(ctx context.Context, o *v1alpha1.Topic) reconciler.Event { -// // TODO: add custom finalization logic here. -// return nil -//} - -// Optionally, use ObserveKind to observe the resource when we are not the leader. -// func (r *Reconciler) ObserveKind(ctx context.Context, o *v1alpha1.Topic) reconciler.Event { -// // TODO: add custom observation logic here. -// return nil -// } - -// Optionally, use ObserveFinalizeKind to observe resources being finalized when we are no the leader. -//func (r *Reconciler) ObserveFinalizeKind(ctx context.Context, o *v1alpha1.Topic) reconciler.Event { -// // TODO: add custom observation logic here. -// return nil -//} diff --git a/pkg/client/injection/reconciler/intevents/v1beta1/pullsubscription/reconciler.go b/pkg/client/injection/reconciler/intevents/v1beta1/pullsubscription/reconciler.go index 669458681f..5b4cddef55 100644 --- a/pkg/client/injection/reconciler/intevents/v1beta1/pullsubscription/reconciler.go +++ b/pkg/client/injection/reconciler/intevents/v1beta1/pullsubscription/reconciler.go @@ -225,10 +225,14 @@ func (r *reconcilerImpl) Reconcile(ctx context.Context, key string) error { return fmt.Errorf("failed to set finalizers: %w", err) } + reconciler.PreProcessReconcile(ctx, resource) + // Reconcile this copy of the resource and then write back any status // updates regardless of whether the reconciliation errored out. reconcileEvent = r.reconciler.ReconcileKind(ctx, resource) + reconciler.PostProcessReconcile(ctx, resource, original) + } else if isROI { // Append the target method to the logger. logger = logger.With(zap.String("targetMethod", "ObserveKind")) diff --git a/pkg/client/injection/reconciler/intevents/v1beta1/topic/reconciler.go b/pkg/client/injection/reconciler/intevents/v1beta1/topic/reconciler.go index 332a9c9e37..9afbc11c30 100644 --- a/pkg/client/injection/reconciler/intevents/v1beta1/topic/reconciler.go +++ b/pkg/client/injection/reconciler/intevents/v1beta1/topic/reconciler.go @@ -225,10 +225,14 @@ func (r *reconcilerImpl) Reconcile(ctx context.Context, key string) error { return fmt.Errorf("failed to set finalizers: %w", err) } + reconciler.PreProcessReconcile(ctx, resource) + // Reconcile this copy of the resource and then write back any status // updates regardless of whether the reconciliation errored out. reconcileEvent = r.reconciler.ReconcileKind(ctx, resource) + reconciler.PostProcessReconcile(ctx, resource, original) + } else if isROI { // Append the target method to the logger. logger = logger.With(zap.String("targetMethod", "ObserveKind")) diff --git a/pkg/client/injection/reconciler/messaging/v1alpha1/channel/controller.go b/pkg/client/injection/reconciler/messaging/v1alpha1/channel/controller.go deleted file mode 100644 index b18bc720e1..0000000000 --- a/pkg/client/injection/reconciler/messaging/v1alpha1/channel/controller.go +++ /dev/null @@ -1,139 +0,0 @@ -/* -Copyright 2020 Google LLC - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -// Code generated by injection-gen. DO NOT EDIT. - -package channel - -import ( - context "context" - fmt "fmt" - reflect "reflect" - strings "strings" - - versionedscheme "github.com/google/knative-gcp/pkg/client/clientset/versioned/scheme" - client "github.com/google/knative-gcp/pkg/client/injection/client" - channel "github.com/google/knative-gcp/pkg/client/injection/informers/messaging/v1alpha1/channel" - corev1 "k8s.io/api/core/v1" - labels "k8s.io/apimachinery/pkg/labels" - types "k8s.io/apimachinery/pkg/types" - watch "k8s.io/apimachinery/pkg/watch" - scheme "k8s.io/client-go/kubernetes/scheme" - v1 "k8s.io/client-go/kubernetes/typed/core/v1" - record "k8s.io/client-go/tools/record" - kubeclient "knative.dev/pkg/client/injection/kube/client" - controller "knative.dev/pkg/controller" - logging "knative.dev/pkg/logging" - reconciler "knative.dev/pkg/reconciler" -) - -const ( - defaultControllerAgentName = "channel-controller" - defaultFinalizerName = "channels.messaging.cloud.google.com" -) - -// NewImpl returns a controller.Impl that handles queuing and feeding work from -// the queue through an implementation of controller.Reconciler, delegating to -// the provided Interface and optional Finalizer methods. OptionsFn is used to return -// controller.Options to be used but the internal reconciler. -func NewImpl(ctx context.Context, r Interface, optionsFns ...controller.OptionsFn) *controller.Impl { - logger := logging.FromContext(ctx) - - // Check the options function input. It should be 0 or 1. - if len(optionsFns) > 1 { - logger.Fatalf("up to one options function is supported, found %d", len(optionsFns)) - } - - channelInformer := channel.Get(ctx) - - lister := channelInformer.Lister() - - rec := &reconcilerImpl{ - LeaderAwareFuncs: reconciler.LeaderAwareFuncs{ - PromoteFunc: func(bkt reconciler.Bucket, enq func(reconciler.Bucket, types.NamespacedName)) error { - all, err := lister.List(labels.Everything()) - if err != nil { - return err - } - for _, elt := range all { - // TODO: Consider letting users specify a filter in options. - enq(bkt, types.NamespacedName{ - Namespace: elt.GetNamespace(), - Name: elt.GetName(), - }) - } - return nil - }, - }, - Client: client.Get(ctx), - Lister: lister, - reconciler: r, - finalizerName: defaultFinalizerName, - } - - t := reflect.TypeOf(r).Elem() - queueName := fmt.Sprintf("%s.%s", strings.ReplaceAll(t.PkgPath(), "/", "-"), t.Name()) - - impl := controller.NewImpl(rec, logger, queueName) - agentName := defaultControllerAgentName - - // Pass impl to the options. Save any optional results. - for _, fn := range optionsFns { - opts := fn(impl) - if opts.ConfigStore != nil { - rec.configStore = opts.ConfigStore - } - if opts.FinalizerName != "" { - rec.finalizerName = opts.FinalizerName - } - if opts.AgentName != "" { - agentName = opts.AgentName - } - } - - rec.Recorder = createRecorder(ctx, agentName) - - return impl -} - -func createRecorder(ctx context.Context, agentName string) record.EventRecorder { - logger := logging.FromContext(ctx) - - recorder := controller.GetEventRecorder(ctx) - if recorder == nil { - // Create event broadcaster - logger.Debug("Creating event broadcaster") - eventBroadcaster := record.NewBroadcaster() - watches := []watch.Interface{ - eventBroadcaster.StartLogging(logger.Named("event-broadcaster").Infof), - eventBroadcaster.StartRecordingToSink( - &v1.EventSinkImpl{Interface: kubeclient.Get(ctx).CoreV1().Events("")}), - } - recorder = eventBroadcaster.NewRecorder(scheme.Scheme, corev1.EventSource{Component: agentName}) - go func() { - <-ctx.Done() - for _, w := range watches { - w.Stop() - } - }() - } - - return recorder -} - -func init() { - versionedscheme.AddToScheme(scheme.Scheme) -} diff --git a/pkg/client/injection/reconciler/messaging/v1alpha1/channel/reconciler.go b/pkg/client/injection/reconciler/messaging/v1alpha1/channel/reconciler.go deleted file mode 100644 index 3d4558b9e8..0000000000 --- a/pkg/client/injection/reconciler/messaging/v1alpha1/channel/reconciler.go +++ /dev/null @@ -1,430 +0,0 @@ -/* -Copyright 2020 Google LLC - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -// Code generated by injection-gen. DO NOT EDIT. - -package channel - -import ( - context "context" - json "encoding/json" - fmt "fmt" - reflect "reflect" - - v1alpha1 "github.com/google/knative-gcp/pkg/apis/messaging/v1alpha1" - versioned "github.com/google/knative-gcp/pkg/client/clientset/versioned" - messagingv1alpha1 "github.com/google/knative-gcp/pkg/client/listers/messaging/v1alpha1" - zap "go.uber.org/zap" - v1 "k8s.io/api/core/v1" - equality "k8s.io/apimachinery/pkg/api/equality" - errors "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - labels "k8s.io/apimachinery/pkg/labels" - types "k8s.io/apimachinery/pkg/types" - sets "k8s.io/apimachinery/pkg/util/sets" - cache "k8s.io/client-go/tools/cache" - record "k8s.io/client-go/tools/record" - controller "knative.dev/pkg/controller" - logging "knative.dev/pkg/logging" - reconciler "knative.dev/pkg/reconciler" -) - -// Interface defines the strongly typed interfaces to be implemented by a -// controller reconciling v1alpha1.Channel. -type Interface interface { - // ReconcileKind implements custom logic to reconcile v1alpha1.Channel. Any changes - // to the objects .Status or .Finalizers will be propagated to the stored - // object. It is recommended that implementors do not call any update calls - // for the Kind inside of ReconcileKind, it is the responsibility of the calling - // controller to propagate those properties. The resource passed to ReconcileKind - // will always have an empty deletion timestamp. - ReconcileKind(ctx context.Context, o *v1alpha1.Channel) reconciler.Event -} - -// Finalizer defines the strongly typed interfaces to be implemented by a -// controller finalizing v1alpha1.Channel. -type Finalizer interface { - // FinalizeKind implements custom logic to finalize v1alpha1.Channel. Any changes - // to the objects .Status or .Finalizers will be ignored. Returning a nil or - // Normal type reconciler.Event will allow the finalizer to be deleted on - // the resource. The resource passed to FinalizeKind will always have a set - // deletion timestamp. - FinalizeKind(ctx context.Context, o *v1alpha1.Channel) reconciler.Event -} - -// ReadOnlyInterface defines the strongly typed interfaces to be implemented by a -// controller reconciling v1alpha1.Channel if they want to process resources for which -// they are not the leader. -type ReadOnlyInterface interface { - // ObserveKind implements logic to observe v1alpha1.Channel. - // This method should not write to the API. - ObserveKind(ctx context.Context, o *v1alpha1.Channel) reconciler.Event -} - -// ReadOnlyFinalizer defines the strongly typed interfaces to be implemented by a -// controller finalizing v1alpha1.Channel if they want to process tombstoned resources -// even when they are not the leader. Due to the nature of how finalizers are handled -// there are no guarantees that this will be called. -type ReadOnlyFinalizer interface { - // ObserveFinalizeKind implements custom logic to observe the final state of v1alpha1.Channel. - // This method should not write to the API. - ObserveFinalizeKind(ctx context.Context, o *v1alpha1.Channel) reconciler.Event -} - -// reconcilerImpl implements controller.Reconciler for v1alpha1.Channel resources. -type reconcilerImpl struct { - // LeaderAwareFuncs is inlined to help us implement reconciler.LeaderAware - reconciler.LeaderAwareFuncs - - // Client is used to write back status updates. - Client versioned.Interface - - // Listers index properties about resources - Lister messagingv1alpha1.ChannelLister - - // Recorder is an event recorder for recording Event resources to the - // Kubernetes API. - Recorder record.EventRecorder - - // configStore allows for decorating a context with config maps. - // +optional - configStore reconciler.ConfigStore - - // reconciler is the implementation of the business logic of the resource. - reconciler Interface - - // finalizerName is the name of the finalizer to reconcile. - finalizerName string -} - -// Check that our Reconciler implements controller.Reconciler -var _ controller.Reconciler = (*reconcilerImpl)(nil) - -// Check that our generated Reconciler is always LeaderAware. -var _ reconciler.LeaderAware = (*reconcilerImpl)(nil) - -func NewReconciler(ctx context.Context, logger *zap.SugaredLogger, client versioned.Interface, lister messagingv1alpha1.ChannelLister, recorder record.EventRecorder, r Interface, options ...controller.Options) controller.Reconciler { - // Check the options function input. It should be 0 or 1. - if len(options) > 1 { - logger.Fatalf("up to one options struct is supported, found %d", len(options)) - } - - // Fail fast when users inadvertently implement the other LeaderAware interface. - // For the typed reconcilers, Promote shouldn't take any arguments. - if _, ok := r.(reconciler.LeaderAware); ok { - logger.Fatalf("%T implements the incorrect LeaderAware interface. Promote() should not take an argument as genreconciler handles the enqueuing automatically.", r) - } - // TODO: Consider validating when folks implement ReadOnlyFinalizer, but not Finalizer. - - rec := &reconcilerImpl{ - LeaderAwareFuncs: reconciler.LeaderAwareFuncs{ - PromoteFunc: func(bkt reconciler.Bucket, enq func(reconciler.Bucket, types.NamespacedName)) error { - all, err := lister.List(labels.Everything()) - if err != nil { - return err - } - for _, elt := range all { - // TODO: Consider letting users specify a filter in options. - enq(bkt, types.NamespacedName{ - Namespace: elt.GetNamespace(), - Name: elt.GetName(), - }) - } - return nil - }, - }, - Client: client, - Lister: lister, - Recorder: recorder, - reconciler: r, - finalizerName: defaultFinalizerName, - } - - for _, opts := range options { - if opts.ConfigStore != nil { - rec.configStore = opts.ConfigStore - } - if opts.FinalizerName != "" { - rec.finalizerName = opts.FinalizerName - } - } - - return rec -} - -// Reconcile implements controller.Reconciler -func (r *reconcilerImpl) Reconcile(ctx context.Context, key string) error { - logger := logging.FromContext(ctx) - - // Convert the namespace/name string into a distinct namespace and name - namespace, name, err := cache.SplitMetaNamespaceKey(key) - if err != nil { - logger.Errorf("invalid resource key: %s", key) - return nil - } - // Establish whether we are the leader for use below. - isLeader := r.IsLeaderFor(types.NamespacedName{ - Namespace: namespace, - Name: name, - }) - roi, isROI := r.reconciler.(ReadOnlyInterface) - rof, isROF := r.reconciler.(ReadOnlyFinalizer) - if !isLeader && !isROI && !isROF { - // If we are not the leader, and we don't implement either ReadOnly - // interface, then take a fast-path out. - return nil - } - - // If configStore is set, attach the frozen configuration to the context. - if r.configStore != nil { - ctx = r.configStore.ToContext(ctx) - } - - // Add the recorder to context. - ctx = controller.WithEventRecorder(ctx, r.Recorder) - - // Get the resource with this namespace/name. - - getter := r.Lister.Channels(namespace) - - original, err := getter.Get(name) - - if errors.IsNotFound(err) { - // The resource may no longer exist, in which case we stop processing. - logger.Debugf("resource %q no longer exists", key) - return nil - } else if err != nil { - return err - } - - // Don't modify the informers copy. - resource := original.DeepCopy() - - var reconcileEvent reconciler.Event - if resource.GetDeletionTimestamp().IsZero() { - if isLeader { - // Append the target method to the logger. - logger = logger.With(zap.String("targetMethod", "ReconcileKind")) - - // Set and update the finalizer on resource if r.reconciler - // implements Finalizer. - if resource, err = r.setFinalizerIfFinalizer(ctx, resource); err != nil { - return fmt.Errorf("failed to set finalizers: %w", err) - } - - // Reconcile this copy of the resource and then write back any status - // updates regardless of whether the reconciliation errored out. - reconcileEvent = r.reconciler.ReconcileKind(ctx, resource) - - } else if isROI { - // Append the target method to the logger. - logger = logger.With(zap.String("targetMethod", "ObserveKind")) - - // Observe any changes to this resource, since we are not the leader. - reconcileEvent = roi.ObserveKind(ctx, resource) - } - } else if fin, ok := r.reconciler.(Finalizer); isLeader && ok { - // Append the target method to the logger. - logger = logger.With(zap.String("targetMethod", "FinalizeKind")) - - // For finalizing reconcilers, if this resource being marked for deletion - // and reconciled cleanly (nil or normal event), remove the finalizer. - reconcileEvent = fin.FinalizeKind(ctx, resource) - if resource, err = r.clearFinalizer(ctx, resource, reconcileEvent); err != nil { - return fmt.Errorf("failed to clear finalizers: %w", err) - } - } else if !isLeader && isROF { - // Append the target method to the logger. - logger = logger.With(zap.String("targetMethod", "ObserveFinalizeKind")) - - // For finalizing reconcilers, just observe when we aren't the leader. - reconcileEvent = rof.ObserveFinalizeKind(ctx, resource) - } - - // Synchronize the status. - if equality.Semantic.DeepEqual(original.Status, resource.Status) { - // If we didn't change anything then don't call updateStatus. - // This is important because the copy we loaded from the injectionInformer's - // cache may be stale and we don't want to overwrite a prior update - // to status with this stale state. - } else if !isLeader { - logger.Warn("Saw status changes when we aren't the leader!") - // TODO: Consider logging the diff at Debug? - } else if err = r.updateStatus(original, resource); err != nil { - logger.Warnw("Failed to update resource status", zap.Error(err)) - r.Recorder.Eventf(resource, v1.EventTypeWarning, "UpdateFailed", - "Failed to update status for %q: %v", resource.Name, err) - return err - } - - // Report the reconciler event, if any. - if reconcileEvent != nil { - var event *reconciler.ReconcilerEvent - if reconciler.EventAs(reconcileEvent, &event) { - logger.Infow("Returned an event", zap.Any("event", reconcileEvent)) - r.Recorder.Eventf(resource, event.EventType, event.Reason, event.Format, event.Args...) - - // the event was wrapped inside an error, consider the reconciliation as failed - if _, isEvent := reconcileEvent.(*reconciler.ReconcilerEvent); !isEvent { - return reconcileEvent - } - return nil - } - - logger.Errorw("Returned an error", zap.Error(reconcileEvent)) - r.Recorder.Event(resource, v1.EventTypeWarning, "InternalError", reconcileEvent.Error()) - return reconcileEvent - } - - return nil -} - -func (r *reconcilerImpl) updateStatus(existing *v1alpha1.Channel, desired *v1alpha1.Channel) error { - existing = existing.DeepCopy() - return reconciler.RetryUpdateConflicts(func(attempts int) (err error) { - // The first iteration tries to use the injectionInformer's state, subsequent attempts fetch the latest state via API. - if attempts > 0 { - - getter := r.Client.MessagingV1alpha1().Channels(desired.Namespace) - - existing, err = getter.Get(desired.Name, metav1.GetOptions{}) - if err != nil { - return err - } - } - - // If there's nothing to update, just return. - if reflect.DeepEqual(existing.Status, desired.Status) { - return nil - } - - existing.Status = desired.Status - - updater := r.Client.MessagingV1alpha1().Channels(existing.Namespace) - - _, err = updater.UpdateStatus(existing) - return err - }) -} - -// updateFinalizersFiltered will update the Finalizers of the resource. -// TODO: this method could be generic and sync all finalizers. For now it only -// updates defaultFinalizerName or its override. -func (r *reconcilerImpl) updateFinalizersFiltered(ctx context.Context, resource *v1alpha1.Channel) (*v1alpha1.Channel, error) { - - getter := r.Lister.Channels(resource.Namespace) - - actual, err := getter.Get(resource.Name) - if err != nil { - return resource, err - } - - // Don't modify the informers copy. - existing := actual.DeepCopy() - - var finalizers []string - - // If there's nothing to update, just return. - existingFinalizers := sets.NewString(existing.Finalizers...) - desiredFinalizers := sets.NewString(resource.Finalizers...) - - if desiredFinalizers.Has(r.finalizerName) { - if existingFinalizers.Has(r.finalizerName) { - // Nothing to do. - return resource, nil - } - // Add the finalizer. - finalizers = append(existing.Finalizers, r.finalizerName) - } else { - if !existingFinalizers.Has(r.finalizerName) { - // Nothing to do. - return resource, nil - } - // Remove the finalizer. - existingFinalizers.Delete(r.finalizerName) - finalizers = existingFinalizers.List() - } - - mergePatch := map[string]interface{}{ - "metadata": map[string]interface{}{ - "finalizers": finalizers, - "resourceVersion": existing.ResourceVersion, - }, - } - - patch, err := json.Marshal(mergePatch) - if err != nil { - return resource, err - } - - patcher := r.Client.MessagingV1alpha1().Channels(resource.Namespace) - - resourceName := resource.Name - resource, err = patcher.Patch(resourceName, types.MergePatchType, patch) - if err != nil { - r.Recorder.Eventf(resource, v1.EventTypeWarning, "FinalizerUpdateFailed", - "Failed to update finalizers for %q: %v", resourceName, err) - } else { - r.Recorder.Eventf(resource, v1.EventTypeNormal, "FinalizerUpdate", - "Updated %q finalizers", resource.GetName()) - } - return resource, err -} - -func (r *reconcilerImpl) setFinalizerIfFinalizer(ctx context.Context, resource *v1alpha1.Channel) (*v1alpha1.Channel, error) { - if _, ok := r.reconciler.(Finalizer); !ok { - return resource, nil - } - - finalizers := sets.NewString(resource.Finalizers...) - - // If this resource is not being deleted, mark the finalizer. - if resource.GetDeletionTimestamp().IsZero() { - finalizers.Insert(r.finalizerName) - } - - resource.Finalizers = finalizers.List() - - // Synchronize the finalizers filtered by r.finalizerName. - return r.updateFinalizersFiltered(ctx, resource) -} - -func (r *reconcilerImpl) clearFinalizer(ctx context.Context, resource *v1alpha1.Channel, reconcileEvent reconciler.Event) (*v1alpha1.Channel, error) { - if _, ok := r.reconciler.(Finalizer); !ok { - return resource, nil - } - if resource.GetDeletionTimestamp().IsZero() { - return resource, nil - } - - finalizers := sets.NewString(resource.Finalizers...) - - if reconcileEvent != nil { - var event *reconciler.ReconcilerEvent - if reconciler.EventAs(reconcileEvent, &event) { - if event.EventType == v1.EventTypeNormal { - finalizers.Delete(r.finalizerName) - } - } - } else { - finalizers.Delete(r.finalizerName) - } - - resource.Finalizers = finalizers.List() - - // Synchronize the finalizers filtered by r.finalizerName. - return r.updateFinalizersFiltered(ctx, resource) -} diff --git a/pkg/client/injection/reconciler/messaging/v1alpha1/channel/stub/controller.go b/pkg/client/injection/reconciler/messaging/v1alpha1/channel/stub/controller.go deleted file mode 100644 index 933865d541..0000000000 --- a/pkg/client/injection/reconciler/messaging/v1alpha1/channel/stub/controller.go +++ /dev/null @@ -1,54 +0,0 @@ -/* -Copyright 2020 Google LLC - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -// Code generated by injection-gen. DO NOT EDIT. - -package channel - -import ( - context "context" - - channel "github.com/google/knative-gcp/pkg/client/injection/informers/messaging/v1alpha1/channel" - v1alpha1channel "github.com/google/knative-gcp/pkg/client/injection/reconciler/messaging/v1alpha1/channel" - configmap "knative.dev/pkg/configmap" - controller "knative.dev/pkg/controller" - logging "knative.dev/pkg/logging" -) - -// TODO: PLEASE COPY AND MODIFY THIS FILE AS A STARTING POINT - -// NewController creates a Reconciler for Channel and returns the result of NewImpl. -func NewController( - ctx context.Context, - cmw configmap.Watcher, -) *controller.Impl { - logger := logging.FromContext(ctx) - - channelInformer := channel.Get(ctx) - - // TODO: setup additional informers here. - - r := &Reconciler{} - impl := v1alpha1channel.NewImpl(ctx, r) - - logger.Info("Setting up event handlers.") - - channelInformer.Informer().AddEventHandler(controller.HandleAll(impl.Enqueue)) - - // TODO: add additional informer event handlers here. - - return impl -} diff --git a/pkg/client/injection/reconciler/messaging/v1alpha1/channel/stub/reconciler.go b/pkg/client/injection/reconciler/messaging/v1alpha1/channel/stub/reconciler.go deleted file mode 100644 index 9c267fb126..0000000000 --- a/pkg/client/injection/reconciler/messaging/v1alpha1/channel/stub/reconciler.go +++ /dev/null @@ -1,87 +0,0 @@ -/* -Copyright 2020 Google LLC - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -// Code generated by injection-gen. DO NOT EDIT. - -package channel - -import ( - context "context" - - v1alpha1 "github.com/google/knative-gcp/pkg/apis/messaging/v1alpha1" - channel "github.com/google/knative-gcp/pkg/client/injection/reconciler/messaging/v1alpha1/channel" - v1 "k8s.io/api/core/v1" - reconciler "knative.dev/pkg/reconciler" -) - -// TODO: PLEASE COPY AND MODIFY THIS FILE AS A STARTING POINT - -// newReconciledNormal makes a new reconciler event with event type Normal, and -// reason ChannelReconciled. -func newReconciledNormal(namespace, name string) reconciler.Event { - return reconciler.NewEvent(v1.EventTypeNormal, "ChannelReconciled", "Channel reconciled: \"%s/%s\"", namespace, name) -} - -// Reconciler implements controller.Reconciler for Channel resources. -type Reconciler struct { - // TODO: add additional requirements here. -} - -// Check that our Reconciler implements Interface -var _ channel.Interface = (*Reconciler)(nil) - -// Optionally check that our Reconciler implements Finalizer -//var _ channel.Finalizer = (*Reconciler)(nil) - -// Optionally check that our Reconciler implements ReadOnlyInterface -// Implement this to observe resources even when we are not the leader. -//var _ channel.ReadOnlyInterface = (*Reconciler)(nil) - -// Optionally check that our Reconciler implements ReadOnlyFinalizer -// Implement this to observe tombstoned resources even when we are not -// the leader (best effort). -//var _ channel.ReadOnlyFinalizer = (*Reconciler)(nil) - -// ReconcileKind implements Interface.ReconcileKind. -func (r *Reconciler) ReconcileKind(ctx context.Context, o *v1alpha1.Channel) reconciler.Event { - // TODO: use this if the resource implements InitializeConditions. - // o.Status.InitializeConditions() - - // TODO: add custom reconciliation logic here. - - // TODO: use this if the object has .status.ObservedGeneration. - // o.Status.ObservedGeneration = o.Generation - return newReconciledNormal(o.Namespace, o.Name) -} - -// Optionally, use FinalizeKind to add finalizers. FinalizeKind will be called -// when the resource is deleted. -//func (r *Reconciler) FinalizeKind(ctx context.Context, o *v1alpha1.Channel) reconciler.Event { -// // TODO: add custom finalization logic here. -// return nil -//} - -// Optionally, use ObserveKind to observe the resource when we are not the leader. -// func (r *Reconciler) ObserveKind(ctx context.Context, o *v1alpha1.Channel) reconciler.Event { -// // TODO: add custom observation logic here. -// return nil -// } - -// Optionally, use ObserveFinalizeKind to observe resources being finalized when we are no the leader. -//func (r *Reconciler) ObserveFinalizeKind(ctx context.Context, o *v1alpha1.Channel) reconciler.Event { -// // TODO: add custom observation logic here. -// return nil -//} diff --git a/pkg/client/injection/reconciler/messaging/v1beta1/channel/reconciler.go b/pkg/client/injection/reconciler/messaging/v1beta1/channel/reconciler.go index fbc80b7b79..912f867427 100644 --- a/pkg/client/injection/reconciler/messaging/v1beta1/channel/reconciler.go +++ b/pkg/client/injection/reconciler/messaging/v1beta1/channel/reconciler.go @@ -225,10 +225,14 @@ func (r *reconcilerImpl) Reconcile(ctx context.Context, key string) error { return fmt.Errorf("failed to set finalizers: %w", err) } + reconciler.PreProcessReconcile(ctx, resource) + // Reconcile this copy of the resource and then write back any status // updates regardless of whether the reconciliation errored out. reconcileEvent = r.reconciler.ReconcileKind(ctx, resource) + reconciler.PostProcessReconcile(ctx, resource, original) + } else if isROI { // Append the target method to the logger. logger = logger.With(zap.String("targetMethod", "ObserveKind")) diff --git a/pkg/kncloudevents/good_client.go b/pkg/kncloudevents/good_client.go index 2ed63d25f9..4ab016d440 100644 --- a/pkg/kncloudevents/good_client.go +++ b/pkg/kncloudevents/good_client.go @@ -1,3 +1,19 @@ +/* +Copyright 2020 Google LLC + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + package kncloudevents import ( diff --git a/pkg/pubsub/adapter/adapter.go b/pkg/pubsub/adapter/adapter.go index 83af4cc101..c48d1b715f 100644 --- a/pkg/pubsub/adapter/adapter.go +++ b/pkg/pubsub/adapter/adapter.go @@ -18,253 +18,250 @@ package adapter import ( "context" - "fmt" - nethttp "net/http" - "go.opencensus.io/trace" "go.uber.org/zap" - cloudevents "github.com/cloudevents/sdk-go" - "github.com/cloudevents/sdk-go/pkg/cloudevents/transport" - "github.com/cloudevents/sdk-go/pkg/cloudevents/transport/http" - cepubsub "github.com/cloudevents/sdk-go/pkg/cloudevents/transport/pubsub" - "github.com/google/knative-gcp/pkg/kncloudevents" + "cloud.google.com/go/pubsub" + cev2 "github.com/cloudevents/sdk-go/v2" + "github.com/cloudevents/sdk-go/v2/binding" + "github.com/cloudevents/sdk-go/v2/extensions" + cehttp "github.com/cloudevents/sdk-go/v2/protocol/http" + "github.com/google/knative-gcp/pkg/apis/messaging" + . "github.com/google/knative-gcp/pkg/pubsub/adapter/context" "github.com/google/knative-gcp/pkg/pubsub/adapter/converters" - "github.com/google/knative-gcp/pkg/utils" - - "k8s.io/apimachinery/pkg/runtime/schema" - "knative.dev/pkg/logging" + "github.com/google/knative-gcp/pkg/tracing" + "github.com/google/knative-gcp/pkg/utils/clients" + "go.opencensus.io/trace" + "k8s.io/apimachinery/pkg/types" + "knative.dev/eventing/pkg/logging" + kntracing "knative.dev/eventing/pkg/tracing" ) -var ( - channelGVR = schema.GroupVersionResource{ - Group: "messaging.cloud.google.com", - Version: "v1alpha1", - Resource: "channels", - } -) +// AdapterArgs has a bundle of arguments needed to create an Adapter. +type AdapterArgs struct { + // TopicID is the id of the Pub/Sub topic. + TopicID string -// Adapter implements the Pub/Sub adapter to deliver Pub/Sub messages from a -// pre-existing topic/subscription to a Sink. -type Adapter struct { - // Environment variable containing project id. - Project string `envconfig:"PROJECT_ID"` - - // Environment variable containing the sink URI. - Sink string `envconfig:"SINK_URI" required:"true"` + // SinkURI is the URI where to sink events to. + SinkURI string - // Environment variable containing the transformer URI. - Transformer string `envconfig:"TRANSFORMER_URI"` + // TransformerURI is the URI for the transformer. + // Used for channels. + TransformerURI string - // Environment variable specifying the type of adapter to use. - AdapterType string `envconfig:"ADAPTER_TYPE"` + // Extensions is the converted ExtensionsBased64 value. + Extensions map[string]string - // Topic is the environment variable containing the PubSub Topic being - // subscribed to's name. In the form that is unique within the project. - // E.g. 'laconia', not 'projects/my-gcp-project/topics/laconia'. - Topic string `envconfig:"PUBSUB_TOPIC_ID" required:"true"` + // ConverterType use to select which converter to use. + ConverterType converters.ConverterType +} - // Subscription is the environment variable containing the name of the - // subscription to use. - Subscription string `envconfig:"PUBSUB_SUBSCRIPTION_ID" required:"true"` +// Adapter implements the Pub/Sub adapter to deliver Pub/Sub messages from a +// pre-existing topic/subscription to a Sink. +type Adapter struct { + // subscription is the pubsub subscription used to receive messages from pubsub. + subscription *pubsub.Subscription - // ExtensionsBase64 is a based64 encoded json string of a map of - // CloudEvents extensions (key-value pairs) override onto the outbound - // event. - ExtensionsBase64 string `envconfig:"K_CE_EXTENSIONS" required:"true"` + // outbound is the client used to send events to. + outbound *nethttp.Client - // extensions is the converted ExtensionsBased64 value. - extensions map[string]string + // reporter reports metrics to the configured backend. + reporter StatsReporter - // SendMode describes how the adapter sends events. - // One of [binary, structured, push]. Default: binary - SendMode converters.ModeType `envconfig:"SEND_MODE" default:"binary" required:"true"` + // converter used to convert pubsub messages to CE. + converter converters.Converter - // MetricsConfigJson is a json string of metrics.ExporterOptions. - // This is used to configure the metrics exporter options, the config is - // stored in a config map inside the controllers namespace and copied here. - MetricsConfigJson string `envconfig:"K_METRICS_CONFIG" required:"true"` + // projectID is the id of the GCP project. + projectID string - // LoggingConfigJson is a json string of logging.Config. - // This is used to configure the logging config, the config is stored in - // a config map inside the controllers namespace and copied here. - LoggingConfigJson string `envconfig:"K_LOGGING_CONFIG" required:"true"` + // namespacedName is the namespaced name of the resource this receive adapter belong to. + namespacedName types.NamespacedName - // TracingConfigJson is a JSON string of tracing.Config. This is used to configure tracing. The - // original config is stored in a ConfigMap inside the controller's namespace. Its value is - // copied here as a JSON string. - TracingConfigJson string `envconfig:"K_TRACING_CONFIG" required:"true"` + // resourceGroup is the resource group name this receive adapter belong to. + resourceGroup string - // Environment variable containing the namespace. - Namespace string `envconfig:"NAMESPACE" required:"true"` + // args holds a set of arguments used to configure the Adapter. + args *AdapterArgs - // Environment variable containing the name. - Name string `envconfig:"NAME" required:"true"` + // cancel is function to stop pulling messages. + cancel context.CancelFunc - // Environment variable containing the resource group. E.g., storages.events.cloud.google.com. - ResourceGroup string `envconfig:"RESOURCE_GROUP" default:"pullsubscriptions.pubsub.cloud.google.com" required:"true"` + logger *zap.Logger +} - // inbound is the cloudevents client to use to receive events. - inbound cloudevents.Client +// NewAdapter creates a new adapter. +func NewAdapter( + ctx context.Context, + projectID clients.ProjectID, + namespace Namespace, + name Name, + resourceGroup ResourceGroup, + subscription *pubsub.Subscription, + outbound *nethttp.Client, + converter converters.Converter, + reporter StatsReporter, + args *AdapterArgs) *Adapter { + return &Adapter{ + subscription: subscription, + projectID: string(projectID), + namespacedName: types.NamespacedName{Namespace: string(namespace), Name: string(name)}, + resourceGroup: string(resourceGroup), + outbound: outbound, + converter: converter, + reporter: reporter, + args: args, + logger: logging.FromContext(ctx), + } +} - // outbound is the cloudevents client to use to send events. - outbound cloudevents.Client +func (a *Adapter) Start(ctx context.Context) error { + ctx, a.cancel = context.WithCancel(ctx) - // transformer is the cloudevents client to transform received events before sending. - transformer cloudevents.Client + // Augment context so that we can use it to create CE attributes. + ctx = WithProjectKey(ctx, a.projectID) + ctx = WithTopicKey(ctx, a.args.TopicID) + ctx = WithSubscriptionKey(ctx, a.subscription.ID()) - // reporter reports metrics to the configured backend. - reporter StatsReporter + return a.subscription.Receive(ctx, a.receive) } -// Start starts the adapter. Note: Only call once, not thread safe. -func (a *Adapter) Start(ctx context.Context) error { - var err error - - if a.SendMode == "" { - a.SendMode = converters.DefaultSendMode - } +// Stop stops the adapter. +func (a *Adapter) Stop() { + a.cancel() +} - // Convert base64 encoded json map to extensions map. - a.extensions, err = utils.Base64ToMap(a.ExtensionsBase64) +// TODO refactor this method. As our RA code is used both for Sources and our Channel, it also supports replies +// (in the case of Channels) and the logic is more convoluted. +func (a *Adapter) receive(ctx context.Context, msg *pubsub.Message) { + event, err := a.converter.Convert(ctx, msg, a.args.ConverterType) if err != nil { - fmt.Printf("[warn] failed to convert base64 extensions to map: %v", err) + a.logger.Debug("Failed to convert received message to an event, check the msg format: %w", zap.Error(err)) + // Ack the message so it won't be retried, we consider all errors to be non-retryable. + msg.Ack() + return } - // Receive Events on Pub/Sub. - if a.inbound == nil { - if a.inbound, err = a.newPubSubClient(ctx); err != nil { - return fmt.Errorf("failed to create inbound cloudevent client: %w", err) - } - } + ctx, span := a.startSpan(ctx, event) + defer span.End() - // Send events on HTTP. - if a.outbound == nil { - if a.outbound, err = a.newHTTPClient(ctx, a.Sink); err != nil { - return fmt.Errorf("failed to create outbound cloudevent client: %w", err) - } + args := &ReportArgs{ + EventType: event.Type(), + EventSource: event.Source(), } - if a.reporter == nil { - a.reporter = NewStatsReporter() - } + // Using this variable to check whether the event came from a reply or not. + reply := false - // Make the transformer client in case the TransformerURI has been set. - if a.Transformer != "" { - if a.transformer == nil { - if a.transformer, err = kncloudevents.NewDefaultClient(a.Transformer); err != nil { - return fmt.Errorf("failed to create transformer cloudevent client: %w", err) - } + // If a transformer has been configured, then "transform" the message. + // Note that currently this path of the code will be executed when using the receive adapter as part of the underlying Channel, + // in case both subscriber and reply are set. The transformer would act as the subscriber and the sink will be where + // we will send the reply. + if a.args.TransformerURI != "" { + resp, err := a.sendMsg(ctx, a.args.TransformerURI, (*binding.EventMessage)(event)) + if err != nil { + a.logger.Error("Failed to send message to transformer", zap.String("address", a.args.TransformerURI), zap.Error(err)) + msg.Nack() + return } - } - return a.inbound.StartReceiver(ctx, a.receive) -} + defer func() { + if err := resp.Body.Close(); err != nil { + a.logger.Warn("Failed to close response body", zap.Error(err)) + } + }() -func (a *Adapter) receive(ctx context.Context, event cloudevents.Event, resp *cloudevents.EventResponse) error { - logger := logging.FromContext(ctx).With(zap.Any("event.id", event.ID()), zap.Any("sink", a.Sink)) + a.reporter.ReportEventCount(args, resp.StatusCode) - // TODO Name and ResourceGroup might cause problems in the near future, as we might use a single receive-adapter - // for multiple source objects. Same with Namespace, when doing multi-tenancy. - args := &ReportArgs{ - Name: a.Name, - Namespace: a.Namespace, - EventType: event.Type(), - EventSource: event.Source(), - ResourceGroup: a.ResourceGroup, - } + if resp.StatusCode/100 != 2 { + a.logger.Error("Event delivery failed", zap.Int("StatusCode", resp.StatusCode)) + msg.Nack() + return + } - var err error - // If a transformer has been configured, then transform the message. - // Note that this path in the code will be executed when using the receive adapter as part of the underlying Channel - // of a Broker. We currently set the TransformerURI to be the address of the Broker filter pod. - // TODO consider renaming transformer as it is confusing. - if a.transformer != nil { - transformedCTX, transformedEvent, err := a.transformer.Send(ctx, event) - rtctx := cloudevents.HTTPTransportContextFrom(transformedCTX) - if err != nil { - logger.Errorf("error transforming cloud event %q", event.ID()) - a.reporter.ReportEventCount(args, rtctx.StatusCode) - return err + respMsg := cehttp.NewMessageFromHttpResponse(resp) + if respMsg.ReadEncoding() == binding.EncodingUnknown { + // No reply + msg.Ack() + return } - if transformedEvent == nil { - // This doesn't mean there was an error. E.g., the Broker filter pod might not return a response. - // Report the returned Status Code and return. - logger.Debugf("cloud event %q was not transformed", event.ID()) - a.reporter.ReportEventCount(args, rtctx.StatusCode) - return nil + + // If there was a reply, we need to send it to the sink. + // We then overwrite the initial event we sent. + event, err = binding.ToEvent(ctx, respMsg) + if err != nil { + a.logger.Error("Failed to convert response message to event", + zap.Any("response", respMsg), zap.Error(err)) + msg.Nack() + return } - // Update the event with the transformed one. - event = *transformedEvent - // Update the tracing information to use the span returned by the transformer. - ctx = trace.NewContext(ctx, trace.FromContext(transformedCTX)) + + reply = true } - // Apply CloudEvent override extensions to the outbound event. - for k, v := range a.extensions { - event.SetExtension(k, v) + // Only if the message is not from a reply, then we should add the override extensions. + if !reply { + // Apply CloudEvent override extensions to the outbound event. + // This code will be mainly executed by Sources. + for k, v := range a.args.Extensions { + event.SetExtension(k, v) + } } - // Send the event and report the count. - rctx, r, err := a.outbound.Send(ctx, event) - rtctx := cloudevents.HTTPTransportContextFrom(rctx) - a.reporter.ReportEventCount(args, rtctx.StatusCode) + response, err := a.sendMsg(ctx, a.args.SinkURI, (*binding.EventMessage)(event)) if err != nil { - return err - } else if r != nil { - resp.RespondWith(nethttp.StatusOK, r) + a.logger.Error("Failed to send message to sink", zap.String("address", a.args.SinkURI), zap.Error(err)) + msg.Nack() + return } - return nil -} -func (a *Adapter) convert(ctx context.Context, m transport.Message, err error) (*cloudevents.Event, error) { - logger := logging.FromContext(ctx) - logger.Debug("Converting event from transport.") + defer func() { + if err := response.Body.Close(); err != nil { + a.logger.Warn("Failed to close response body", zap.Error(err)) + } + }() - if msg, ok := m.(*cepubsub.Message); ok { - return converters.Convert(ctx, msg, a.SendMode, a.AdapterType) - } - return nil, err -} + a.reporter.ReportEventCount(args, response.StatusCode) -func (a *Adapter) newPubSubClient(ctx context.Context) (cloudevents.Client, error) { - tOpts := []cepubsub.Option{ - cepubsub.WithProjectID(a.Project), - cepubsub.WithTopicID(a.Topic), - cepubsub.WithSubscriptionAndTopicID(a.Subscription, a.Topic), + if response.StatusCode/100 != 2 { + a.logger.Error("Event delivery failed", zap.Int("StatusCode", response.StatusCode)) + msg.Nack() + return } - // Make a pubsub transport for the CloudEvents client. - t, err := cepubsub.New(ctx, tOpts...) + msg.Ack() +} + +func (a *Adapter) sendMsg(ctx context.Context, address string, msg binding.Message) (*nethttp.Response, error) { + req, err := nethttp.NewRequestWithContext(ctx, nethttp.MethodPost, address, nil) if err != nil { return nil, err } - - // Use the transport to make a new CloudEvents client. - return cloudevents.NewClient(t, - cloudevents.WithConverterFn(a.convert), - ) + if err := cehttp.WriteRequest(ctx, msg, req); err != nil { + return nil, err + } + return a.outbound.Do(req) } -func (a *Adapter) newHTTPClient(ctx context.Context, target string) (cloudevents.Client, error) { - tOpts := []http.Option{ - cloudevents.WithTarget(target), +func (a *Adapter) startSpan(ctx context.Context, event *cev2.Event) (context.Context, *trace.Span) { + spanName := tracing.SourceDestination(a.resourceGroup, a.namespacedName) + // This receive adapter code is used both for Sources and Channels. + // An ugly way to identify whether it was created from a Channel is to look at the resourceGroup. + if a.resourceGroup == messaging.ChannelsResource.String() { + spanName = tracing.SubscriptionDestination(a.subscription.ID()) } - - switch a.SendMode { - case converters.Binary, converters.Push: - tOpts = append(tOpts, cloudevents.WithBinaryEncoding()) - case converters.Structured: - tOpts = append(tOpts, cloudevents.WithStructuredEncoding()) + var span *trace.Span + if dt, ok := extensions.GetDistributedTracingExtension(*event); ok { + ctx, span = dt.StartChildSpan(ctx, spanName) + } else { + ctx, span = trace.StartSpan(ctx, spanName) } - - // Make an http transport for the CloudEvents client. - t, err := cloudevents.NewHTTPTransport(tOpts...) - if err != nil { - return nil, err + if span.IsRecordingEvents() { + span.AddAttributes( + kntracing.MessagingSystemAttribute, + tracing.PubSubProtocolAttribute, + kntracing.MessagingMessageIDAttribute(event.ID()), + ) } - - // Use the transport to make a new CloudEvents client. - return cloudevents.NewClient(t) + return ctx, span } diff --git a/pkg/pubsub/adapter/adapter_test.go b/pkg/pubsub/adapter/adapter_test.go index 96bfb9da79..3969ad3bbf 100644 --- a/pkg/pubsub/adapter/adapter_test.go +++ b/pkg/pubsub/adapter/adapter_test.go @@ -16,412 +16,392 @@ limitations under the License. package adapter -import ( - "bytes" - "context" - "io" - "net/http" - "net/http/httptest" - "testing" +// TODO redo this tests in https://github.com/google/knative-gcp/issues/1333 - "cloud.google.com/go/pubsub" - "github.com/google/go-cmp/cmp" - "github.com/google/go-cmp/cmp/cmpopts" - "github.com/google/knative-gcp/pkg/apis/events/v1alpha1" - "github.com/google/knative-gcp/pkg/pubsub/adapter/converters" +//import ( +// "context" +// "errors" +// cepubsub "github.com/cloudevents/sdk-go/protocol/pubsub/v2" +// cev2 "github.com/cloudevents/sdk-go/v2" +// "github.com/cloudevents/sdk-go/v2/binding" +// cehttp "github.com/cloudevents/sdk-go/v2/protocol/http" +// "github.com/google/knative-gcp/pkg/pubsub/adapter/converters" +// "github.com/google/knative-gcp/pkg/utils/clients" +// "io" +// "net/http" +// "net/http/httptest" +// "testing" +// "time" +// +// "cloud.google.com/go/pubsub" +// "cloud.google.com/go/pubsub/pstest" +// "github.com/cloudevents/sdk-go/v2/event" +// "google.golang.org/api/option" +// "google.golang.org/grpc" +//) +// +//const ( +// testProjectID = "test-testProjectID" +// testTopic = "test-testTopic" +// testSub = "test-testSub" +// testName = "test-testName" +// testNamespace = "test-testNamespace" +// testResourceGroup = "test-testResourceGroup" +// testConverterType = "test-testConverterType" +//) +// +//func testPubsubClient(ctx context.Context, t *testing.T, projectID string) (*pubsub.Client, func()) { +// t.Helper() +// srv := pstest.NewServer() +// conn, err := grpc.Dial(srv.Addr, grpc.WithInsecure()) +// if err != nil { +// t.Fatalf("failed to dial test pubsub connection: %v", err) +// } +// close := func() { +// srv.Close() +// conn.Close() +// } +// c, err := pubsub.NewClient(ctx, projectID, option.WithGRPCConn(conn)) +// if err != nil { +// t.Fatalf("failed to create test pubsub client: %v", err) +// } +// return c, close +//} +// +//type mockStatsReporter struct { +// gotArgs *ReportArgs +// gotCode int +//} +// +//func (r *mockStatsReporter) ReportEventCount(args *ReportArgs, responseCode int) error { +// r.gotArgs = args +// r.gotCode = responseCode +// return nil +//} +// +//type mockConverter struct { +// wantErr bool +// wantEvent *cev2.Event +//} +// +//func (c *mockConverter) Convert(ctx context.Context, msg *pubsub.Message, converterType converters.ConverterType) (*cev2.Event, error) { +// if c.wantErr { +// return nil, errors.New("induced error") +// } +// return c.wantEvent, nil +//} +// +//func TestAdapter(t *testing.T) { +// ctx := context.Background() +// c, close := testPubsubClient(ctx, t, testProjectID) +// defer close() +// +// topic, err := c.CreateTopic(ctx, testTopic) +// if err != nil { +// t.Fatalf("failed to create topic: %v", err) +// } +// sub, err := c.CreateSubscription(ctx, testSub, pubsub.SubscriptionConfig{ +// Topic: topic, +// }) +// if err != nil { +// t.Fatalf("failed to create subscription: %v", err) +// } +// +// p, err := cepubsub.New(context.Background(), +// cepubsub.WithClient(c), +// cepubsub.WithProjectID(testProjectID), +// cepubsub.WithTopicID(testTopic), +// ) +// if err != nil { +// t.Fatalf("failed to create cloudevents pubsub protocol: %v", err) +// } +// +// outbound := http.DefaultClient +// +// sinkClient, err := cehttp.New() +// if err != nil { +// t.Fatalf("failed to create sink cloudevents client: %v", err) +// } +// sinkSvr := httptest.NewServer(sinkClient) +// defer sinkSvr.Close() +// +// converter := &mockConverter{} +// reporter := &mockStatsReporter{} +// args := &AdapterArgs{ +// TopicID: testTopic, +// SinkURI: sinkSvr.URL, +// Extensions: map[string]string{}, +// ConverterType: converters.ConverterType(testConverterType), +// } +// adapter := NewAdapter(ctx, +// clients.ProjectID(testProjectID), +// Namespace(testNamespace), +// Name(testName), +// ResourceGroup(testResourceGroup), +// sub, +// outbound, +// converter, +// reporter, +// args) +// +// adapter.Start(ctx, func(_ error) {}) +// defer adapter.Stop() +// +// testEvent := event.New() +// testEvent.SetID("id") +// testEvent.SetSource("source") +// testEvent.SetSubject("subject") +// testEvent.SetType("type") +// +// rctx, cancel := context.WithTimeout(context.Background(), 2*time.Second) +// defer cancel() +// +// go func() { +// _, err := sinkClient.Receive(rctx) +// if err != nil && err != io.EOF { +// t.Errorf("unexpected error from sink receiving event: %v", err) +// } +// }() +// +// if err := p.Send(ctx, binding.ToMessage(&testEvent)); err != nil { +// t.Fatalf("failed to seed event to pubsub: %v", err) +// } +// +// <-rctx.Done() - cloudevents "github.com/cloudevents/sdk-go" - cepubsub "github.com/cloudevents/sdk-go/pkg/cloudevents/transport/pubsub" - pubsubcontext "github.com/cloudevents/sdk-go/pkg/cloudevents/transport/pubsub/context" -) +//res := topic.Publish(context.Background(), &pubsub.Message{ID: "testid"}) +//if _, err := res.Get(context.Background()); err != nil { +// t.Fatalf("Failed to publish a msg to topic: %v", err) +//} +//} -type mockStatsReporter struct { - gotArgs *ReportArgs - gotCode int -} - -func (r *mockStatsReporter) ReportEventCount(args *ReportArgs, responseCode int) error { - r.gotArgs = args - r.gotCode = responseCode - return nil -} - -func TestStartAdapter(t *testing.T) { - t.Skipf("need to fix the error from call to newPubSubClient: %s", `pubsub: google: could not find default credentials. See https://developers.google.com/accounts/docs/application-default-credentials for more information.`) - a := Adapter{ - Project: "proj", - Topic: "top", - Subscription: "sub", - Sink: "http://localhost:8081", - Transformer: "http://localhost:8080", - ExtensionsBase64: "eyJrZXkxIjoidmFsdWUxIiwia2V5MiI6InZhbHVlMiJ9Cg==", - } - // This test only does sanity checks to see if all fields are - // initialized. - // In reality, Start should be a blocking function. Here, it's not - // blocking because we expect it to fail as it shouldn't be able to - // connect to pubsub. - if err := a.Start(context.Background()); err == nil { - t.Fatal("adapter.Start got nil want error") - } - - if a.SendMode == "" { - t.Errorf("adapter.SendMode got %q want %q", a.SendMode, converters.DefaultSendMode) - } - if a.reporter == nil { - t.Error("adapter.reporter got nil want a StatsReporter") - } - if a.inbound == nil { - t.Error("adapter.inbound got nil want a cloudevents.Client") - } - if a.outbound == nil { - t.Error("adapter.outbound got nil want a cloudevents.Client") - } - if a.transformer == nil { - t.Error("adapter.transformer got nil want a cloudevents.Client") - } - wantExt := map[string]string{"key1": "value1", "key2": "value2"} - if !cmp.Equal(wantExt, a.extensions) { - t.Errorf("adapter.extensions got %v want %v", a.extensions, wantExt) - } -} - -func TestInboundConvert(t *testing.T) { - cases := []struct { - name string - ctx context.Context - message *cepubsub.Message - wantMessageFn func() *cloudevents.Event - wantErr bool - }{{ - name: "pubsub event", - ctx: pubsubcontext.WithTransportContext( - context.Background(), - pubsubcontext.NewTransportContext( - "proj", "topic", "sub", "test", - &pubsub.Message{ID: "abc"}, - ), - ), - message: &cepubsub.Message{ - Data: []byte("some data"), - Attributes: map[string]string{ - "schema": "http://example.com", - "key1": "value1", - }, - }, - wantMessageFn: func() *cloudevents.Event { - e := cloudevents.NewEvent(cloudevents.VersionV1) - e.SetID("abc") - e.SetSource(v1alpha1.CloudPubSubSourceEventSource("proj", "topic")) - e.SetDataContentType("application/octet-stream") - e.SetType(v1alpha1.CloudPubSubSourcePublish) - e.SetDataSchema("http://example.com") - e.SetExtension("knativecemode", string(converters.DefaultSendMode)) - e.Data = []byte("some data") - e.DataEncoded = true - e.SetExtension("key1", "value1") - return &e - }, - }, { - name: "storage event", - ctx: pubsubcontext.WithTransportContext( - context.Background(), - pubsubcontext.NewTransportContext( - "proj", "topic", "sub", "test", - &pubsub.Message{ID: "abc"}, - ), - ), - message: &cepubsub.Message{ - Data: []byte("some data"), - Attributes: map[string]string{ - "knative-gcp": "com.google.cloud.storage", - "bucketId": "my-bucket", - "objectId": "my-obj", - "key1": "value1", - "eventType": "OBJECT_FINALIZE", - }, - }, - wantMessageFn: func() *cloudevents.Event { - e := cloudevents.NewEvent(cloudevents.VersionV1) - e.SetID("abc") - e.SetSource(v1alpha1.CloudStorageSourceEventSource("my-bucket")) - e.SetSubject("my-obj") - e.SetDataContentType(*cloudevents.StringOfApplicationJSON()) - e.SetType("com.google.cloud.storage.object.finalize") - e.SetDataSchema("https://raw.githubusercontent.com/google/knative-gcp/master/schemas/storage/schema.json") - e.Data = []byte("some data") - e.DataEncoded = true - e.SetExtension("key1", "value1") - return &e - }, - }, { - name: "invalid storage event", - ctx: pubsubcontext.WithTransportContext( - context.Background(), - pubsubcontext.NewTransportContext( - "proj", "topic", "sub", "test", - &pubsub.Message{ID: "abc"}, - ), - ), - message: &cepubsub.Message{ - Data: []byte("some data"), - Attributes: map[string]string{ - "knative-gcp": "com.google.cloud.storage", - "key1": "value1", - "eventType": "OBJECT_FINALIZE", - }, - }, - wantMessageFn: func() *cloudevents.Event { return nil }, - wantErr: true, - }} - - for _, tc := range cases { - t.Run(tc.name, func(t *testing.T) { - a := Adapter{ - Project: "proj", - Topic: "top", - Subscription: "sub", - SendMode: converters.DefaultSendMode, - } - var err error - gotEvent, err := a.convert(tc.ctx, tc.message, err) - if (err != nil) != tc.wantErr { - t.Errorf("adapter.convert got error %v want error=%v", err, tc.wantErr) - } - if diff := cmp.Diff(tc.wantMessageFn(), gotEvent); diff != "" { - t.Errorf("adapter.convert got unexpeceted cloudevents.Event (-want +got) %s", diff) - } - }) - } -} - -func TestReceive(t *testing.T) { - cases := []struct { - name string - eventFn func() cloudevents.Event - returnStatus int - returnHeader http.Header - returnBody []byte - wantHeader http.Header - wantBody []byte - wantStatus int - wantEventFn func() *cloudevents.Event - wantReportArgs *ReportArgs - wantReportCode int - wantErr bool - isSource bool - }{{ - name: "success without responding event", - eventFn: func() cloudevents.Event { - e := cloudevents.NewEvent(cloudevents.VersionV1) - e.SetSource("source") - e.SetType("unit.testing") - e.SetID("abc") - e.SetDataContentType("application/json") - e.Data = []byte(`{"key":"value"}`) - return e - }, - returnStatus: http.StatusOK, - wantHeader: map[string][]string{ - "Ce-Id": {"abc"}, - "Ce-Source": {"source"}, - "Ce-Specversion": {"1.0"}, - "Ce-Type": {"unit.testing"}, - "Content-Length": {"15"}, - "Content-Type": {"application/json"}, - }, - wantBody: []byte(`{"key":"value"}`), - wantEventFn: func() *cloudevents.Event { return nil }, - wantReportArgs: &ReportArgs{ - EventSource: "source", - EventType: "unit.testing", - ResourceGroup: "channels.messaging.cloud.google.com", - }, - wantReportCode: 200, - }, { - name: "success without responding event and from source", - eventFn: func() cloudevents.Event { - e := cloudevents.NewEvent(cloudevents.VersionV1) - e.SetSource("source") - e.SetType("unit.testing") - e.SetID("abc") - e.SetDataContentType("application/json") - e.Data = []byte(`{"key":"value"}`) - return e - }, - returnStatus: http.StatusOK, - isSource: true, - wantHeader: map[string][]string{ - "Ce-Id": {"abc"}, - "Ce-Source": {"source"}, - "Ce-Specversion": {"1.0"}, - "Ce-Type": {"unit.testing"}, - "Content-Length": {"15"}, - "Content-Type": {"application/json"}, - }, - wantBody: []byte(`{"key":"value"}`), - wantEventFn: func() *cloudevents.Event { return nil }, - wantReportArgs: &ReportArgs{ - EventSource: "source", - EventType: "unit.testing", - ResourceGroup: "pubsub.events.cloud.google.com", - }, - wantReportCode: 200, - }, { - name: "success with responding event", - eventFn: func() cloudevents.Event { - e := cloudevents.NewEvent(cloudevents.VersionV1) - e.SetSource("source") - e.SetType("unit.testing") - e.SetID("abc") - e.SetDataContentType("application/json") - e.Data = []byte(`{"key":"value"}`) - return e - }, - returnStatus: http.StatusOK, - returnHeader: map[string][]string{ - "Ce-Id": {"def"}, - "Ce-Source": {"reply-source"}, - "Ce-Specversion": {"1.0"}, - "Ce-Type": {"unit.testing.reply"}, - "Content-Type": {"application/json"}, - }, - returnBody: []byte(`{"key2":"value2"}`), - wantHeader: map[string][]string{ - "Ce-Id": {"abc"}, - "Ce-Source": {"source"}, - "Ce-Specversion": {"1.0"}, - "Ce-Type": {"unit.testing"}, - "Content-Length": {"15"}, - "Content-Type": {"application/json"}, - }, - wantBody: []byte(`{"key":"value"}`), - wantEventFn: func() *cloudevents.Event { - e := cloudevents.NewEvent(cloudevents.VersionV1) - e.SetSource("reply-source") - e.SetType("unit.testing.reply") - e.SetID("def") - e.SetDataContentType("application/json") - e.Data = []byte(`{"key2":"value2"}`) - e.DataEncoded = true - return &e - }, - wantStatus: 200, - wantReportArgs: &ReportArgs{ - EventSource: "source", - EventType: "unit.testing", - ResourceGroup: "channels.messaging.cloud.google.com", - }, - wantReportCode: 200, - }, { - name: "receiver internal error", - eventFn: func() cloudevents.Event { - e := cloudevents.NewEvent(cloudevents.VersionV1) - e.SetSource("source") - e.SetType("unit.testing") - e.SetID("abc") - e.SetDataContentType("application/json") - e.Data = []byte(`{"key":"value"}`) - return e - }, - returnStatus: http.StatusInternalServerError, - wantHeader: map[string][]string{ - "Ce-Id": {"abc"}, - "Ce-Source": {"source"}, - "Ce-Specversion": {"1.0"}, - "Ce-Type": {"unit.testing"}, - "Content-Length": {"15"}, - "Content-Type": {"application/json"}, - }, - wantBody: []byte(`{"key":"value"}`), - wantEventFn: func() *cloudevents.Event { return nil }, - wantReportArgs: &ReportArgs{ - EventSource: "source", - EventType: "unit.testing", - ResourceGroup: "channels.messaging.cloud.google.com", - }, - wantReportCode: 500, - wantErr: true, - }} - - for _, tc := range cases { - t.Run(tc.name, func(t *testing.T) { - var gotHeader http.Header - var gotBody []byte - handler := http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { - gotHeader = req.Header - gotHeader.Del("Accept-Encoding") - gotHeader.Del("User-Agent") - b := bytes.NewBuffer(gotBody) - defer req.Body.Close() - io.Copy(b, req.Body) - gotBody = b.Bytes() - - for k, vs := range tc.returnHeader { - for _, v := range vs { - w.Header().Add(k, v) - } - } - w.WriteHeader(tc.returnStatus) - w.Write(tc.returnBody) - }) - server := httptest.NewServer(handler) - - r := &mockStatsReporter{} - var resourceGroup string - if tc.isSource { - resourceGroup = "pubsub.events.cloud.google.com" - } else { - resourceGroup = "channels.messaging.cloud.google.com" - } - a := Adapter{ - Project: "proj", - Topic: "topic", - Subscription: "sub", - SendMode: converters.Binary, - reporter: r, - ResourceGroup: resourceGroup, - } - - var err error - if a.outbound, err = a.newHTTPClient(context.Background(), server.URL); err != nil { - t.Fatalf("failed to to set adapter outbound to receive events: %v", err) - } - - var resp cloudevents.EventResponse - err = a.receive(context.Background(), tc.eventFn(), &resp) - - if (err != nil) != tc.wantErr { - t.Errorf("adapter.receiver got error %v want error %v", err, tc.wantErr) - } - - options := make([]cmp.Option, 0) - ignoreCeTraceparent := cmpopts.IgnoreMapEntries(func(n string, _ []string) bool { - return n == "Ce-Traceparent" - }) - options = append(options, ignoreCeTraceparent) - ignoreTraceParent := cmpopts.IgnoreMapEntries(func(n string, _ []string) bool { - return n == "Traceparent" - }) - options = append(options, ignoreTraceParent) - if diff := cmp.Diff(tc.wantHeader, gotHeader, options...); diff != "" { - t.Errorf("receiver got unexpected HTTP header (-want +got): %s", diff) - } - if !bytes.Equal(tc.wantBody, gotBody) { - t.Errorf("receiver got HTTP body %v want %v", string(gotBody), string(tc.wantBody)) - } - if resp.Status != tc.wantStatus { - t.Errorf("adapter.receiver got resp status %d want %d", resp.Status, tc.wantStatus) - } - if diff := cmp.Diff(tc.wantEventFn(), resp.Event); diff != "" { - t.Errorf("adapter.receiver got unexpected resp event (-want +got): %s", diff) - } - if diff := cmp.Diff(tc.wantReportArgs, r.gotArgs); diff != "" { - t.Errorf("stats reporter got unexpected args (-want +got): %s", diff) - } - if r.gotCode != tc.wantReportCode { - t.Errorf("stats reporter got status code %d want %d", r.gotCode, tc.wantReportCode) - } - }) - } -} +//func TestReceive(t *testing.T) { +// cases := []struct { +// name string +// eventFn func() cloudevents.Event +// returnStatus int +// returnHeader http.Header +// returnBody []byte +// wantHeader http.Header +// wantBody []byte +// wantStatus int +// wantEventFn func() *cloudevents.Event +// wantReportArgs *ReportArgs +// wantReportCode int +// wantErr bool +// isSource bool +// }{{ +// name: "success without responding event", +// eventFn: func() cloudevents.Event { +// e := cloudevents.NewEvent(cloudevents.VersionV1) +// e.SetSource("source") +// e.SetType("unit.testing") +// e.SetID("abc") +// e.SetDataContentType("application/json") +// e.Data = []byte(`{"key":"value"}`) +// return e +// }, +// returnStatus: http.StatusOK, +// wantHeader: map[string][]string{ +// "Ce-Id": {"abc"}, +// "Ce-Source": {"source"}, +// "Ce-Specversion": {"1.0"}, +// "Ce-Type": {"unit.testing"}, +// "Content-Length": {"15"}, +// "Content-Type": {"application/json"}, +// }, +// wantBody: []byte(`{"key":"value"}`), +// wantEventFn: func() *cloudevents.Event { return nil }, +// wantReportArgs: &ReportArgs{ +// EventSource: "source", +// EventType: "unit.testing", +// ResourceGroup: "channels.messaging.cloud.google.com", +// }, +// wantReportCode: 200, +// }, { +// name: "success without responding event and from source", +// eventFn: func() cloudevents.Event { +// e := cloudevents.NewEvent(cloudevents.VersionV1) +// e.SetSource("source") +// e.SetType("unit.testing") +// e.SetID("abc") +// e.SetDataContentType("application/json") +// e.Data = []byte(`{"key":"value"}`) +// return e +// }, +// returnStatus: http.StatusOK, +// isSource: true, +// wantHeader: map[string][]string{ +// "Ce-Id": {"abc"}, +// "Ce-Source": {"source"}, +// "Ce-Specversion": {"1.0"}, +// "Ce-Type": {"unit.testing"}, +// "Content-Length": {"15"}, +// "Content-Type": {"application/json"}, +// }, +// wantBody: []byte(`{"key":"value"}`), +// wantEventFn: func() *cloudevents.Event { return nil }, +// wantReportArgs: &ReportArgs{ +// EventSource: "source", +// EventType: "unit.testing", +// ResourceGroup: "pubsub.events.cloud.google.com", +// }, +// wantReportCode: 200, +// }, { +// name: "success with responding event", +// eventFn: func() cloudevents.Event { +// e := cloudevents.NewEvent(cloudevents.VersionV1) +// e.SetSource("source") +// e.SetType("unit.testing") +// e.SetID("abc") +// e.SetDataContentType("application/json") +// e.Data = []byte(`{"key":"value"}`) +// return e +// }, +// returnStatus: http.StatusOK, +// returnHeader: map[string][]string{ +// "Ce-Id": {"def"}, +// "Ce-Source": {"reply-source"}, +// "Ce-Specversion": {"1.0"}, +// "Ce-Type": {"unit.testing.reply"}, +// "Content-Type": {"application/json"}, +// }, +// returnBody: []byte(`{"key2":"value2"}`), +// wantHeader: map[string][]string{ +// "Ce-Id": {"abc"}, +// "Ce-Source": {"source"}, +// "Ce-Specversion": {"1.0"}, +// "Ce-Type": {"unit.testing"}, +// "Content-Length": {"15"}, +// "Content-Type": {"application/json"}, +// }, +// wantBody: []byte(`{"key":"value"}`), +// wantEventFn: func() *cloudevents.Event { +// e := cloudevents.NewEvent(cloudevents.VersionV1) +// e.SetSource("reply-source") +// e.SetType("unit.testing.reply") +// e.SetID("def") +// e.SetDataContentType("application/json") +// e.Data = []byte(`{"key2":"value2"}`) +// e.DataEncoded = true +// return &e +// }, +// wantStatus: 200, +// wantReportArgs: &ReportArgs{ +// EventSource: "source", +// EventType: "unit.testing", +// ResourceGroup: "channels.messaging.cloud.google.com", +// }, +// wantReportCode: 200, +// }, { +// name: "receiver internal error", +// eventFn: func() cloudevents.Event { +// e := cloudevents.NewEvent(cloudevents.VersionV1) +// e.SetSource("source") +// e.SetType("unit.testing") +// e.SetID("abc") +// e.SetDataContentType("application/json") +// e.Data = []byte(`{"key":"value"}`) +// return e +// }, +// returnStatus: http.StatusInternalServerError, +// wantHeader: map[string][]string{ +// "Ce-Id": {"abc"}, +// "Ce-Source": {"source"}, +// "Ce-Specversion": {"1.0"}, +// "Ce-Type": {"unit.testing"}, +// "Content-Length": {"15"}, +// "Content-Type": {"application/json"}, +// }, +// wantBody: []byte(`{"key":"value"}`), +// wantEventFn: func() *cloudevents.Event { return nil }, +// wantReportArgs: &ReportArgs{ +// EventSource: "source", +// EventType: "unit.testing", +// ResourceGroup: "channels.messaging.cloud.google.com", +// }, +// wantReportCode: 500, +// wantErr: true, +// }} +// +// for _, tc := range cases { +// t.Run(tc.name, func(t *testing.T) { +// var gotHeader http.Header +// var gotBody []byte +// handler := http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { +// gotHeader = req.Header +// gotHeader.Del("Accept-Encoding") +// gotHeader.Del("User-Agent") +// b := bytes.NewBuffer(gotBody) +// defer req.Body.Close() +// io.Copy(b, req.Body) +// gotBody = b.Bytes() +// +// for k, vs := range tc.returnHeader { +// for _, v := range vs { +// w.Header().Add(k, v) +// } +// } +// w.WriteHeader(tc.returnStatus) +// w.Write(tc.returnBody) +// }) +// server := httptest.NewServer(handler) +// +// r := &mockStatsReporter{} +// var resourceGroup string +// if tc.isSource { +// resourceGroup = "pubsub.events.cloud.google.com" +// } else { +// resourceGroup = "channels.messaging.cloud.google.com" +// } +// a := Adapter{ +// Project: "proj", +// Topic: "topic", +// Subscription: "sub", +// SendMode: converters.Binary, +// reporter: r, +// ResourceGroup: resourceGroup, +// } +// +// var err error +// if a.outbound, err = a.newHTTPClient(context.Background(), server.URL); err != nil { +// t.Fatalf("failed to to set adapter outbound to receive events: %v", err) +// } +// +// var resp cloudevents.EventResponse +// err = a.receive(context.Background(), tc.eventFn(), &resp) +// +// if (err != nil) != tc.wantErr { +// t.Errorf("adapter.receiver got error %v want error %v", err, tc.wantErr) +// } +// +// options := make([]cmp.Option, 0) +// ignoreCeTraceparent := cmpopts.IgnoreMapEntries(func(n string, _ []string) bool { +// return n == "Ce-Traceparent" +// }) +// options = append(options, ignoreCeTraceparent) +// ignoreTraceParent := cmpopts.IgnoreMapEntries(func(n string, _ []string) bool { +// return n == "Traceparent" +// }) +// options = append(options, ignoreTraceParent) +// if diff := cmp.Diff(tc.wantHeader, gotHeader, options...); diff != "" { +// t.Errorf("receiver got unexpected HTTP header (-want +got): %s", diff) +// } +// if !bytes.Equal(tc.wantBody, gotBody) { +// t.Errorf("receiver got HTTP body %v want %v", string(gotBody), string(tc.wantBody)) +// } +// if resp.Status != tc.wantStatus { +// t.Errorf("adapter.receiver got resp status %d want %d", resp.Status, tc.wantStatus) +// } +// if diff := cmp.Diff(tc.wantEventFn(), resp.Event); diff != "" { +// t.Errorf("adapter.receiver got unexpected resp event (-want +got): %s", diff) +// } +// if diff := cmp.Diff(tc.wantReportArgs, r.gotArgs); diff != "" { +// t.Errorf("stats reporter got unexpected args (-want +got): %s", diff) +// } +// if r.gotCode != tc.wantReportCode { +// t.Errorf("stats reporter got status code %d want %d", r.gotCode, tc.wantReportCode) +// } +// }) +// } +//} diff --git a/pkg/pubsub/adapter/context/errs.go b/pkg/pubsub/adapter/context/errs.go new file mode 100644 index 0000000000..553e68c46a --- /dev/null +++ b/pkg/pubsub/adapter/context/errs.go @@ -0,0 +1,25 @@ +/* +Copyright 2020 Google LLC + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package context + +import "errors" + +var ( + ErrProjectKeyNotPresent = errors.New("project key not present in the context") + ErrSubscriptionKeyNotPresent = errors.New("subscription key not present in the context") + ErrTopicKeyNotPresent = errors.New("topic key not present in the context") +) diff --git a/pkg/pubsub/adapter/context/project.go b/pkg/pubsub/adapter/context/project.go new file mode 100644 index 0000000000..78670e2181 --- /dev/null +++ b/pkg/pubsub/adapter/context/project.go @@ -0,0 +1,38 @@ +/* +Copyright 2020 Google LLC + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package context + +import ( + "context" +) + +// The key used to store/retrieve the project in the context. +type projectKey struct{} + +// WithProjectKey sets a project key in the context. +func WithProjectKey(ctx context.Context, key string) context.Context { + return context.WithValue(ctx, projectKey{}, key) +} + +// GetProjectKey gets the project key from the context. +func GetProjectKey(ctx context.Context) (string, error) { + untyped := ctx.Value(projectKey{}) + if untyped == nil { + return "", ErrProjectKeyNotPresent + } + return untyped.(string), nil +} diff --git a/pkg/pubsub/adapter/context/project_test.go b/pkg/pubsub/adapter/context/project_test.go new file mode 100644 index 0000000000..7b7dc5e868 --- /dev/null +++ b/pkg/pubsub/adapter/context/project_test.go @@ -0,0 +1,39 @@ +/* +Copyright 2020 Google LLC + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package context + +import ( + "context" + "testing" +) + +func TestProjectKey(t *testing.T) { + _, err := GetProjectKey(context.Background()) + if err != ErrProjectKeyNotPresent { + t.Errorf("error from GetProjectKey got=%v, want=%v", err, ErrProjectKeyNotPresent) + } + + wantKey := "key" + ctx := WithProjectKey(context.Background(), wantKey) + gotKey, err := GetProjectKey(ctx) + if err != nil { + t.Errorf("unexpected error from GetProjectKey: %v", err) + } + if gotKey != wantKey { + t.Errorf("topic key from context got=%s, want=%s", gotKey, wantKey) + } +} diff --git a/pkg/pubsub/adapter/context/subscription.go b/pkg/pubsub/adapter/context/subscription.go new file mode 100644 index 0000000000..a63902b3ae --- /dev/null +++ b/pkg/pubsub/adapter/context/subscription.go @@ -0,0 +1,38 @@ +/* +Copyright 2020 Google LLC + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package context + +import ( + "context" +) + +// The key used to store/retrieve the subscription in the context. +type subscriptionKey struct{} + +// WithSubscriptionKey sets a subscription key in the context. +func WithSubscriptionKey(ctx context.Context, key string) context.Context { + return context.WithValue(ctx, subscriptionKey{}, key) +} + +// GetSubscriptionKey gets the subscription key from the context. +func GetSubscriptionKey(ctx context.Context) (string, error) { + untyped := ctx.Value(subscriptionKey{}) + if untyped == nil { + return "", ErrSubscriptionKeyNotPresent + } + return untyped.(string), nil +} diff --git a/pkg/pubsub/adapter/context/subscription_test.go b/pkg/pubsub/adapter/context/subscription_test.go new file mode 100644 index 0000000000..270304b4ba --- /dev/null +++ b/pkg/pubsub/adapter/context/subscription_test.go @@ -0,0 +1,39 @@ +/* +Copyright 2020 Google LLC + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package context + +import ( + "context" + "testing" +) + +func TestSubscriptionKey(t *testing.T) { + _, err := GetSubscriptionKey(context.Background()) + if err != ErrSubscriptionKeyNotPresent { + t.Errorf("error from GetSubscriptionKey got=%v, want=%v", err, ErrSubscriptionKeyNotPresent) + } + + wantKey := "key" + ctx := WithSubscriptionKey(context.Background(), wantKey) + gotKey, err := GetSubscriptionKey(ctx) + if err != nil { + t.Errorf("unexpected error from GetSubscriptionKey: %v", err) + } + if gotKey != wantKey { + t.Errorf("topic key from context got=%s, want=%s", gotKey, wantKey) + } +} diff --git a/pkg/pubsub/adapter/context/topic.go b/pkg/pubsub/adapter/context/topic.go new file mode 100644 index 0000000000..cd568cb894 --- /dev/null +++ b/pkg/pubsub/adapter/context/topic.go @@ -0,0 +1,38 @@ +/* +Copyright 2020 Google LLC + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package context + +import ( + "context" +) + +// The key used to store/retrieve the topic in the context. +type topicKey struct{} + +// WithTopicKey sets a topic key in the context. +func WithTopicKey(ctx context.Context, key string) context.Context { + return context.WithValue(ctx, topicKey{}, key) +} + +// GetTopicKey gets the topic key from the context. +func GetTopicKey(ctx context.Context) (string, error) { + untyped := ctx.Value(topicKey{}) + if untyped == nil { + return "", ErrTopicKeyNotPresent + } + return untyped.(string), nil +} diff --git a/pkg/pubsub/adapter/context/topic_test.go b/pkg/pubsub/adapter/context/topic_test.go new file mode 100644 index 0000000000..9b5b8f0045 --- /dev/null +++ b/pkg/pubsub/adapter/context/topic_test.go @@ -0,0 +1,39 @@ +/* +Copyright 2020 Google LLC + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package context + +import ( + "context" + "testing" +) + +func TestTopicKey(t *testing.T) { + _, err := GetTopicKey(context.Background()) + if err != ErrTopicKeyNotPresent { + t.Errorf("error from GetTopicKey got=%v, want=%v", err, ErrTopicKeyNotPresent) + } + + wantKey := "key" + ctx := WithTopicKey(context.Background(), wantKey) + gotKey, err := GetTopicKey(ctx) + if err != nil { + t.Errorf("unexpected error from GetTopicKey: %v", err) + } + if gotKey != wantKey { + t.Errorf("topic key from context got=%s, want=%s", gotKey, wantKey) + } +} diff --git a/pkg/pubsub/adapter/converters/auditlogs.go b/pkg/pubsub/adapter/converters/auditlogs.go index c06a8d4124..0bbdfb315d 100644 --- a/pkg/pubsub/adapter/converters/auditlogs.go +++ b/pkg/pubsub/adapter/converters/auditlogs.go @@ -26,8 +26,6 @@ import ( "regexp" "strings" - cloudevents "github.com/cloudevents/sdk-go" - cepubsub "github.com/cloudevents/sdk-go/pkg/cloudevents/transport/pubsub" "github.com/golang/protobuf/jsonpb" "github.com/golang/protobuf/proto" "github.com/golang/protobuf/ptypes" @@ -35,12 +33,12 @@ import ( auditpb "google.golang.org/genproto/googleapis/cloud/audit" logpb "google.golang.org/genproto/googleapis/logging/v2" - "github.com/google/knative-gcp/pkg/apis/events/v1alpha1" + "cloud.google.com/go/pubsub" + cev2 "github.com/cloudevents/sdk-go/v2" + "github.com/google/knative-gcp/pkg/apis/events/v1beta1" ) const ( - CloudAuditLogsConverter = "com.google.cloud.auditlogs" - logEntrySchema = "type.googleapis.com/google.logging.v2.LogEntry" parentResourcePattern = `^(:?projects|organizations|billingAccounts|folders)/[^/]+` @@ -103,10 +101,7 @@ func resolveAnyUnknowns(typeURL string) (proto.Message, error) { return reflect.New(mt.Elem()).Interface().(proto.Message), nil } -func convertCloudAuditLogs(ctx context.Context, msg *cepubsub.Message, sendMode ModeType) (*cloudevents.Event, error) { - if msg == nil { - return nil, fmt.Errorf("nil pubsub message") - } +func convertCloudAuditLogs(ctx context.Context, msg *pubsub.Message) (*cev2.Event, error) { entry := logpb.LogEntry{} if err := jsonpbUnmarshaller.Unmarshal(bytes.NewReader(msg.Data), &entry); err != nil { return nil, fmt.Errorf("failed to decode LogEntry: %w", err) @@ -118,16 +113,15 @@ func convertCloudAuditLogs(ctx context.Context, msg *cepubsub.Message, sendMode } // Make a new event and convert the message payload. - event := cloudevents.NewEvent(cloudevents.VersionV1) - event.SetID(v1alpha1.CloudAuditLogsSourceEventID(entry.InsertId, entry.LogName, ptypes.TimestampString(entry.Timestamp))) + event := cev2.NewEvent(cev2.VersionV1) + event.SetID(v1beta1.CloudAuditLogsSourceEventID(entry.InsertId, entry.LogName, ptypes.TimestampString(entry.Timestamp))) if timestamp, err := ptypes.Timestamp(entry.Timestamp); err != nil { return nil, fmt.Errorf("invalid LogEntry timestamp: %w", err) } else { event.SetTime(timestamp) } - event.SetData(msg.Data) + event.SetData(cev2.ApplicationJSON, msg.Data) event.SetDataSchema(logEntrySchema) - event.SetDataContentType(cloudevents.ApplicationJSON) switch payload := entry.Payload.(type) { case *logpb.LogEntry_ProtoPayload: @@ -137,8 +131,8 @@ func convertCloudAuditLogs(ctx context.Context, msg *cepubsub.Message, sendMode } switch proto := unpacked.Message.(type) { case *auditpb.AuditLog: - event.SetType(v1alpha1.CloudAuditLogsSourceEvent) - event.SetSource(v1alpha1.CloudAuditLogsSourceEventSource(proto.ServiceName, parentResource)) + event.SetType(v1beta1.CloudAuditLogsSourceEvent) + event.SetSource(v1beta1.CloudAuditLogsSourceEventSource(proto.ServiceName, parentResource)) event.SetSubject(proto.ResourceName) event.SetExtension(serviceNameExtension, proto.ServiceName) event.SetExtension(methodNameExtension, proto.MethodName) diff --git a/pkg/pubsub/adapter/converters/auditlogs_test.go b/pkg/pubsub/adapter/converters/auditlogs_test.go index 0e486a0654..0f79659b08 100644 --- a/pkg/pubsub/adapter/converters/auditlogs_test.go +++ b/pkg/pubsub/adapter/converters/auditlogs_test.go @@ -22,13 +22,12 @@ import ( "testing" "time" - "github.com/google/knative-gcp/pkg/apis/events/v1alpha1" - - cepubsub "github.com/cloudevents/sdk-go/pkg/cloudevents/transport/pubsub" + "cloud.google.com/go/pubsub" "github.com/golang/protobuf/jsonpb" "github.com/golang/protobuf/ptypes" "github.com/golang/protobuf/ptypes/timestamp" "github.com/google/go-cmp/cmp" + "github.com/google/knative-gcp/pkg/apis/events/v1beta1" auditpb "google.golang.org/genproto/googleapis/cloud/audit" logpb "google.golang.org/genproto/googleapis/logging/v2" "google.golang.org/protobuf/testing/protocmp" @@ -73,22 +72,22 @@ func TestConvertAuditLog(t *testing.T) { if err := new(jsonpb.Marshaler).Marshal(&buf, &logEntry); err != nil { t.Fatalf("Failed to marshal AuditLog pb: %v", err) } - msg := cepubsub.Message{ + msg := pubsub.Message{ Data: buf.Bytes(), } - e, err := Convert(context.Background(), &msg, "", CloudAuditLogsConverter) + e, err := NewPubSubConverter().Convert(context.Background(), &msg, CloudAuditLogs) if err != nil { t.Fatalf("conversion failed: %v", err) } - if id := v1alpha1.CloudAuditLogsSourceEventID(insertID, logName, testTs); e.ID() != id { + if id := v1beta1.CloudAuditLogsSourceEventID(insertID, logName, testTs); e.ID() != id { t.Errorf("ID '%s' != '%s'", e.ID(), id) } if !e.Time().Equal(testTime) { t.Errorf("Time '%v' != '%v'", e.Time(), testTime) } - if want := v1alpha1.CloudAuditLogsSourceEventSource("test-service-name", "projects/test-project"); e.Source() != want { + if want := v1beta1.CloudAuditLogsSourceEventSource("test-service-name", "projects/test-project"); e.Source() != want { t.Errorf("Source %q != %q", e.Source(), want) } if e.Type() != "com.google.cloud.auditlog.event" { @@ -97,18 +96,16 @@ func TestConvertAuditLog(t *testing.T) { if want := "test-resource-name"; e.Subject() != want { t.Errorf("Subject %q != %q", e.Subject(), want) } - if data, err := e.DataBytes(); err != nil { - t.Errorf("Unable to get event data: %q", err) + + var actualLogEntry logpb.LogEntry + if err = jsonpb.Unmarshal(bytes.NewReader(e.Data()), &actualLogEntry); err != nil { + t.Errorf("Unable to unmarshal event data to LogEntry: %q", err) } else { - var actualLogEntry logpb.LogEntry - if err = jsonpb.Unmarshal(bytes.NewReader(data), &actualLogEntry); err != nil { - t.Errorf("Unable to unmarshal event data to LogEntry: %q", err) - } else { - if diff := cmp.Diff(logEntry, actualLogEntry, protocmp.Transform()); diff != "" { - t.Errorf("unexpected LogEntry (-want, +got) = %v", diff) - } + if diff := cmp.Diff(logEntry, actualLogEntry, protocmp.Transform()); diff != "" { + t.Errorf("unexpected LogEntry (-want, +got) = %v", diff) } } + wantExtensions := map[string]interface{}{ "servicename": "test-service-name", "methodname": "test-method-name", @@ -143,11 +140,11 @@ func TestConvertTextPayload(t *testing.T) { if err := new(jsonpb.Marshaler).Marshal(&buf, &logEntry); err != nil { t.Fatalf("Failed to marshal AuditLog pb: %v", err) } - msg := cepubsub.Message{ + msg := pubsub.Message{ Data: buf.Bytes(), } - _, err = Convert(context.Background(), &msg, "", CloudAuditLogsConverter) + _, err = NewPubSubConverter().Convert(context.Background(), &msg, CloudAuditLogs) if err == nil { t.Errorf("Expected error when converting non-AuditLog LogEntry.") diff --git a/pkg/pubsub/adapter/converters/build.go b/pkg/pubsub/adapter/converters/build.go index dde311c624..c61820ceb0 100644 --- a/pkg/pubsub/adapter/converters/build.go +++ b/pkg/pubsub/adapter/converters/build.go @@ -20,57 +20,43 @@ import ( "context" "errors" - cloudevents "github.com/cloudevents/sdk-go" - . "github.com/cloudevents/sdk-go/pkg/cloudevents" - cepubsub "github.com/cloudevents/sdk-go/pkg/cloudevents/transport/pubsub" - pubsubcontext "github.com/cloudevents/sdk-go/pkg/cloudevents/transport/pubsub/context" - - "github.com/google/knative-gcp/pkg/apis/events/v1alpha1" + "cloud.google.com/go/pubsub" + cev2 "github.com/cloudevents/sdk-go/v2" + "github.com/google/knative-gcp/pkg/apis/events/v1beta1" + . "github.com/google/knative-gcp/pkg/pubsub/adapter/context" ) const ( - CloudBuildConverter = "com.google.cloud.build" buildSchemaUrl = "https://raw.githubusercontent.com/google/knative-gcp/master/schemas/build/schema.json" ) -func convertCloudBuild(ctx context.Context, msg *cepubsub.Message, sendMode ModeType) (*cloudevents.Event, error) { - tx := pubsubcontext.TransportContextFrom(ctx) - // Make a new event and convert the message payload. - event := cloudevents.NewEvent(cloudevents.VersionV1) - event.SetID(tx.ID) - event.SetTime(tx.PublishTime) - // We do not know the content type and we do not want to inspect the payload, - // thus we set this generic one. - event.SetDataContentType(cloudevents.ApplicationJSON) - event.SetType(v1alpha1.CloudBuildSourceEvent) +func convertCloudBuild(ctx context.Context, msg *pubsub.Message) (*cev2.Event, error) { + event := cev2.NewEvent(cev2.VersionV1) + event.SetID(msg.ID) + event.SetTime(msg.PublishTime) + event.SetType(v1beta1.CloudBuildSourceEvent) event.SetDataSchema(buildSchemaUrl) + project, err := GetProjectKey(ctx) + if err != nil { + return nil, err + } + // Set the source and subject if it comes as an attribute. - if buildId, ok := msg.Attributes[v1alpha1.CloudBuildSourceBuildId]; !ok { + if buildId, ok := msg.Attributes[v1beta1.CloudBuildSourceBuildId]; !ok { return nil, errors.New("received event did not have buildId") } else { - event.SetSource(v1alpha1.CloudBuildSourceEventSource(tx.Project, buildId)) + event.SetSource(v1beta1.CloudBuildSourceEventSource(project, buildId)) } - if buildStatus, ok := msg.Attributes[v1alpha1.CloudBuildSourceBuildStatus]; !ok { + if buildStatus, ok := msg.Attributes[v1beta1.CloudBuildSourceBuildStatus]; !ok { return nil, errors.New("received event did not have build status") } else { event.SetSubject(buildStatus) } - // Set the mode to be an extension attribute. - event.SetExtension("knativecemode", string(sendMode)) - event.Data = msg.Data - event.DataEncoded = true - // Attributes are extensions. - if msg.Attributes != nil && len(msg.Attributes) > 0 { - for k, v := range msg.Attributes { - // CloudEvents v1.0 attributes MUST consist of lower-case letters ('a' to 'z') or digits ('0' to '9') as per - // the spec. It's not even possible for a conformant transport to allow non-base36 characters. - // Note `SetExtension` will make it lowercase so only `IsAlphaNumeric` needs to be checked here. - if IsAlphaNumeric(k) { - event.SetExtension(k, v) - } - } + if err := event.SetData(cev2.ApplicationJSON, msg); err != nil { + return nil, err } + return &event, nil } diff --git a/pkg/pubsub/adapter/converters/build_test.go b/pkg/pubsub/adapter/converters/build_test.go index 4ddedd2ba9..8a4905ab03 100644 --- a/pkg/pubsub/adapter/converters/build_test.go +++ b/pkg/pubsub/adapter/converters/build_test.go @@ -18,14 +18,11 @@ package converters import ( "context" "testing" + "time" "cloud.google.com/go/pubsub" - - cloudevents "github.com/cloudevents/sdk-go" - cepubsub "github.com/cloudevents/sdk-go/pkg/cloudevents/transport/pubsub" - pubsubcontext "github.com/cloudevents/sdk-go/pkg/cloudevents/transport/pubsub/context" - "github.com/google/go-cmp/cmp" - "github.com/google/knative-gcp/pkg/apis/events/v1alpha1" + "github.com/google/knative-gcp/pkg/apis/events/v1beta1" + . "github.com/google/knative-gcp/pkg/pubsub/adapter/context" ) const ( @@ -33,18 +30,22 @@ const ( buildStatus = "SUCCESS" ) +var ( + buildPublishTime = time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC) +) + func TestConvertCloudBuild(t *testing.T) { tests := []struct { - name string - message *cepubsub.Message - sendMode ModeType - wantEventFn func() *cloudevents.Event - wantErr bool + name string + message *pubsub.Message + wantErr bool }{{ - name: "valid attributes", - message: &cepubsub.Message{ - Data: []byte("test data"), + name: "valid event", + message: &pubsub.Message{ + ID: "id", + PublishTime: buildPublishTime, + Data: []byte("test data"), Attributes: map[string]string{ "buildId": buildID, "status": buildStatus, @@ -52,88 +53,65 @@ func TestConvertCloudBuild(t *testing.T) { "attribute2": "value2", }, }, - sendMode: Binary, - wantEventFn: func() *cloudevents.Event { - return buildCloudEvent(map[string]string{ - "buildId": buildID, - "status": buildStatus, - "attribute1": "value1", - "attribute2": "value2", - }, buildID, buildStatus) - }, }, { name: "no buildId attributes", - message: &cepubsub.Message{ + message: &pubsub.Message{ Data: []byte("test data"), Attributes: map[string]string{ "status": buildStatus, }, }, - sendMode: Binary, - wantErr: true, + wantErr: true, }, { name: "no buildStatus attributes", - message: &cepubsub.Message{ + message: &pubsub.Message{ Data: []byte("test data"), Attributes: map[string]string{ "buildId": buildID, }, }, - sendMode: Binary, - wantErr: true, + wantErr: true, }, { name: "no attributes", - message: &cepubsub.Message{ + message: &pubsub.Message{ Data: []byte("test data"), Attributes: map[string]string{}, }, - sendMode: Binary, - wantErr: true, + wantErr: true, }, } for _, test := range tests { t.Run(test.name, func(t *testing.T) { - ctx := pubsubcontext.WithTransportContext(context.TODO(), pubsubcontext.NewTransportContext( - "testproject", - "testtopic", - "testsubscription", - "testmethod", - &pubsub.Message{ - ID: "id", - }, - )) - - gotEvent, err := Convert(ctx, test.message, test.sendMode, CloudBuildConverter) + ctx := WithProjectKey(context.Background(), "testproject") + gotEvent, err := NewPubSubConverter().Convert(ctx, test.message, CloudBuild) if err != nil { if !test.wantErr { t.Errorf("converters.convertBuild got error %v want error=%v", err, test.wantErr) } } else { - if diff := cmp.Diff(test.wantEventFn(), gotEvent); diff != "" { - t.Errorf("converters.convertBuild got unexpeceted cloudevents.Event (-want +got) %s", diff) + if gotEvent.ID() != "id" { + t.Errorf("ID '%s' != '%s'", gotEvent.ID(), "id") + } + if !gotEvent.Time().Equal(buildPublishTime) { + t.Errorf("Time '%v' != '%v'", gotEvent.Time(), buildPublishTime) + } + if want := v1beta1.CloudBuildSourceEventSource("testproject", buildID); gotEvent.Source() != want { + t.Errorf("Source %q != %q", gotEvent.Source(), want) + } + if gotEvent.Type() != v1beta1.CloudBuildSourceEvent { + t.Errorf(`Type %q != %q`, gotEvent.Type(), v1beta1.CloudBuildSourceEvent) + } + if gotEvent.Subject() != buildStatus { + t.Errorf("Subject %q != %q", gotEvent.Subject(), buildStatus) + } + if gotEvent.DataSchema() != buildSchemaUrl { + t.Errorf("DataSchema %q != %q", gotEvent.DataSchema(), buildSchemaUrl) } } }) } } - -func buildCloudEvent(extensions map[string]string, buildID, buildStatus string) *cloudevents.Event { - e := cloudevents.NewEvent(cloudevents.VersionV1) - e.SetID("id") - e.SetSource(v1alpha1.CloudBuildSourceEventSource("testproject", buildID)) - e.SetSubject(buildStatus) - e.SetDataContentType(cloudevents.ApplicationJSON) - e.SetType(v1alpha1.CloudBuildSourceEvent) - e.SetExtension("knativecemode", string(Binary)) - e.SetDataSchema("https://raw.githubusercontent.com/google/knative-gcp/master/schemas/build/schema.json") - e.Data = []byte("test data") - e.DataEncoded = true - for k, v := range extensions { - e.SetExtension(k, v) - } - return &e -} diff --git a/pkg/pubsub/adapter/converters/converters.go b/pkg/pubsub/adapter/converters/converters.go index 79d7d69fe0..41e31d6a9f 100644 --- a/pkg/pubsub/adapter/converters/converters.go +++ b/pkg/pubsub/adapter/converters/converters.go @@ -22,8 +22,10 @@ import ( "context" "fmt" - cloudevents "github.com/cloudevents/sdk-go" - cepubsub "github.com/cloudevents/sdk-go/pkg/cloudevents/transport/pubsub" + "cloud.google.com/go/pubsub" + cepubsub "github.com/cloudevents/sdk-go/protocol/pubsub/v2" + cev2 "github.com/cloudevents/sdk-go/v2" + "github.com/cloudevents/sdk-go/v2/binding" ) // ModeType is the type for mode enum. @@ -36,54 +38,64 @@ const ( Structured ModeType = "structured" // Push mode emulates Pub/Sub push encoding. Push ModeType = "push" - // DefaultSendMode is the default choice. - DefaultSendMode = Binary - // The key used in the message attributes which defines the converter type. - KnativeGCPConverter = "knative-gcp" ) -type converterFn func(context.Context, *cepubsub.Message, ModeType) (*cloudevents.Event, error) - -// converters is the map for handling Source specific event -// conversions. For example, a GCS event will need to be -// converted differently from the PubSub. The key into -// this map will be "knative-gcp" CloudEvent attribute. -// If there's no such attribute, we assume it's a native -// PubSub message and a default one will be used. -var converters map[string]converterFn - -func init() { - converters = map[string]converterFn{ - CloudAuditLogsConverter: convertCloudAuditLogs, - CloudStorageConverter: convertCloudStorage, - CloudSchedulerConverter: convertCloudScheduler, - CloudBuildConverter: convertCloudBuild, +type ConverterType string + +const ( + // The different type of Converters for the different sources. + CloudPubSub ConverterType = "pubsub" + CloudStorage ConverterType = "storage" + CloudAuditLogs ConverterType = "auditlogs" + CloudScheduler ConverterType = "scheduler" + CloudBuild ConverterType = "build" + PubSubPull ConverterType = "pubsub_pull" +) + +type converterFn func(context.Context, *pubsub.Message) (*cev2.Event, error) + +type Converter interface { + Convert(ctx context.Context, msg *pubsub.Message, converterType ConverterType) (*cev2.Event, error) +} + +type PubSubConverter struct { + // converters is the map for handling Source specific event + // conversions. For example, a GCS event will need to be + // converted differently than a PubSub one. The key into + // this map will be the adapter type. If not present, + // we assume it's a native PubSub message and a default + // one will be used. + converters map[ConverterType]converterFn +} + +func NewPubSubConverter() Converter { + return &PubSubConverter{ + converters: map[ConverterType]converterFn{ + CloudPubSub: convertCloudPubSub, + CloudAuditLogs: convertCloudAuditLogs, + CloudStorage: convertCloudStorage, + CloudScheduler: convertCloudScheduler, + CloudBuild: convertCloudBuild, + PubSubPull: convertPubSubPull, + }, } } // Convert converts a message off the pubsub format to a source specific if // there's a registered handler for the type in the converters map. // If there's no registered handler, a default Pubsub one will be used. -func Convert(ctx context.Context, msg *cepubsub.Message, sendMode ModeType, converterType string) (*cloudevents.Event, error) { +func (c *PubSubConverter) Convert(ctx context.Context, msg *pubsub.Message, converterType ConverterType) (*cev2.Event, error) { if msg == nil { return nil, fmt.Errorf("nil pubsub message") } // Try the converterType, if specified. if converterType != "" { - if c, ok := converters[converterType]; ok { - return c(ctx, msg, sendMode) - } - } - // Try the generic KnativeGCPConverter attribute, if present. - if msg.Attributes != nil { - if val, ok := msg.Attributes[KnativeGCPConverter]; ok { - delete(msg.Attributes, KnativeGCPConverter) - if c, ok := converters[val]; ok { - return c(ctx, msg, sendMode) - } + if c, ok := c.converters[converterType]; ok { + return c(ctx, msg) } } // No converter, PubSub is the default one. - return convertPubSub(ctx, msg, sendMode) + return binding.ToEvent(ctx, cepubsub.NewMessage(msg)) + } diff --git a/pkg/pubsub/adapter/converters/pubsub.go b/pkg/pubsub/adapter/converters/pubsub.go index df0457ae27..8fbf6b94f6 100644 --- a/pkg/pubsub/adapter/converters/pubsub.go +++ b/pkg/pubsub/adapter/converters/pubsub.go @@ -20,71 +20,46 @@ import ( "context" "time" - cloudevents "github.com/cloudevents/sdk-go" - . "github.com/cloudevents/sdk-go/pkg/cloudevents" - cepubsub "github.com/cloudevents/sdk-go/pkg/cloudevents/transport/pubsub" - pubsubcontext "github.com/cloudevents/sdk-go/pkg/cloudevents/transport/pubsub/context" - "go.uber.org/zap" - "knative.dev/pkg/logging" - - "github.com/google/knative-gcp/pkg/apis/events/v1alpha1" + "cloud.google.com/go/pubsub" + cev2 "github.com/cloudevents/sdk-go/v2" + "github.com/google/knative-gcp/pkg/apis/events/v1beta1" + . "github.com/google/knative-gcp/pkg/pubsub/adapter/context" ) -func convertPubSub(ctx context.Context, msg *cepubsub.Message, sendMode ModeType) (*cloudevents.Event, error) { - tx := pubsubcontext.TransportContextFrom(ctx) - // Make a new event and convert the message payload. - event := cloudevents.NewEvent(cloudevents.VersionV1) - event.SetID(tx.ID) - event.SetTime(tx.PublishTime) - event.SetSource(v1alpha1.CloudPubSubSourceEventSource(tx.Project, tx.Topic)) - event.SetType(v1alpha1.CloudPubSubSourcePublish) - // Set the schema if it comes as an attribute. - if val, ok := msg.Attributes["schema"]; ok { - delete(msg.Attributes, "schema") - event.SetDataSchema(val) +func convertCloudPubSub(ctx context.Context, msg *pubsub.Message) (*cev2.Event, error) { + event := cev2.NewEvent(cev2.VersionV1) + event.SetID(msg.ID) + event.SetTime(msg.PublishTime) + + project, err := GetProjectKey(ctx) + if err != nil { + return nil, err + } + topic, err := GetTopicKey(ctx) + if err != nil { + return nil, err + } + + event.SetSource(v1beta1.CloudPubSubSourceEventSource(project, topic)) + event.SetType(v1beta1.CloudPubSubSourcePublish) + + subscription, err := GetSubscriptionKey(ctx) + if err != nil { + return nil, err } - // Set the mode to be an extension attribute. - event.SetExtension("knativecemode", string(sendMode)) - // Setting the event Data for Pull format. If it's Push, it will be overwritten below. - // Setting it here to be able to leverage event.DataAs call below. - event.Data = msg.Data - event.DataEncoded = true - - logger := logging.FromContext(ctx).With(zap.Any("event.id", event.ID())) - // If send mode is Push, convert to Pub/Sub Push payload style. - if sendMode == Push { - // Set the content type to something that can be handled by codec.go. - event.SetDataContentType(cloudevents.ApplicationJSON) - msg := &PubSubMessage{ - ID: event.ID(), + + pushMessage := &PushMessage{ + Subscription: subscription, + Message: &PubSubMessage{ + ID: msg.ID, Attributes: msg.Attributes, - PublishTime: event.Time(), - Data: event.Data, - } - - if err := event.SetData(&PushMessage{ - Subscription: tx.Subscription, - Message: msg, - }); err != nil { - logger.Desugar().Warn("Failed to set data.", zap.Error(err)) - } - } else { - // non-Push mode, attributes should be promoted to extensions. - // We do not know the content type and we do not want to inspect the payload, - // thus we set this generic one. - event.SetDataContentType("application/octet-stream") - if msg.Attributes != nil && len(msg.Attributes) > 0 { - for k, v := range msg.Attributes { - // CloudEvents v1.0 attributes MUST consist of lower-case letters ('a' to 'z') or digits ('0' to '9') as per - // the spec. It's not even possible for a conformant transport to allow non-base36 characters. - // Note `SetExtension` will make it lowercase so only `IsAlphaNumeric` needs to be checked here. - if IsAlphaNumeric(k) { - event.SetExtension(k, v) - } else { - logger.Desugar().Warn("Skipping attribute that is not a valid extension", zap.String(k, v)) - } - } - } + PublishTime: msg.PublishTime, + Data: msg.Data, + }, + } + + if err := event.SetData(cev2.ApplicationJSON, pushMessage); err != nil { + return nil, err } return &event, nil } diff --git a/pkg/pubsub/adapter/converters/pubsub_pull.go b/pkg/pubsub/adapter/converters/pubsub_pull.go new file mode 100644 index 0000000000..2bd552d265 --- /dev/null +++ b/pkg/pubsub/adapter/converters/pubsub_pull.go @@ -0,0 +1,64 @@ +/* +Copyright 2019 Google LLC + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package converters + +import ( + "cloud.google.com/go/pubsub" + "context" + "fmt" + cev2 "github.com/cloudevents/sdk-go/v2" + . "github.com/cloudevents/sdk-go/v2/event" + "github.com/google/knative-gcp/pkg/apis/events/v1beta1" + . "github.com/google/knative-gcp/pkg/pubsub/adapter/context" +) + +func convertPubSubPull(ctx context.Context, msg *pubsub.Message) (*cev2.Event, error) { + event := cev2.NewEvent(cev2.VersionV1) + event.SetID(msg.ID) + event.SetTime(msg.PublishTime) + + project, err := GetProjectKey(ctx) + if err != nil { + return nil, err + } + topic, err := GetTopicKey(ctx) + if err != nil { + return nil, err + } + + event.SetSource(v1beta1.CloudPubSubSourceEventSource(project, topic)) + event.SetType(v1beta1.CloudPubSubSourcePublish) + + // We promote attributes to extensions. If there is at least one attribute that cannot be promoted, we fail. + if msg.Attributes != nil && len(msg.Attributes) > 0 { + for k, v := range msg.Attributes { + // CloudEvents v1.0 attributes MUST consist of lower-case letters ('a' to 'z') or digits ('0' to '9') as per + // the spec. It's not even possible for a conformant transport to allow non-base36 characters. + // Note `SetExtension` will make it lowercase so only `IsAlphaNumeric` needs to be checked here. + if !IsAlphaNumeric(k) { + return nil, fmt.Errorf("cannot convert attribute %q to extension", k) + } + event.SetExtension(k, v) + } + } + // We do not know the content type and we do not want to inspect the payload, + // thus we set this generic one. + if err := event.SetData("application/octet-stream", msg.Data); err != nil { + return nil, err + } + return &event, nil +} diff --git a/pkg/pubsub/adapter/converters/pubsub_pull_test.go b/pkg/pubsub/adapter/converters/pubsub_pull_test.go new file mode 100644 index 0000000000..0ae23656f0 --- /dev/null +++ b/pkg/pubsub/adapter/converters/pubsub_pull_test.go @@ -0,0 +1,112 @@ +/* +Copyright 2019 Google LLC + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package converters + +import ( + "context" + "github.com/cloudevents/sdk-go" + "github.com/google/knative-gcp/pkg/apis/events/v1alpha1" + "testing" + + "cloud.google.com/go/pubsub" + cev2 "github.com/cloudevents/sdk-go/v2" + "github.com/google/go-cmp/cmp" + . "github.com/google/knative-gcp/pkg/pubsub/adapter/context" +) + +func TestConvertPubSubPull(t *testing.T) { + + tests := []struct { + name string + message *pubsub.Message + wantEventFn func() *cev2.Event + wantErr bool + }{{ + name: "valid attributes", + message: &pubsub.Message{ + ID: "id", + Data: []byte("test data"), + Attributes: map[string]string{ + "attribute1": "value1", + "attribute2": "value2", + }, + }, + wantEventFn: func() *cev2.Event { + return pubSubPull(map[string]string{ + "attribute1": "value1", + "attribute2": "value2", + }) + }, + }, { + name: "upper case attributes", + message: &pubsub.Message{ + ID: "id", + Data: []byte("test data"), + Attributes: map[string]string{ + "AttriBUte1": "value1", + "AttrIbuTe2": "value2", + }, + }, + wantEventFn: func() *cev2.Event { + return pubSubPull(map[string]string{ + "attribute1": "value1", + "attribute2": "value2", + }) + }, + }, { + name: "failing with invalid attributes", + message: &pubsub.Message{ + Data: []byte("test data"), + Attributes: map[string]string{ + "attribute1": "value1", + "Invalid-Attrib#$^": "value2", + }, + }, + wantErr: true, + }} + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + ctx := WithProjectKey(context.Background(), "testproject") + ctx = WithTopicKey(ctx, "testtopic") + ctx = WithSubscriptionKey(ctx, "testsubscription") + + gotEvent, err := NewPubSubConverter().Convert(ctx, test.message, PubSubPull) + if err != nil { + if !test.wantErr { + t.Errorf("converters.convertPubsubPull got error %v want error=%v", err, test.wantErr) + } + } else { + if diff := cmp.Diff(test.wantEventFn(), gotEvent); diff != "" { + t.Errorf("converters.convertPubsubPull got unexpeceted cloudevents.Event (-want +got) %s", diff) + } + } + }) + } +} + +func pubSubPull(extensions map[string]string) *cev2.Event { + e := cev2.NewEvent(cloudevents.VersionV1) + e.SetID("id") + e.SetSource(v1alpha1.CloudPubSubSourceEventSource("testproject", "testtopic")) + e.SetType(v1alpha1.CloudPubSubSourcePublish) + e.SetData("application/octet-stream", []byte("test data")) + for k, v := range extensions { + e.SetExtension(k, v) + } + return &e +} diff --git a/pkg/pubsub/adapter/converters/pubsub_test.go b/pkg/pubsub/adapter/converters/pubsub_test.go index d502019256..253dcb3558 100644 --- a/pkg/pubsub/adapter/converters/pubsub_test.go +++ b/pkg/pubsub/adapter/converters/pubsub_test.go @@ -23,126 +23,68 @@ import ( "testing" "cloud.google.com/go/pubsub" - cloudevents "github.com/cloudevents/sdk-go" - cepubsub "github.com/cloudevents/sdk-go/pkg/cloudevents/transport/pubsub" - pubsubcontext "github.com/cloudevents/sdk-go/pkg/cloudevents/transport/pubsub/context" + cev2 "github.com/cloudevents/sdk-go/v2" "github.com/google/go-cmp/cmp" - "github.com/google/knative-gcp/pkg/apis/events/v1alpha1" + "github.com/google/knative-gcp/pkg/apis/events/v1beta1" + . "github.com/google/knative-gcp/pkg/pubsub/adapter/context" ) func TestConvertCloudPubSub(t *testing.T) { tests := []struct { name string - message *cepubsub.Message - sendMode ModeType - wantEventFn func() *cloudevents.Event + message *pubsub.Message + wantEventFn func() *cev2.Event wantErr bool + wantInvalidContext bool }{{ - name: "valid attributes", - message: &cepubsub.Message{ - Data: []byte("test data"), - Attributes: map[string]string{ - "attribute1": "value1", - "attribute2": "value2", - }, - }, - sendMode: Binary, - wantEventFn: func() *cloudevents.Event { - return pubSubPullCloudEvent(map[string]string{ - "attribute1": "value1", - "attribute2": "value2", - }, "") - }, - }, { - name: "upper case attributes", - message: &cepubsub.Message{ - Data: []byte("test data"), - Attributes: map[string]string{ - "AttriBUte1": "value1", - "AttrIbuTe2": "value2", - }, - }, - sendMode: Binary, - wantEventFn: func() *cloudevents.Event { - return pubSubPullCloudEvent(map[string]string{ - "attribute1": "value1", - "attribute2": "value2", - }, "") - }, - }, { - name: "only setting valid alphanumeric attribute", - message: &cepubsub.Message{ - Data: []byte("test data"), - Attributes: map[string]string{ - "attribute1": "value1", - "Invalid-Attrib#$^": "value2", - }, - }, - sendMode: Binary, - wantEventFn: func() *cloudevents.Event { - return pubSubPullCloudEvent(map[string]string{ - "attribute1": "value1", - }, "") - }, - }, { - name: "schema as attribute", - message: &cepubsub.Message{ - Data: []byte("test data"), - Attributes: map[string]string{ - "attribute1": "value1", - "attribute2": "value2", - "schema": "schema_val", - }, - }, - sendMode: Binary, - wantEventFn: func() *cloudevents.Event { - return pubSubPullCloudEvent(map[string]string{ - "attribute1": "value1", - "attribute2": "value2", - }, "schema_val") - }, - }, { - name: "Push mode with non valid alphanumeric attribute", - message: &cepubsub.Message{ + name: "non alphanumeric attribute", + message: &pubsub.Message{ + ID: "id", Data: []byte("\"test data\""), // Data passed in quotes for it to be marshalled properly Attributes: map[string]string{ "attribute1": "value1", "Invalid-Attrib#$^": "value2", }, }, - sendMode: Push, - wantEventFn: func() *cloudevents.Event { - return pubSubPushCloudEvent(map[string]string{ + wantEventFn: func() *cev2.Event { + return pubSubCloudEvent(map[string]string{ "attribute1": "value1", "Invalid-Attrib#$^": "value2", }, "\"InRlc3QgZGF0YSI=\"") }, }, { - name: "Push mode with no attributes", - message: &cepubsub.Message{ + name: "no attributes", + message: &pubsub.Message{ + ID: "id", Data: []byte("\"test data\""), // Data passed in quotes for it to be marshalled properly Attributes: map[string]string{}, }, - sendMode: Push, - wantEventFn: func() *cloudevents.Event { - return pubSubPushCloudEvent(nil, "\"InRlc3QgZGF0YSI=\"") + wantEventFn: func() *cev2.Event { + return pubSubCloudEvent(nil, "\"InRlc3QgZGF0YSI=\"") + }, + }, { + name: "invalid context", + message: &pubsub.Message{ + ID: "id", + Data: []byte("\"test data\""), // Data passed in quotes for it to be marshalled properly + Attributes: map[string]string{}, }, + wantInvalidContext: true, + wantErr: true, }} for _, test := range tests { t.Run(test.name, func(t *testing.T) { - ctx := pubsubcontext.WithTransportContext(context.TODO(), pubsubcontext.NewTransportContext( - "testproject", - "testtopic", - "testsubscription", - "testmethod", - &pubsub.Message{ - ID: "id", - }, - )) + ctx := context.Background() + // TODO add flags to test each of the keys + if !test.wantInvalidContext { + ctx = WithProjectKey(context.Background(), "testproject") + ctx = WithTopicKey(ctx, "testtopic") + ctx = WithSubscriptionKey(ctx, "testsubscription") + } - gotEvent, err := Convert(ctx, test.message, test.sendMode, "") + gotEvent, err := NewPubSubConverter().Convert(ctx, test.message, CloudPubSub) if err != nil { if !test.wantErr { t.Errorf("converters.convertPubsub got error %v want error=%v", err, test.wantErr) @@ -156,38 +98,18 @@ func TestConvertCloudPubSub(t *testing.T) { } } -func pubSubPullCloudEvent(extensions map[string]string, schema string) *cloudevents.Event { - e := cloudevents.NewEvent(cloudevents.VersionV1) - e.SetID("id") - e.SetSource(v1alpha1.CloudPubSubSourceEventSource("testproject", "testtopic")) - e.SetDataContentType("application/octet-stream") - e.SetType(v1alpha1.CloudPubSubSourcePublish) - e.SetExtension("knativecemode", string(Binary)) - e.Data = []byte("test data") - e.DataEncoded = true - for k, v := range extensions { - e.SetExtension(k, v) - } - if schema != "" { - e.SetDataSchema(schema) - } - return &e -} - -func pubSubPushCloudEvent(attributes map[string]string, data string) *cloudevents.Event { - e := cloudevents.NewEvent(cloudevents.VersionV1) +func pubSubCloudEvent(attributes map[string]string, data string) *cev2.Event { + e := cev2.NewEvent(cev2.VersionV1) e.SetID("id") - e.SetSource(v1alpha1.CloudPubSubSourceEventSource("testproject", "testtopic")) - e.SetDataContentType(cloudevents.ApplicationJSON) - e.SetType(v1alpha1.CloudPubSubSourcePublish) - e.SetExtension("knativecemode", string(Push)) + e.SetSource(v1beta1.CloudPubSubSourceEventSource("testproject", "testtopic")) at := "" if attributes != nil { ex, _ := json.Marshal(attributes) at = fmt.Sprintf(`"attributes":%s,`, ex) } s := fmt.Sprintf(`{"subscription":"testsubscription","message":{"messageId":"id","data":%s,%s"publishTime":"0001-01-01T00:00:00Z"}}`, data, at) - e.Data = []byte(s) - e.DataEncoded = true + e.SetData(cev2.ApplicationJSON, []byte(s)) + e.SetType(v1beta1.CloudPubSubSourcePublish) + e.DataBase64 = false return &e } diff --git a/pkg/pubsub/adapter/converters/scheduler.go b/pkg/pubsub/adapter/converters/scheduler.go index 4c5093da3f..eb81c6c95f 100644 --- a/pkg/pubsub/adapter/converters/scheduler.go +++ b/pkg/pubsub/adapter/converters/scheduler.go @@ -20,65 +20,37 @@ import ( "context" "errors" - cloudevents "github.com/cloudevents/sdk-go" - . "github.com/cloudevents/sdk-go/pkg/cloudevents" - cepubsub "github.com/cloudevents/sdk-go/pkg/cloudevents/transport/pubsub" - pubsubcontext "github.com/cloudevents/sdk-go/pkg/cloudevents/transport/pubsub/context" - - "github.com/google/knative-gcp/pkg/apis/events/v1alpha1" + "github.com/google/knative-gcp/pkg/apis/events/v1beta1" "github.com/google/knative-gcp/pkg/reconciler/events/scheduler/resources" -) -const ( - CloudSchedulerConverter = "com.google.cloud.scheduler" + "cloud.google.com/go/pubsub" + cev2 "github.com/cloudevents/sdk-go/v2" ) -func convertCloudScheduler(ctx context.Context, msg *cepubsub.Message, sendMode ModeType) (*cloudevents.Event, error) { - tx := pubsubcontext.TransportContextFrom(ctx) - // Make a new event and convert the message payload. - event := cloudevents.NewEvent(cloudevents.VersionV1) - event.SetID(tx.ID) - event.SetTime(tx.PublishTime) - // We do not know the content type and we do not want to inspect the payload, - // thus we set this generic one. - event.SetDataContentType("application/octet-stream") - event.SetType(v1alpha1.CloudSchedulerSourceExecute) - // Set the schema if it comes as an attribute. - if val, ok := msg.Attributes["schema"]; ok { - delete(msg.Attributes, "schema") - event.SetDataSchema(val) - } +func convertCloudScheduler(ctx context.Context, msg *pubsub.Message) (*cev2.Event, error) { + event := cev2.NewEvent(cev2.VersionV1) + event.SetID(msg.ID) + event.SetTime(msg.PublishTime) + event.SetType(v1beta1.CloudSchedulerSourceExecute) + // Set the source and subject if it comes as an attribute. - jobName, ok := msg.Attributes[v1alpha1.CloudSchedulerSourceJobName] - if ok { - delete(msg.Attributes, v1alpha1.CloudSchedulerSourceJobName) - } else { + // We added this attributes so that we could identify the scheduler. + // We should remove them here. + jobName, ok := msg.Attributes[v1beta1.CloudSchedulerSourceJobName] + if !ok { return nil, errors.New("received event did not have jobName") } - schedulerName, ok := msg.Attributes[v1alpha1.CloudSchedulerSourceName] - if ok { - delete(msg.Attributes, v1alpha1.CloudSchedulerSourceName) - } else { + schedulerName, ok := msg.Attributes[v1beta1.CloudSchedulerSourceName] + if !ok { return nil, errors.New("received event did not have schedulerName") } + parentName := resources.ExtractParentName(jobName) - event.SetSource(v1alpha1.CloudSchedulerSourceEventSource(parentName, schedulerName)) + event.SetSource(v1beta1.CloudSchedulerSourceEventSource(parentName, schedulerName)) event.SetSubject(resources.ExtractJobID(jobName)) - // Set the mode to be an extension attribute. - event.SetExtension("knativecemode", string(sendMode)) - event.Data = msg.Data - event.DataEncoded = true - // Attributes are extensions. - if msg.Attributes != nil && len(msg.Attributes) > 0 { - for k, v := range msg.Attributes { - // CloudEvents v1.0 attributes MUST consist of lower-case letters ('a' to 'z') or digits ('0' to '9') as per - // the spec. It's not even possible for a conformant transport to allow non-base36 characters. - // Note `SetExtension` will make it lowercase so only `IsAlphaNumeric` needs to be checked here. - if IsAlphaNumeric(k) { - event.SetExtension(k, v) - } - } + if err := event.SetData(cev2.ApplicationJSON, msg.Data); err != nil { + return nil, err } return &event, nil } diff --git a/pkg/pubsub/adapter/converters/scheduler_test.go b/pkg/pubsub/adapter/converters/scheduler_test.go index 6d068578db..7ec5a4fa90 100644 --- a/pkg/pubsub/adapter/converters/scheduler_test.go +++ b/pkg/pubsub/adapter/converters/scheduler_test.go @@ -22,26 +22,24 @@ import ( "testing" "cloud.google.com/go/pubsub" - cloudevents "github.com/cloudevents/sdk-go" - cepubsub "github.com/cloudevents/sdk-go/pkg/cloudevents/transport/pubsub" - pubsubcontext "github.com/cloudevents/sdk-go/pkg/cloudevents/transport/pubsub/context" "github.com/google/go-cmp/cmp" + "github.com/google/knative-gcp/pkg/apis/events/v1beta1" - "github.com/google/knative-gcp/pkg/apis/events/v1alpha1" + cev2 "github.com/cloudevents/sdk-go/v2" ) func TestConvertCloudSchedulerSource(t *testing.T) { tests := []struct { name string - message *cepubsub.Message + message *pubsub.Message source string - sendMode ModeType - wantEventFn func() *cloudevents.Event + wantEventFn func() *cev2.Event wantErr string }{{ name: "valid attributes", - message: &cepubsub.Message{ + message: &pubsub.Message{ + ID: "id", Data: []byte("test data"), Attributes: map[string]string{ "knative-gcp": "com.google.cloud.scheduler", @@ -51,57 +49,14 @@ func TestConvertCloudSchedulerSource(t *testing.T) { "attribute2": "value2", }, }, - sendMode: Binary, - wantEventFn: func() *cloudevents.Event { - return schedulerCloudEvent(map[string]string{ - "attribute1": "value1", - "attribute2": "value2"}, - "//cloudscheduler.googleapis.com/projects/knative-gcp-test/locations/us-east4/schedulers/scheduler-test", - "jobs/cre-scheduler-test") - }, - }, { - name: "upper case attributes", - message: &cepubsub.Message{ - Data: []byte("test data"), - Attributes: map[string]string{ - "knative-gcp": "com.google.cloud.scheduler", - "jobName": "projects/knative-gcp-test/locations/us-east4/jobs/cre-scheduler-test", - "schedulerName": "scheduler-test", - "AttriBUte1": "value1", - "AttrIbuTe2": "value2", - }, - }, - sendMode: Binary, - wantEventFn: func() *cloudevents.Event { - return schedulerCloudEvent(map[string]string{ - "attribute1": "value1", - "attribute2": "value2", - }, - "//cloudscheduler.googleapis.com/projects/knative-gcp-test/locations/us-east4/schedulers/scheduler-test", - "jobs/cre-scheduler-test") - }, - }, { - name: "only setting valid alphanumeric attribute", - message: &cepubsub.Message{ - Data: []byte("test data"), - Attributes: map[string]string{ - "knative-gcp": "com.google.cloud.scheduler", - "jobName": "projects/knative-gcp-test/locations/us-east4/jobs/cre-scheduler-test", - "schedulerName": "scheduler-test", - "attribute1": "value1", - "Invalid-Attrib#$^": "value2", - }, - }, - sendMode: Binary, - wantEventFn: func() *cloudevents.Event { - return schedulerCloudEvent(map[string]string{ - "attribute1": "value1"}, + wantEventFn: func() *cev2.Event { + return schedulerCloudEvent( "//cloudscheduler.googleapis.com/projects/knative-gcp-test/locations/us-east4/schedulers/scheduler-test", "jobs/cre-scheduler-test") }, }, { name: "missing jobName attribute", - message: &cepubsub.Message{ + message: &pubsub.Message{ Data: []byte("test data"), Attributes: map[string]string{ "knative-gcp": "com.google.cloud.scheduler", @@ -110,11 +65,10 @@ func TestConvertCloudSchedulerSource(t *testing.T) { "attribute2": "value2", }, }, - sendMode: Binary, - wantErr: "received event did not have jobName", + wantErr: "received event did not have jobName", }, { name: "missing schedulerName attribute", - message: &cepubsub.Message{ + message: &pubsub.Message{ Data: []byte("test data"), Attributes: map[string]string{ "knative-gcp": "com.google.cloud.scheduler", @@ -123,23 +77,13 @@ func TestConvertCloudSchedulerSource(t *testing.T) { "attribute2": "value2", }, }, - sendMode: Binary, - wantErr: "received event did not have schedulerName", + wantErr: "received event did not have schedulerName", }} for _, test := range tests { t.Run(test.name, func(t *testing.T) { - ctx := pubsubcontext.WithTransportContext(context.Background(), pubsubcontext.NewTransportContext( - "testproject", - "testtopic", - "testsubscription", - "testmethod", - &pubsub.Message{ - ID: "id", - }, - )) - gotEvent, err := Convert(ctx, test.message, test.sendMode, "") + gotEvent, err := NewPubSubConverter().Convert(context.Background(), test.message, CloudScheduler) if test.wantErr != "" || err != nil { var gotErr string @@ -154,26 +98,18 @@ func TestConvertCloudSchedulerSource(t *testing.T) { } if diff := cmp.Diff(test.wantEventFn(), gotEvent); diff != "" { - t.Errorf("converters.convertCloudScheduler got unexpeceted cloudevents.Event (-want +got) %s", diff) + t.Errorf("converters.convertCloudScheduler got unexpected cev2.Event (-want +got) %s", diff) } }) } } -func schedulerCloudEvent(extensions map[string]string, source, subject string) *cloudevents.Event { - e := cloudevents.NewEvent(cloudevents.VersionV1) +func schedulerCloudEvent(source, subject string) *cev2.Event { + e := cev2.NewEvent(cev2.VersionV1) e.SetID("id") - e.SetDataContentType("application/octet-stream") - e.SetType(v1alpha1.CloudSchedulerSourceExecute) - e.SetExtension("knativecemode", string(Binary)) + e.SetData(cev2.ApplicationJSON, []byte("test data")) + e.SetType(v1beta1.CloudSchedulerSourceExecute) e.SetSource(source) e.SetSubject(subject) - e.Data = []byte("test data") - e.DataEncoded = true - for k, v := range extensions { - if k != v1alpha1.CloudSchedulerSourceJobName { - e.SetExtension(k, v) - } - } return &e } diff --git a/pkg/pubsub/adapter/converters/storage.go b/pkg/pubsub/adapter/converters/storage.go index 6c957ff024..a8ea5c8a26 100644 --- a/pkg/pubsub/adapter/converters/storage.go +++ b/pkg/pubsub/adapter/converters/storage.go @@ -17,91 +17,59 @@ limitations under the License. package converters import ( + "cloud.google.com/go/pubsub" "context" "errors" - - "go.uber.org/zap" - "knative.dev/pkg/logging" - - cloudevents "github.com/cloudevents/sdk-go" - . "github.com/cloudevents/sdk-go/pkg/cloudevents" - cepubsub "github.com/cloudevents/sdk-go/pkg/cloudevents/transport/pubsub" - pubsubcontext "github.com/cloudevents/sdk-go/pkg/cloudevents/transport/pubsub/context" - "github.com/google/knative-gcp/pkg/apis/events/v1alpha1" + "fmt" + cev2 "github.com/cloudevents/sdk-go/v2" + "github.com/google/knative-gcp/pkg/apis/events/v1beta1" ) var ( // Mapping of GCS eventTypes to CloudEvent types. storageEventTypes = map[string]string{ - "OBJECT_FINALIZE": v1alpha1.CloudStorageSourceFinalize, - "OBJECT_ARCHIVE": v1alpha1.CloudStorageSourceArchive, - "OBJECT_DELETE": v1alpha1.CloudStorageSourceDelete, - "OBJECT_METADATA_UPDATE": v1alpha1.CloudStorageSourceMetadataUpdate, + "OBJECT_FINALIZE": v1beta1.CloudStorageSourceFinalize, + "OBJECT_ARCHIVE": v1beta1.CloudStorageSourceArchive, + "OBJECT_DELETE": v1beta1.CloudStorageSourceDelete, + "OBJECT_METADATA_UPDATE": v1beta1.CloudStorageSourceMetadataUpdate, } ) const ( - storageDefaultEventType = "com.google.cloud.storage" // Schema extracted from https://raw.githubusercontent.com/googleapis/google-api-go-client/master/storage/v1/storage-api.json. // TODO find the public google endpoint we should use to point to the schema and avoid hosting it ourselves. // The link above is tied to the go-client, and it seems not to be a valid json schema. storageSchemaUrl = "https://raw.githubusercontent.com/google/knative-gcp/master/schemas/storage/schema.json" - CloudStorageConverter = "com.google.cloud.storage" ) -func convertCloudStorage(ctx context.Context, msg *cepubsub.Message, sendMode ModeType) (*cloudevents.Event, error) { - if msg == nil { - return nil, errors.New("nil pubsub message") - } - - tx := pubsubcontext.TransportContextFrom(ctx) - // Make a new event and convert the message payload. - event := cloudevents.NewEvent(cloudevents.VersionV1) - event.SetID(tx.ID) - event.SetTime(tx.PublishTime) +func convertCloudStorage(ctx context.Context, msg *pubsub.Message) (*cev2.Event, error) { + event := cev2.NewEvent(cev2.VersionV1) + event.SetID(msg.ID) + event.SetTime(msg.PublishTime) event.SetDataSchema(storageSchemaUrl) if val, ok := msg.Attributes["bucketId"]; ok { - delete(msg.Attributes, "bucketId") - event.SetSource(v1alpha1.CloudStorageSourceEventSource(val)) + event.SetSource(v1beta1.CloudStorageSourceEventSource(val)) } else { return nil, errors.New("received event did not have bucketId") } if val, ok := msg.Attributes["objectId"]; ok { - delete(msg.Attributes, "objectId") event.SetSubject(val) } else { - // Not setting subject, as it's optional - logging.FromContext(ctx).Desugar().Debug("received event did not have objectId") + return nil, errors.New("received event did not have objectId") } if val, ok := msg.Attributes["eventType"]; ok { - delete(msg.Attributes, "eventType") if eventType, ok := storageEventTypes[val]; ok { event.SetType(eventType) } else { - logging.FromContext(ctx).Desugar().Debug("Unknown eventType, using default", zap.String("eventType", eventType), zap.String("default", storageDefaultEventType)) - event.SetType(storageDefaultEventType) + return nil, fmt.Errorf("unknown event type %s", val) } } else { return nil, errors.New("received event did not have eventType") } - if _, ok := msg.Attributes["eventTime"]; ok { - delete(msg.Attributes, "eventTime") - } - event.SetDataContentType(*cloudevents.StringOfApplicationJSON()) - event.Data = msg.Data - event.DataEncoded = true - // Attributes are extensions. - if msg.Attributes != nil && len(msg.Attributes) > 0 { - for k, v := range msg.Attributes { - // CloudEvents v1.0 attributes MUST consist of lower-case letters ('a' to 'z') or digits ('0' to '9') as per - // the spec. It's not even possible for a conformant transport to allow non-base36 characters. - // Note `SetExtension` will make it lowercase so only `IsAlphaNumeric` needs to be checked here. - if IsAlphaNumeric(k) { - event.SetExtension(k, v) - } - } + if err := event.SetData(cev2.ApplicationJSON, msg.Data); err != nil { + return nil, err } return &event, nil } diff --git a/pkg/pubsub/adapter/converters/storage_test.go b/pkg/pubsub/adapter/converters/storage_test.go index 7e2f5bb076..5ead70ac0e 100644 --- a/pkg/pubsub/adapter/converters/storage_test.go +++ b/pkg/pubsub/adapter/converters/storage_test.go @@ -19,171 +19,118 @@ package converters import ( "context" "testing" + "time" "cloud.google.com/go/pubsub" - "github.com/google/go-cmp/cmp" + "github.com/google/knative-gcp/pkg/apis/events/v1beta1" +) + +const ( + bucket = "my-bucket" + objectId = "myfile.jpg" + eventType = "OBJECT_FINALIZE" +) - cloudevents "github.com/cloudevents/sdk-go" - cepubsub "github.com/cloudevents/sdk-go/pkg/cloudevents/transport/pubsub" - pubsubcontext "github.com/cloudevents/sdk-go/pkg/cloudevents/transport/pubsub/context" - "github.com/google/knative-gcp/pkg/apis/events/v1alpha1" +var ( + storagePublishTime = time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC) ) func TestConvertCloudStorageSource(t *testing.T) { tests := []struct { - name string - message *cepubsub.Message - sendMode ModeType - wantEventFn func() *cloudevents.Event - wantErr bool + name string + message *pubsub.Message + wantErr bool }{{ name: "no attributes", - message: &cepubsub.Message{ + message: &pubsub.Message{ Data: []byte("test data"), - Attributes: map[string]string{ - "knative-gcp": "com.google.cloud.storage", - }, - }, - sendMode: Binary, - wantEventFn: func() *cloudevents.Event { - return storageCloudEvent(map[string]string{}) }, wantErr: true, }, { name: "no bucketId attribute", - message: &cepubsub.Message{ + message: &pubsub.Message{ Data: []byte("test data"), Attributes: map[string]string{ - "knative-gcp": "com.google.cloud.storage", - "eventType": "OBJECT_FINALIZE", - "attribute1": "value1", - "attribute2": "value2", - }, - }, - sendMode: Binary, - wantEventFn: func() *cloudevents.Event { - return storageCloudEvent(map[string]string{ + "eventType": eventType, "attribute1": "value1", "attribute2": "value2", - }) + }, }, wantErr: true, }, { name: "no eventType attribute", - message: &cepubsub.Message{ + message: &pubsub.Message{ Data: []byte("test data"), Attributes: map[string]string{ - "knative-gcp": "com.google.cloud.storage", - "bucketId": "my-bucket", + "bucketId": bucket, + "objectId": objectId, }, }, - sendMode: Binary, - wantEventFn: func() *cloudevents.Event { - return storageCloudEvent(map[string]string{}) - }, wantErr: true, }, { - name: "set subject", - message: &cepubsub.Message{ + name: "unkown eventType attribute", + message: &pubsub.Message{ Data: []byte("test data"), Attributes: map[string]string{ - "knative-gcp": "com.google.cloud.storage", - "bucketId": "my-bucket", - "eventType": "OBJECT_FINALIZE", - "objectId": "myfile.jpg", - "AttriBUte1": "value1", - "AttrIbuTe2": "value2", - }, - }, - sendMode: Binary, - wantEventFn: func() *cloudevents.Event { - return storageCloudEvent(map[string]string{ - "attribute1": "value1", - "attribute2": "value2", + "eventType": "RANDOM_EVENT", + "bucketId": bucket, + "objectId": objectId, }, - "myfile.jpg") }, + wantErr: true, }, { - name: "not setting invalid upper case attributes", - message: &cepubsub.Message{ + name: "no objectId attribute", + message: &pubsub.Message{ Data: []byte("test data"), Attributes: map[string]string{ - "knative-gcp": "com.google.cloud.storage", - "bucketId": "my-bucket", - "eventType": "OBJECT_FINALIZE", - "AttriBUte1": "value1", - "AttrIbuTe2": "value2", + "bucketId": bucket, + "eventType": eventType, }, }, - sendMode: Binary, - wantEventFn: func() *cloudevents.Event { - return storageCloudEvent(map[string]string{ - "attribute1": "value1", - "attribute2": "value2", - }) - }, + wantErr: true, }, { - name: "only setting valid alphanumeric attribute", - message: &cepubsub.Message{ - Data: []byte("test data"), + name: "valid message", + message: &pubsub.Message{ + ID: "id", + PublishTime: storagePublishTime, + Data: []byte("test data"), Attributes: map[string]string{ - "knative-gcp": "com.google.cloud.storage", - "bucketId": "my-bucket", - "eventType": "OBJECT_FINALIZE", - "attribute1": "value1", - "Invalid-Attrib#$^": "value2", + "bucketId": bucket, + "eventType": eventType, + "objectId": objectId, }, }, - sendMode: Binary, - wantEventFn: func() *cloudevents.Event { - return storageCloudEvent(map[string]string{ - "attribute1": "value1", - }) - }, }} for _, test := range tests { t.Run(test.name, func(t *testing.T) { - ctx := pubsubcontext.WithTransportContext(context.TODO(), pubsubcontext.NewTransportContext( - "testproject", - "testtopic", - "testsubscription", - "testmethod", - &pubsub.Message{ - ID: "id", - }, - )) - - gotEvent, err := Convert(ctx, test.message, test.sendMode, "") + gotEvent, err := NewPubSubConverter().Convert(context.Background(), test.message, CloudStorage) if err != nil { if !test.wantErr { t.Fatalf("converters.convertCloudStorage got error %v want error=%v", err, test.wantErr) } } else { - if diff := cmp.Diff(test.wantEventFn(), gotEvent); diff != "" { - t.Fatalf("converters.convertCloudStorage got unexpeceted cloudevents.Event (-want +got) %s", diff) + if gotEvent.ID() != "id" { + t.Errorf("ID '%s' != '%s'", gotEvent.ID(), "id") + } + if !gotEvent.Time().Equal(storagePublishTime) { + t.Errorf("Time '%v' != '%v'", gotEvent.Time(), storagePublishTime) + } + if want := v1beta1.CloudStorageSourceEventSource("my-bucket"); gotEvent.Source() != want { + t.Errorf("Source %q != %q", gotEvent.Source(), want) + } + if gotEvent.Type() != v1beta1.CloudStorageSourceFinalize { + t.Errorf(`Type %q != %q`, gotEvent.Type(), v1beta1.CloudStorageSourceFinalize) + } + if gotEvent.Subject() != objectId { + t.Errorf("Subject %q != %q", gotEvent.Subject(), objectId) + } + if gotEvent.DataSchema() != storageSchemaUrl { + t.Errorf("DataSchema %q != %q", gotEvent.DataSchema(), storageSchemaUrl) } } }) } } - -func storageCloudEvent(extensions map[string]string, subject ...string) *cloudevents.Event { - e := cloudevents.NewEvent(cloudevents.VersionV1) - e.SetID("id") - e.SetDataContentType(*cloudevents.StringOfApplicationJSON()) - e.SetDataSchema(storageSchemaUrl) - e.SetSource(v1alpha1.CloudStorageSourceEventSource("my-bucket")) - e.SetType(v1alpha1.CloudStorageSourceFinalize) - if len(subject) > 0 { - e.SetSubject(subject[0]) - } - e.Data = []byte("test data") - e.DataEncoded = true - for k, v := range extensions { - e.SetExtension(k, v) - } - return &e -} diff --git a/pkg/pubsub/adapter/providers.go b/pkg/pubsub/adapter/providers.go new file mode 100644 index 0000000000..2056b388e6 --- /dev/null +++ b/pkg/pubsub/adapter/providers.go @@ -0,0 +1,34 @@ +package adapter + +import ( + "context" + + "cloud.google.com/go/pubsub" + "github.com/google/knative-gcp/pkg/pubsub/adapter/converters" + "github.com/google/knative-gcp/pkg/utils/clients" + "github.com/google/wire" +) + +// TODO Name and ResourceGroup might cause problems in the near future, as we might use a single receive-adapter +// for multiple source objects. Same with Namespace, when doing multi-tenancy. +type Name string +type Namespace string +type ResourceGroup string + +type SinkURI string +type TransformerURI string +type SubscriptionID string + +// AdapterSet provides an adapter with a PubSub client and HTTP client. +var AdapterSet wire.ProviderSet = wire.NewSet( + NewAdapter, + clients.NewPubsubClient, + NewPubSubSubscription, + converters.NewPubSubConverter, + NewStatsReporter, + clients.NewHTTPClient, +) + +func NewPubSubSubscription(ctx context.Context, client *pubsub.Client, subscriptionID SubscriptionID) *pubsub.Subscription { + return client.Subscription(string(subscriptionID)) +} diff --git a/pkg/pubsub/adapter/stats_reporter.go b/pkg/pubsub/adapter/stats_reporter.go index 1cbf5d0f4d..9421a71c60 100644 --- a/pkg/pubsub/adapter/stats_reporter.go +++ b/pkg/pubsub/adapter/stats_reporter.go @@ -18,6 +18,7 @@ package adapter import ( "context" + "fmt" "strconv" "go.opencensus.io/stats/view" @@ -51,15 +52,8 @@ var ( ) type ReportArgs struct { - Namespace string - EventType string - EventSource string - Name string - ResourceGroup string -} - -func init() { - register() + EventType string + EventSource string } // StatsReporter defines the interface for sending metrics. @@ -72,11 +66,23 @@ var _ StatsReporter = (*reporter)(nil) var emptyContext = context.Background() // reporter holds cached metric objects to report metrics. -type reporter struct{} +type reporter struct { + name string + namespace string + resourceGroup string +} // NewStatsReporter creates a reporter that collects and reports metrics. -func NewStatsReporter() StatsReporter { - return &reporter{} +func NewStatsReporter(name Name, namespace Namespace, resourceGroup ResourceGroup) (StatsReporter, error) { + r := &reporter{ + name: string(name), + namespace: string(namespace), + resourceGroup: string(resourceGroup), + } + if err := r.register(); err != nil { + return nil, fmt.Errorf("failed to register stats: %w", err) + } + return r, nil } func (r *reporter) ReportEventCount(args *ReportArgs, responseCode int) error { @@ -91,16 +97,16 @@ func (r *reporter) ReportEventCount(args *ReportArgs, responseCode int) error { func (r *reporter) generateTag(args *ReportArgs, responseCode int) (context.Context, error) { return tag.New( emptyContext, - tag.Insert(namespaceKey, args.Namespace), + tag.Insert(namespaceKey, r.namespace), tag.Insert(eventSourceKey, args.EventSource), tag.Insert(eventTypeKey, args.EventType), - tag.Insert(nameKey, args.Name), - tag.Insert(resourceGroupKey, args.ResourceGroup), + tag.Insert(nameKey, r.name), + tag.Insert(resourceGroupKey, r.resourceGroup), tag.Insert(responseCodeKey, strconv.Itoa(responseCode)), tag.Insert(responseCodeClassKey, metrics.ResponseCodeClass(responseCode))) } -func register() { +func (r *reporter) register() error { tagKeys := []tag.Key{ namespaceKey, eventSourceKey, @@ -111,14 +117,12 @@ func register() { responseCodeClassKey} // Create view to see our measurements. - if err := metrics.RegisterResourceView( + return metrics.RegisterResourceView( &view.View{ Description: eventCountM.Description(), Measure: eventCountM, Aggregation: view.Count(), TagKeys: tagKeys, }, - ); err != nil { - panic(err) - } + ) } diff --git a/pkg/pubsub/adapter/stats_reporter_test.go b/pkg/pubsub/adapter/stats_reporter_test.go index 502b0ce3c1..f2773f3842 100644 --- a/pkg/pubsub/adapter/stats_reporter_test.go +++ b/pkg/pubsub/adapter/stats_reporter_test.go @@ -27,17 +27,15 @@ import ( ) func TestStatsReporter(t *testing.T) { - setup() - args := &ReportArgs{ - Namespace: "testns", - EventType: "dev.knative.event", - EventSource: "unit-test", - Name: "testobject", - ResourceGroup: "testresourcegroup", + EventType: "dev.knative.event", + EventSource: "unit-test", } - r := NewStatsReporter() + r, err := NewStatsReporter("testobject", "testns", "testresourcegroup") + if err != nil { + t.Fatalf("Error creating reporter: %v", err) + } wantTags := map[string]string{ metricskey.LabelNamespaceName: "testns", @@ -65,13 +63,3 @@ func expectSuccess(t *testing.T, f func() error) { t.Errorf("Reporter expected success but got error: %v", err) } } - -func setup() { - resetMetrics() -} - -func resetMetrics() { - // OpenCensus metrics carry global state that need to be reset between unit tests. - metricstest.Unregister("event_count") - register() -} diff --git a/pkg/pubsub/publisher/providers.go b/pkg/pubsub/publisher/providers.go new file mode 100644 index 0000000000..ff65dd06a8 --- /dev/null +++ b/pkg/pubsub/publisher/providers.go @@ -0,0 +1,26 @@ +package publisher + +import ( + "context" + + "cloud.google.com/go/pubsub" + "github.com/google/knative-gcp/pkg/utils/clients" + "github.com/google/wire" + "knative.dev/eventing/pkg/kncloudevents" +) + +type TopicID string + +// PublisherSet provides a handler with a real HTTPMessageReceiver and a PubSub client. +var PublisherSet wire.ProviderSet = wire.NewSet( + NewPublisher, + clients.NewHTTPMessageReceiver, + clients.NewPubsubClient, + NewPubSubTopic, + wire.Bind(new(HttpMessageReceiver), new(*kncloudevents.HttpMessageReceiver)), +) + +// NewPubSubTopic provides a pubsub topic from a PubSub client. +func NewPubSubTopic(ctx context.Context, client *pubsub.Client, topicID TopicID) *pubsub.Topic { + return client.Topic(string(topicID)) +} diff --git a/pkg/pubsub/publisher/publisher.go b/pkg/pubsub/publisher/publisher.go index 47f84b6d42..aa4a634752 100644 --- a/pkg/pubsub/publisher/publisher.go +++ b/pkg/pubsub/publisher/publisher.go @@ -17,79 +17,129 @@ limitations under the License. package publisher import ( + "context" + "errors" "fmt" + nethttp "net/http" + "time" + "cloud.google.com/go/pubsub" + "github.com/cloudevents/sdk-go/v2/binding" + "github.com/cloudevents/sdk-go/v2/binding/transformer" + "github.com/cloudevents/sdk-go/v2/protocol/http" "go.uber.org/zap" - "knative.dev/pkg/logging" + "knative.dev/eventing/pkg/logging" - "context" + cev2 "github.com/cloudevents/sdk-go/v2" + "github.com/cloudevents/sdk-go/v2/protocol" + + cepubsub "github.com/cloudevents/sdk-go/protocol/pubsub/v2" + "github.com/cloudevents/sdk-go/v2/extensions" + "go.opencensus.io/trace" +) - cloudevents "github.com/cloudevents/sdk-go" - cepubsub "github.com/cloudevents/sdk-go/pkg/cloudevents/transport/pubsub" - "github.com/google/knative-gcp/pkg/kncloudevents" +const ( + sinkTimeout = 30 * time.Second ) -// Publisher implements the Pub/Sub adapter to deliver Pub/Sub messages from a -// pre-existing topic/subscription to a Sink. +// PubSubPublisher is an interface to publish events to a pubsub topic. +type PubSubPublisher interface { + Publish(ctx context.Context, event cev2.Event) protocol.Result +} + +// HttpMessageReceiver is an interface to listen on http requests. +type HttpMessageReceiver interface { + StartListen(ctx context.Context, handler nethttp.Handler) error +} + +// Publisher receives HTTP events and sends them to Pubsub. type Publisher struct { - // ProjectID is the pre-existing eventing project id to use. - ProjectID string - // TopicID is the pre-existing eventing pub/sub topic id to use. - TopicID string - - // inbound is the cloudevents client to use to receive events. - inbound cloudevents.Client - // outbound is the cloudevents client to use to send events. - outbound cloudevents.Client + // inbound is an HTTP server to receive events. + inbound HttpMessageReceiver + // topic is the topic to publish events to. + topic *pubsub.Topic + + logger *zap.Logger } -func (a *Publisher) Start(ctx context.Context) error { - var err error +// NewPublisher creates a new publisher. +func NewPublisher(ctx context.Context, inbound HttpMessageReceiver, topic *pubsub.Topic) *Publisher { + return &Publisher{ + inbound: inbound, + topic: topic, + logger: logging.FromContext(ctx), + } +} - // Receive events on HTTP. - if a.inbound == nil { - if a.inbound, err = kncloudevents.NewDefaultClient(); err != nil { - return fmt.Errorf("failed to create inbound cloudevent client: %w", err) - } +// Start blocks to receive events over HTTP. +func (p *Publisher) Start(ctx context.Context) error { + return p.inbound.StartListen(ctx, p) +} + +// ServeHTTP implements net/http Publisher interface method. +// 1. Performs basic validation of the request. +// 2. Converts the request to an event. +// 3. Sends the event to pubsub. +func (p *Publisher) ServeHTTP(response nethttp.ResponseWriter, request *nethttp.Request) { + ctx := request.Context() + p.logger.Debug("Serving http", zap.Any("headers", request.Header)) + if request.Method != nethttp.MethodPost { + response.WriteHeader(nethttp.StatusMethodNotAllowed) + return } - // Send Events on Pub/Sub. - if a.outbound == nil { - if a.outbound, err = a.newPubSubClient(ctx); err != nil { - return fmt.Errorf("failed to create outbound cloudevent client: %w", err) - } + event, err := p.toEvent(request) + if err != nil { + nethttp.Error(response, err.Error(), nethttp.StatusBadRequest) + return } - return a.inbound.StartReceiver(ctx, a.receive) + // Optimistically set status code to StatusAccepted. It will be updated if there is an error. + // According to the data plane spec (https://github.com/knative/eventing/blob/master/docs/spec/data-plane.md), a + // non-callable Sink (which Publisher is) MUST respond with 202 Accepted if the request is accepted. + statusCode := nethttp.StatusAccepted + ctx, cancel := context.WithTimeout(ctx, sinkTimeout) + defer cancel() + if res := p.Publish(ctx, event); !cev2.IsACK(res) { + msg := fmt.Sprintf("Error publishing to PubSub. event: %+v, err: %v.", event, res) + p.logger.Error(msg) + statusCode = nethttp.StatusInternalServerError + nethttp.Error(response, msg, statusCode) + return + } + response.WriteHeader(statusCode) } -func (a *Publisher) receive(ctx context.Context, event cloudevents.Event, resp *cloudevents.EventResponse) error { - if _, r, err := a.outbound.Send(ctx, event); err != nil { - logging.FromContext(ctx).Desugar().Error("Error publishing to PubSub", zap.String("event", event.String()), zap.Error(err)) +// Publish publishes an incoming event to a pubsub topic. +func (p *Publisher) Publish(ctx context.Context, event *cev2.Event) protocol.Result { + dt := extensions.FromSpanContext(trace.FromContext(ctx).SpanContext()) + msg := new(pubsub.Message) + if err := cepubsub.WritePubSubMessage(ctx, binding.ToMessage(event), msg, dt.WriteTransformer()); err != nil { return err - } else if r != nil { - resp.RespondWith(200, r) } - - return nil + _, err := p.topic.Publish(ctx, msg).Get(ctx) + return err } -func (a *Publisher) newPubSubClient(ctx context.Context) (cloudevents.Client, error) { - tOpts := []cepubsub.Option{ - cepubsub.WithBinaryEncoding(), - cepubsub.WithProjectID(a.ProjectID), - cepubsub.WithTopicID(a.TopicID), +// toEvent converts an http request to an event. +func (p *Publisher) toEvent(request *nethttp.Request) (*cev2.Event, error) { + message := http.NewMessageFromHttpRequest(request) + defer func() { + if err := message.Finish(nil); err != nil { + p.logger.Error("Failed to close message", zap.Any("message", message), zap.Error(err)) + } + }() + // If encoding is unknown, the message is not an event. + if message.ReadEncoding() == binding.EncodingUnknown { + msg := fmt.Sprintf("Encoding is unknown. Not a cloud event? request: %+v", request) + p.logger.Debug(msg) + return nil, errors.New(msg) } - - // Make a pubsub transport for the CloudEvents client. - t, err := cepubsub.New(ctx, tOpts...) + event, err := binding.ToEvent(request.Context(), message, transformer.AddTimeNow) if err != nil { - return nil, err + msg := fmt.Sprintf("Failed to convert request to event: %v", err) + p.logger.Error(msg) + return nil, errors.New(msg) } - - // Use the transport to make a new CloudEvents client. - return cloudevents.NewClient(t, - cloudevents.WithUUIDs(), - cloudevents.WithTimeNow(), - ) + return event, nil } diff --git a/pkg/reconciler/brokercell/brokercell_test.go b/pkg/reconciler/brokercell/brokercell_test.go index 23e873daf6..d166a1cbab 100644 --- a/pkg/reconciler/brokercell/brokercell_test.go +++ b/pkg/reconciler/brokercell/brokercell_test.go @@ -870,6 +870,7 @@ func TestAllCases(t *testing.T) { Objects: []runtime.Object{NewBrokerCell(brokerCellName, testNS, WithBrokerCellAnnotations(creatorAnnotation), WithBrokerCellSetDefaults, + WithInitBrokerCellConditions, )}, WithReactors: []clientgotesting.ReactionFunc{InduceFailure("delete", "brokercells")}, WantDeletes: []clientgotesting.DeleteActionImpl{ @@ -891,6 +892,7 @@ func TestAllCases(t *testing.T) { Objects: []runtime.Object{NewBrokerCell(brokerCellName, testNS, WithBrokerCellAnnotations(creatorAnnotation), WithBrokerCellSetDefaults, + WithInitBrokerCellConditions, )}, WantDeletes: []clientgotesting.DeleteActionImpl{ { diff --git a/pkg/reconciler/events/auditlogs/auditlogs_test.go b/pkg/reconciler/events/auditlogs/auditlogs_test.go index a968ed2378..8bbb6c6b0c 100644 --- a/pkg/reconciler/events/auditlogs/auditlogs_test.go +++ b/pkg/reconciler/events/auditlogs/auditlogs_test.go @@ -497,7 +497,7 @@ func TestAllCases(t *testing.T) { PubSubSpec: duckv1beta1.PubSubSpec{ Secret: &secret, }, - AdapterType: converters.CloudAuditLogsConverter, + AdapterType: string(converters.CloudAuditLogs), }), WithPullSubscriptionSink(sinkGVK, sinkName), WithPullSubscriptionLabels(map[string]string{ @@ -549,7 +549,7 @@ func TestAllCases(t *testing.T) { Sink: newSinkDestination(), }, }, - AdapterType: converters.CloudAuditLogsConverter, + AdapterType: string(converters.CloudAuditLogs), })), }, Key: testNS + "/" + sourceName, @@ -603,7 +603,7 @@ func TestAllCases(t *testing.T) { Sink: newSinkDestination(), }, }, - AdapterType: converters.CloudAuditLogsConverter, + AdapterType: string(converters.CloudAuditLogs), })), }, Key: testNS + "/" + sourceName, @@ -657,7 +657,7 @@ func TestAllCases(t *testing.T) { Sink: newSinkDestination(), }, }, - AdapterType: converters.CloudAuditLogsConverter, + AdapterType: string(converters.CloudAuditLogs), })), }, Key: testNS + "/" + sourceName, @@ -712,7 +712,7 @@ func TestAllCases(t *testing.T) { Sink: newSinkDestination(), }, }, - AdapterType: converters.CloudAuditLogsConverter, + AdapterType: string(converters.CloudAuditLogs), })), }, Key: testNS + "/" + sourceName, @@ -775,7 +775,7 @@ func TestAllCases(t *testing.T) { Sink: newSinkDestination(), }, }, - AdapterType: converters.CloudAuditLogsConverter, + AdapterType: string(converters.CloudAuditLogs), })), }, Key: testNS + "/" + sourceName, @@ -838,7 +838,7 @@ func TestAllCases(t *testing.T) { Sink: newSinkDestination(), }, }, - AdapterType: converters.CloudAuditLogsConverter, + AdapterType: string(converters.CloudAuditLogs), })), }, Key: testNS + "/" + sourceName, @@ -901,7 +901,7 @@ func TestAllCases(t *testing.T) { Sink: newSinkDestination(), }, }, - AdapterType: converters.CloudAuditLogsConverter, + AdapterType: string(converters.CloudAuditLogs), })), }, Key: testNS + "/" + sourceName, @@ -966,7 +966,7 @@ func TestAllCases(t *testing.T) { Sink: newSinkDestination(), }, }, - AdapterType: converters.CloudAuditLogsConverter, + AdapterType: string(converters.CloudAuditLogs), })), }, Key: testNS + "/" + sourceName, @@ -1041,7 +1041,7 @@ func TestAllCases(t *testing.T) { Sink: newSinkDestination(), }, }, - AdapterType: converters.CloudAuditLogsConverter, + AdapterType: string(converters.CloudAuditLogs), })), }, Key: testNS + "/" + sourceName, @@ -1116,7 +1116,7 @@ func TestAllCases(t *testing.T) { Sink: newSinkDestination(), }, }, - AdapterType: converters.CloudAuditLogsConverter, + AdapterType: string(converters.CloudAuditLogs), })), }, Key: testNS + "/" + sourceName, @@ -1185,7 +1185,7 @@ func TestAllCases(t *testing.T) { Sink: newSinkDestination(), }, }, - AdapterType: converters.CloudAuditLogsConverter, + AdapterType: string(converters.CloudAuditLogs), })), }, Key: testNS + "/" + sourceName, @@ -1408,7 +1408,13 @@ func TestAllCases(t *testing.T) { tt.Test(t, MakeFactory( func(ctx context.Context, listers *Listers, cmw configmap.Watcher, testData map[string]interface{}) controller.Reconciler { r := &Reconciler{ - PubSubBase: intevents.NewPubSubBaseWithAdapter(ctx, controllerAgentName, receiveAdapterName, converters.CloudAuditLogsConverter, cmw), + PubSubBase: intevents.NewPubSubBase(ctx, + &intevents.PubSubBaseArgs{ + ControllerAgentName: controllerAgentName, + ReceiveAdapterName: receiveAdapterName, + ReceiveAdapterType: string(converters.CloudAuditLogs), + ConfigWatcher: cmw, + }), Identity: identity.NewIdentity(ctx, NoopIAMPolicyManager, NewGCPAuthTestStore(t, nil)), auditLogsSourceLister: listers.GetCloudAuditLogsSourceLister(), logadminClientProvider: logadminClientProvider, diff --git a/pkg/reconciler/events/auditlogs/controller.go b/pkg/reconciler/events/auditlogs/controller.go index be33e1140a..3de9790488 100644 --- a/pkg/reconciler/events/auditlogs/controller.go +++ b/pkg/reconciler/events/auditlogs/controller.go @@ -76,7 +76,13 @@ func newController( serviceAccountInformer := serviceaccountinformers.Get(ctx) r := &Reconciler{ - PubSubBase: intevents.NewPubSubBaseWithAdapter(ctx, controllerAgentName, receiveAdapterName, converters.CloudAuditLogsConverter, cmw), + PubSubBase: intevents.NewPubSubBase(ctx, + &intevents.PubSubBaseArgs{ + ControllerAgentName: controllerAgentName, + ReceiveAdapterName: receiveAdapterName, + ReceiveAdapterType: string(converters.CloudAuditLogs), + ConfigWatcher: cmw, + }), Identity: identity.NewIdentity(ctx, ipm, gcpas), auditLogsSourceLister: cloudauditlogssourceInformer.Lister(), logadminClientProvider: glogadmin.NewClient, diff --git a/pkg/reconciler/events/build/build.go b/pkg/reconciler/events/build/build.go index 43926a7a16..192f6bd51b 100644 --- a/pkg/reconciler/events/build/build.go +++ b/pkg/reconciler/events/build/build.go @@ -19,8 +19,6 @@ package build import ( "context" - "github.com/google/knative-gcp/pkg/apis/events" - "go.uber.org/zap" corev1 "k8s.io/api/core/v1" @@ -29,6 +27,7 @@ import ( "knative.dev/pkg/logging" pkgreconciler "knative.dev/pkg/reconciler" + "github.com/google/knative-gcp/pkg/apis/events" "github.com/google/knative-gcp/pkg/apis/events/v1beta1" cloudbuildsourcereconciler "github.com/google/knative-gcp/pkg/client/injection/reconciler/events/v1beta1/cloudbuildsource" listers "github.com/google/knative-gcp/pkg/client/listers/events/v1beta1" @@ -73,7 +72,7 @@ func (r *Reconciler) ReconcileKind(ctx context.Context, build *v1beta1.CloudBuil return pkgreconciler.NewEvent(corev1.EventTypeWarning, workloadIdentityFailed, "Failed to reconcile CloudBuildSource workload identity: %s", err.Error()) } } - _, event := r.PubSubBase.ReconcilePullSubscription(ctx, build, events.CloudBuildTopic, resourceGroup, false) + _, event := r.PubSubBase.ReconcilePullSubscription(ctx, build, events.CloudBuildTopic, resourceGroup) if event != nil { return event } diff --git a/pkg/reconciler/events/build/build_test.go b/pkg/reconciler/events/build/build_test.go index 28c310ecde..b4392f13a1 100644 --- a/pkg/reconciler/events/build/build_test.go +++ b/pkg/reconciler/events/build/build_test.go @@ -23,7 +23,7 @@ import ( "testing" "github.com/google/knative-gcp/pkg/apis/events" - + "github.com/google/knative-gcp/pkg/pubsub/adapter/converters" corev1 "k8s.io/api/core/v1" apierrs "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -196,6 +196,7 @@ func TestAllCases(t *testing.T) { Sink: newSinkDestination(), }, }, + AdapterType: string(converters.CloudBuild), }), WithPullSubscriptionSink(sinkGVK, sinkName), WithPullSubscriptionLabels(map[string]string{ @@ -234,6 +235,7 @@ func TestAllCases(t *testing.T) { Sink: newSinkDestination(), }, }, + AdapterType: string(converters.CloudBuild), }), WithPullSubscriptionReadyStatus(corev1.ConditionFalse, "PullSubscriptionFalse", "status false test message")), newSink(), @@ -274,6 +276,7 @@ func TestAllCases(t *testing.T) { Sink: newSinkDestination(), }, }, + AdapterType: string(converters.CloudBuild), }), WithPullSubscriptionReadyStatus(corev1.ConditionUnknown, "PullSubscriptionUnknown", "status unknown test message")), newSink(), @@ -314,6 +317,7 @@ func TestAllCases(t *testing.T) { Sink: newSinkDestination(), }, }, + AdapterType: string(converters.CloudBuild), }), WithPullSubscriptionReady(sinkURI), WithPullSubscriptionReadyStatus(corev1.ConditionTrue, "PullSubscriptionNoReady", ""), @@ -366,7 +370,13 @@ func TestAllCases(t *testing.T) { defer logtesting.ClearAll() table.Test(t, MakeFactory(func(ctx context.Context, listers *Listers, cmw configmap.Watcher, _ map[string]interface{}) controller.Reconciler { r := &Reconciler{ - PubSubBase: intevents.NewPubSubBase(ctx, controllerAgentName, receiveAdapterName, cmw), + PubSubBase: intevents.NewPubSubBase(ctx, + &intevents.PubSubBaseArgs{ + ControllerAgentName: controllerAgentName, + ReceiveAdapterName: receiveAdapterName, + ReceiveAdapterType: string(converters.CloudBuild), + ConfigWatcher: cmw, + }), Identity: identity.NewIdentity(ctx, NoopIAMPolicyManager, NewGCPAuthTestStore(t, nil)), buildLister: listers.GetCloudBuildSourceLister(), serviceAccountLister: listers.GetServiceAccountLister(), diff --git a/pkg/reconciler/events/build/controller.go b/pkg/reconciler/events/build/controller.go index 51dc846ebe..a40a677414 100644 --- a/pkg/reconciler/events/build/controller.go +++ b/pkg/reconciler/events/build/controller.go @@ -67,7 +67,13 @@ func newController( serviceAccountInformer := serviceaccountinformers.Get(ctx) r := &Reconciler{ - PubSubBase: intevents.NewPubSubBaseWithAdapter(ctx, controllerAgentName, receiveAdapterName, converters.CloudBuildConverter, cmw), + PubSubBase: intevents.NewPubSubBase(ctx, + &intevents.PubSubBaseArgs{ + ControllerAgentName: controllerAgentName, + ReceiveAdapterName: receiveAdapterName, + ReceiveAdapterType: string(converters.CloudBuild), + ConfigWatcher: cmw, + }), Identity: identity.NewIdentity(ctx, ipm, gcpas), buildLister: cloudbuildsourceInformer.Lister(), serviceAccountLister: serviceAccountInformer.Lister(), diff --git a/pkg/reconciler/events/pubsub/controller.go b/pkg/reconciler/events/pubsub/controller.go index 81c90ad9f9..5ebfc4ac00 100644 --- a/pkg/reconciler/events/pubsub/controller.go +++ b/pkg/reconciler/events/pubsub/controller.go @@ -31,6 +31,7 @@ import ( cloudpubsubsourceinformers "github.com/google/knative-gcp/pkg/client/injection/informers/events/v1beta1/cloudpubsubsource" pullsubscriptioninformers "github.com/google/knative-gcp/pkg/client/injection/informers/intevents/v1beta1/pullsubscription" cloudpubsubsourcereconciler "github.com/google/knative-gcp/pkg/client/injection/reconciler/events/v1beta1/cloudpubsubsource" + "github.com/google/knative-gcp/pkg/pubsub/adapter/converters" "github.com/google/knative-gcp/pkg/reconciler" "github.com/google/knative-gcp/pkg/reconciler/identity" "github.com/google/knative-gcp/pkg/reconciler/identity/iam" @@ -69,7 +70,13 @@ func newController( serviceAccountInformer := serviceaccountinformers.Get(ctx) r := &Reconciler{ - PubSubBase: intevents.NewPubSubBase(ctx, controllerAgentName, receiveAdapterName, cmw), + PubSubBase: intevents.NewPubSubBase(ctx, + &intevents.PubSubBaseArgs{ + ControllerAgentName: controllerAgentName, + ReceiveAdapterName: receiveAdapterName, + ReceiveAdapterType: string(converters.CloudPubSub), + ConfigWatcher: cmw, + }), Identity: identity.NewIdentity(ctx, ipm, gcpas), pubsubLister: cloudpubsubsourceInformer.Lister(), } diff --git a/pkg/reconciler/events/pubsub/pubsub.go b/pkg/reconciler/events/pubsub/pubsub.go index 56216cb636..cfb8ec8172 100644 --- a/pkg/reconciler/events/pubsub/pubsub.go +++ b/pkg/reconciler/events/pubsub/pubsub.go @@ -64,7 +64,7 @@ func (r *Reconciler) ReconcileKind(ctx context.Context, pubsub *v1beta1.CloudPub } } - _, event := r.PubSubBase.ReconcilePullSubscription(ctx, pubsub, pubsub.Spec.Topic, resourceGroup, true) + _, event := r.PubSubBase.ReconcilePullSubscription(ctx, pubsub, pubsub.Spec.Topic, resourceGroup) if event != nil { return event } diff --git a/pkg/reconciler/events/pubsub/pubsub_test.go b/pkg/reconciler/events/pubsub/pubsub_test.go index d17cf4997e..d353d68794 100644 --- a/pkg/reconciler/events/pubsub/pubsub_test.go +++ b/pkg/reconciler/events/pubsub/pubsub_test.go @@ -43,6 +43,7 @@ import ( inteventsv1beta1 "github.com/google/knative-gcp/pkg/apis/intevents/v1beta1" "github.com/google/knative-gcp/pkg/client/injection/reconciler/events/v1beta1/cloudpubsubsource" testingMetadataClient "github.com/google/knative-gcp/pkg/gclient/metadata/testing" + "github.com/google/knative-gcp/pkg/pubsub/adapter/converters" "github.com/google/knative-gcp/pkg/reconciler/identity" "github.com/google/knative-gcp/pkg/reconciler/intevents" . "github.com/google/knative-gcp/pkg/reconciler/testing" @@ -191,9 +192,9 @@ func TestAllCases(t *testing.T) { PubSubSpec: duckv1beta1.PubSubSpec{ Secret: &secret, }, + AdapterType: string(converters.CloudPubSub), }), WithPullSubscriptionSink(sinkGVK, sinkName), - WithPullSubscriptionMode(inteventsv1beta1.ModePushCompatible), WithPullSubscriptionLabels(map[string]string{ "receive-adapter": receiveAdapterName, "events.cloud.google.com/source-name": pubsubName, @@ -231,7 +232,7 @@ func TestAllCases(t *testing.T) { Sink: newSinkDestination(), }, }, - Mode: inteventsv1beta1.ModePushCompatible, + AdapterType: string(converters.CloudPubSub), }), WithPullSubscriptionReadyStatus(corev1.ConditionFalse, "PullSubscriptionFalse", "status false test message")), newSink(), @@ -274,7 +275,7 @@ func TestAllCases(t *testing.T) { Sink: newSinkDestination(), }, }, - Mode: inteventsv1beta1.ModePushCompatible, + AdapterType: string(converters.CloudPubSub), }), WithPullSubscriptionReadyStatus(corev1.ConditionUnknown, "PullSubscriptionUnknown", "status unknown test message")), newSink(), @@ -317,7 +318,7 @@ func TestAllCases(t *testing.T) { Sink: newSinkDestination(), }, }, - Mode: inteventsv1beta1.ModePushCompatible, + AdapterType: string(converters.CloudPubSub), }), WithPullSubscriptionReady(sinkURI), WithPullSubscriptionReadyStatus(corev1.ConditionTrue, "PullSubscriptionNoReady", ""), @@ -372,7 +373,13 @@ func TestAllCases(t *testing.T) { defer logtesting.ClearAll() table.Test(t, MakeFactory(func(ctx context.Context, listers *Listers, cmw configmap.Watcher, _ map[string]interface{}) controller.Reconciler { r := &Reconciler{ - PubSubBase: intevents.NewPubSubBase(ctx, controllerAgentName, receiveAdapterName, cmw), + PubSubBase: intevents.NewPubSubBase(ctx, + &intevents.PubSubBaseArgs{ + ControllerAgentName: controllerAgentName, + ReceiveAdapterName: receiveAdapterName, + ReceiveAdapterType: string(converters.CloudPubSub), + ConfigWatcher: cmw, + }), Identity: identity.NewIdentity(ctx, NoopIAMPolicyManager, NewGCPAuthTestStore(t, nil)), pubsubLister: listers.GetCloudPubSubSourceLister(), } diff --git a/pkg/reconciler/events/scheduler/controller.go b/pkg/reconciler/events/scheduler/controller.go index b938195f4e..b25998ac2c 100644 --- a/pkg/reconciler/events/scheduler/controller.go +++ b/pkg/reconciler/events/scheduler/controller.go @@ -23,6 +23,7 @@ import ( "github.com/google/knative-gcp/pkg/apis/configs/gcpauth" "github.com/google/knative-gcp/pkg/apis/events/v1beta1" + "github.com/google/knative-gcp/pkg/pubsub/adapter/converters" "github.com/google/knative-gcp/pkg/reconciler" "github.com/google/knative-gcp/pkg/reconciler/identity" "github.com/google/knative-gcp/pkg/reconciler/identity/iam" @@ -72,7 +73,13 @@ func newController( serviceAccountInformer := serviceaccountinformers.Get(ctx) c := &Reconciler{ - PubSubBase: intevents.NewPubSubBase(ctx, controllerAgentName, receiveAdapterName, cmw), + PubSubBase: intevents.NewPubSubBase(ctx, + &intevents.PubSubBaseArgs{ + ControllerAgentName: controllerAgentName, + ReceiveAdapterName: receiveAdapterName, + ReceiveAdapterType: string(converters.CloudScheduler), + ConfigWatcher: cmw, + }), Identity: identity.NewIdentity(ctx, ipm, gcpas), schedulerLister: cloudschedulersourceInformer.Lister(), createClientFn: gscheduler.NewClient, diff --git a/pkg/reconciler/events/scheduler/scheduler.go b/pkg/reconciler/events/scheduler/scheduler.go index 3c60bd98ac..0193b46c46 100644 --- a/pkg/reconciler/events/scheduler/scheduler.go +++ b/pkg/reconciler/events/scheduler/scheduler.go @@ -33,7 +33,6 @@ import ( listers "github.com/google/knative-gcp/pkg/client/listers/events/v1beta1" metadataClient "github.com/google/knative-gcp/pkg/gclient/metadata" gscheduler "github.com/google/knative-gcp/pkg/gclient/scheduler" - "github.com/google/knative-gcp/pkg/pubsub/adapter/converters" "github.com/google/knative-gcp/pkg/reconciler/events/scheduler/resources" "github.com/google/knative-gcp/pkg/reconciler/identity" "github.com/google/knative-gcp/pkg/reconciler/intevents" @@ -122,9 +121,8 @@ func (r *Reconciler) reconcileJob(ctx context.Context, scheduler *v1beta1.CloudS } else if st.Code() == codes.NotFound { // Create the job as it does not exist. For creation, we need a parent, extract it from the jobName. parent := resources.ExtractParentName(jobName) - // Add our own converter type, jobName, and schedulerName as customAttributes. + // Add our jobName, and schedulerName as customAttributes. customAttributes := map[string]string{ - converters.KnativeGCPConverter: converters.CloudSchedulerConverter, v1beta1.CloudSchedulerSourceJobName: jobName, v1beta1.CloudSchedulerSourceName: scheduler.GetName(), } diff --git a/pkg/reconciler/events/scheduler/scheduler_test.go b/pkg/reconciler/events/scheduler/scheduler_test.go index ba776ee9ff..c9873ce3fd 100644 --- a/pkg/reconciler/events/scheduler/scheduler_test.go +++ b/pkg/reconciler/events/scheduler/scheduler_test.go @@ -46,6 +46,7 @@ import ( "github.com/google/knative-gcp/pkg/client/injection/reconciler/events/v1beta1/cloudschedulersource" testingMetadataClient "github.com/google/knative-gcp/pkg/gclient/metadata/testing" gscheduler "github.com/google/knative-gcp/pkg/gclient/scheduler/testing" + "github.com/google/knative-gcp/pkg/pubsub/adapter/converters" "github.com/google/knative-gcp/pkg/reconciler/identity" "github.com/google/knative-gcp/pkg/reconciler/intevents" . "github.com/google/knative-gcp/pkg/reconciler/testing" @@ -521,6 +522,7 @@ func TestAllCases(t *testing.T) { PubSubSpec: duckv1beta1.PubSubSpec{ Secret: &secret, }, + AdapterType: string(converters.CloudScheduler), }), WithPullSubscriptionSink(sinkGVK, sinkName), WithPullSubscriptionLabels(map[string]string{ @@ -570,6 +572,7 @@ func TestAllCases(t *testing.T) { Sink: newSinkDestination(), }, }, + AdapterType: string(converters.CloudScheduler), })), newSink(), }, @@ -623,6 +626,7 @@ func TestAllCases(t *testing.T) { Sink: newSinkDestination(), }, }, + AdapterType: string(converters.CloudScheduler), })), newSink(), }, @@ -676,6 +680,7 @@ func TestAllCases(t *testing.T) { Sink: newSinkDestination(), }, }, + AdapterType: string(converters.CloudScheduler), })), newSink(), }, @@ -733,6 +738,7 @@ func TestAllCases(t *testing.T) { }, Project: testProject, }, + AdapterType: string(converters.CloudScheduler), }), ), newSink(), @@ -800,6 +806,7 @@ func TestAllCases(t *testing.T) { }, Project: testProject, }, + AdapterType: string(converters.CloudScheduler), }), ), newSink(), @@ -867,6 +874,7 @@ func TestAllCases(t *testing.T) { }, Project: testProject, }, + AdapterType: string(converters.CloudScheduler), }), ), newSink(), @@ -934,6 +942,7 @@ func TestAllCases(t *testing.T) { }, Project: testProject, }, + AdapterType: string(converters.CloudScheduler), }), ), newSink(), @@ -1002,6 +1011,7 @@ func TestAllCases(t *testing.T) { }, Project: testProject, }, + AdapterType: string(converters.CloudScheduler), }), ), newSink(), @@ -1069,6 +1079,7 @@ func TestAllCases(t *testing.T) { }, Project: testProject, }, + AdapterType: string(converters.CloudScheduler), }), ), newSink(), @@ -1243,7 +1254,13 @@ func TestAllCases(t *testing.T) { defer logtesting.ClearAll() table.Test(t, MakeFactory(func(ctx context.Context, listers *Listers, cmw configmap.Watcher, testData map[string]interface{}) controller.Reconciler { r := &Reconciler{ - PubSubBase: intevents.NewPubSubBase(ctx, controllerAgentName, receiveAdapterName, cmw), + PubSubBase: intevents.NewPubSubBase(ctx, + &intevents.PubSubBaseArgs{ + ControllerAgentName: controllerAgentName, + ReceiveAdapterName: receiveAdapterName, + ReceiveAdapterType: string(converters.CloudScheduler), + ConfigWatcher: cmw, + }), Identity: identity.NewIdentity(ctx, NoopIAMPolicyManager, NewGCPAuthTestStore(t, nil)), schedulerLister: listers.GetCloudSchedulerSourceLister(), createClientFn: gscheduler.TestClientCreator(testData["scheduler"]), diff --git a/pkg/reconciler/events/storage/controller.go b/pkg/reconciler/events/storage/controller.go index 4f3b173913..1744a08239 100644 --- a/pkg/reconciler/events/storage/controller.go +++ b/pkg/reconciler/events/storage/controller.go @@ -21,6 +21,7 @@ import ( "knative.dev/pkg/injection" + "github.com/google/knative-gcp/pkg/pubsub/adapter/converters" "k8s.io/client-go/tools/cache" serviceaccountinformers "knative.dev/pkg/client/injection/kube/informers/core/v1/serviceaccount" "knative.dev/pkg/configmap" @@ -72,7 +73,13 @@ func newController( serviceAccountInformer := serviceaccountinformers.Get(ctx) r := &Reconciler{ - PubSubBase: intevents.NewPubSubBase(ctx, controllerAgentName, receiveAdapterName, cmw), + PubSubBase: intevents.NewPubSubBase(ctx, + &intevents.PubSubBaseArgs{ + ControllerAgentName: controllerAgentName, + ReceiveAdapterName: receiveAdapterName, + ReceiveAdapterType: string(converters.CloudStorage), + ConfigWatcher: cmw, + }), Identity: identity.NewIdentity(ctx, ipm, gcpas), storageLister: cloudstoragesourceInformer.Lister(), createClientFn: gstorage.NewClient, diff --git a/pkg/reconciler/events/storage/storage.go b/pkg/reconciler/events/storage/storage.go index 9a627785fd..33e07cca8c 100644 --- a/pkg/reconciler/events/storage/storage.go +++ b/pkg/reconciler/events/storage/storage.go @@ -34,7 +34,6 @@ import ( listers "github.com/google/knative-gcp/pkg/client/listers/events/v1beta1" metadataClient "github.com/google/knative-gcp/pkg/gclient/metadata" gstorage "github.com/google/knative-gcp/pkg/gclient/storage" - "github.com/google/knative-gcp/pkg/pubsub/adapter/converters" "github.com/google/knative-gcp/pkg/reconciler/events/storage/resources" "github.com/google/knative-gcp/pkg/reconciler/identity" "github.com/google/knative-gcp/pkg/reconciler/intevents" @@ -152,18 +151,12 @@ func (r *Reconciler) reconcileNotification(ctx context.Context, storage *v1beta1 // If the notification does not exist, then create it. - // Add our own converter type as a customAttribute. - customAttributes := map[string]string{ - converters.KnativeGCPConverter: converters.CloudStorageConverter, - } - nc := &Notification{ TopicProjectID: storage.Status.ProjectID, TopicID: storage.Status.TopicID, PayloadFormat: JSONPayload, EventTypes: r.toCloudStorageSourceEventTypes(storage.Spec.EventTypes), ObjectNamePrefix: storage.Spec.ObjectNamePrefix, - CustomAttributes: customAttributes, } notification, err := bucket.AddNotification(ctx, nc) diff --git a/pkg/reconciler/events/storage/storage_test.go b/pkg/reconciler/events/storage/storage_test.go index a3bd9f847a..fb168daa75 100644 --- a/pkg/reconciler/events/storage/storage_test.go +++ b/pkg/reconciler/events/storage/storage_test.go @@ -48,6 +48,7 @@ import ( "github.com/google/knative-gcp/pkg/client/injection/reconciler/events/v1beta1/cloudstoragesource" testingMetadataClient "github.com/google/knative-gcp/pkg/gclient/metadata/testing" gstorage "github.com/google/knative-gcp/pkg/gclient/storage/testing" + "github.com/google/knative-gcp/pkg/pubsub/adapter/converters" "github.com/google/knative-gcp/pkg/reconciler/identity" "github.com/google/knative-gcp/pkg/reconciler/intevents" . "github.com/google/knative-gcp/pkg/reconciler/testing" @@ -513,6 +514,7 @@ func TestAllCases(t *testing.T) { PubSubSpec: duckv1beta1.PubSubSpec{ Secret: &secret, }, + AdapterType: string(converters.CloudStorage), }), WithPullSubscriptionSink(sinkGVK, sinkName), WithPullSubscriptionLabels(map[string]string{ @@ -562,6 +564,7 @@ func TestAllCases(t *testing.T) { Sink: newSinkDestination(), }, }, + AdapterType: string(converters.CloudStorage), })), newSink(), }, @@ -615,6 +618,7 @@ func TestAllCases(t *testing.T) { Sink: newSinkDestination(), }, }, + AdapterType: string(converters.CloudStorage), }), WithPullSubscriptionFailed()), }, Key: testNS + "/" + storageName, @@ -667,6 +671,7 @@ func TestAllCases(t *testing.T) { Sink: newSinkDestination(), }, }, + AdapterType: string(converters.CloudStorage), })), }, Key: testNS + "/" + storageName, @@ -723,6 +728,7 @@ func TestAllCases(t *testing.T) { Sink: newSinkDestination(), }, }, + AdapterType: string(converters.CloudStorage), }), WithPullSubscriptionReady(sinkURI), ), @@ -794,6 +800,7 @@ func TestAllCases(t *testing.T) { Sink: newSinkDestination(), }, }, + AdapterType: string(converters.CloudStorage), }), WithPullSubscriptionReady(sinkURI), ), @@ -866,6 +873,7 @@ func TestAllCases(t *testing.T) { Sink: newSinkDestination(), }, }, + AdapterType: string(converters.CloudStorage), }), WithPullSubscriptionReady(sinkURI), ), @@ -938,6 +946,7 @@ func TestAllCases(t *testing.T) { Sink: newSinkDestination(), }, }, + AdapterType: string(converters.CloudStorage), }), WithPullSubscriptionReady(sinkURI), ), @@ -1010,6 +1019,7 @@ func TestAllCases(t *testing.T) { Sink: newSinkDestination(), }, }, + AdapterType: string(converters.CloudStorage), }), WithPullSubscriptionReady(sinkURI), ), @@ -1261,7 +1271,13 @@ func TestAllCases(t *testing.T) { defer logtesting.ClearAll() table.Test(t, MakeFactory(func(ctx context.Context, listers *Listers, cmw configmap.Watcher, testData map[string]interface{}) controller.Reconciler { r := &Reconciler{ - PubSubBase: intevents.NewPubSubBase(ctx, controllerAgentName, receiveAdapterName, cmw), + PubSubBase: intevents.NewPubSubBase(ctx, + &intevents.PubSubBaseArgs{ + ControllerAgentName: controllerAgentName, + ReceiveAdapterName: receiveAdapterName, + ReceiveAdapterType: string(converters.CloudStorage), + ConfigWatcher: cmw, + }), Identity: identity.NewIdentity(ctx, NoopIAMPolicyManager, NewGCPAuthTestStore(t, nil)), storageLister: listers.GetCloudStorageSourceLister(), createClientFn: gstorage.TestClientCreator(testData["storage"]), diff --git a/pkg/reconciler/intevents/controller.go b/pkg/reconciler/intevents/controller.go index 993fe3f01e..0590fd82c8 100644 --- a/pkg/reconciler/intevents/controller.go +++ b/pkg/reconciler/intevents/controller.go @@ -18,26 +18,24 @@ package intevents import ( "context" - "knative.dev/pkg/configmap" pubsubClient "github.com/google/knative-gcp/pkg/client/injection/client" "github.com/google/knative-gcp/pkg/reconciler" ) -func NewPubSubBase(ctx context.Context, controllerAgentName, receiveAdapterName string, cmw configmap.Watcher) *PubSubBase { - return &PubSubBase{ - Base: reconciler.NewBase(ctx, controllerAgentName, cmw), - pubsubClient: pubsubClient.Get(ctx), - receiveAdapterName: receiveAdapterName, - } +type PubSubBaseArgs struct { + ControllerAgentName string + ReceiveAdapterName string + ReceiveAdapterType string + ConfigWatcher configmap.Watcher } -func NewPubSubBaseWithAdapter(ctx context.Context, controllerAgentName, receiveAdapterName string, adapterType string, cmw configmap.Watcher) *PubSubBase { +func NewPubSubBase(ctx context.Context, args *PubSubBaseArgs) *PubSubBase { return &PubSubBase{ - Base: reconciler.NewBase(ctx, controllerAgentName, cmw), + Base: reconciler.NewBase(ctx, args.ControllerAgentName, args.ConfigWatcher), pubsubClient: pubsubClient.Get(ctx), - receiveAdapterName: receiveAdapterName, - adapterType: adapterType, + receiveAdapterName: args.ReceiveAdapterName, + receiveAdapterType: args.ReceiveAdapterType, } } diff --git a/pkg/reconciler/intevents/controller_test.go b/pkg/reconciler/intevents/controller_test.go index 98d7a14ce1..5610a99b3b 100644 --- a/pkg/reconciler/intevents/controller_test.go +++ b/pkg/reconciler/intevents/controller_test.go @@ -28,7 +28,13 @@ func TestNew(t *testing.T) { defer logtesting.ClearAll() ctx, _ := SetupFakeContext(t) - c := NewPubSubBase(ctx, "test-controller", "test-ra", configmap.NewStaticWatcher()) + args := &PubSubBaseArgs{ + ControllerAgentName: "test-controller", + ReceiveAdapterName: "test-ra", + ReceiveAdapterType: "test-ra-type", + ConfigWatcher: configmap.NewStaticWatcher(), + } + c := NewPubSubBase(ctx, args) if c == nil { t.Fatal("Expected NewPubSubBase to return a non-nil value") diff --git a/pkg/reconciler/intevents/pullsubscription/resources/receive_adapter.go b/pkg/reconciler/intevents/pullsubscription/resources/receive_adapter.go index f0cb5c4828..83e2b6c750 100644 --- a/pkg/reconciler/intevents/pullsubscription/resources/receive_adapter.go +++ b/pkg/reconciler/intevents/pullsubscription/resources/receive_adapter.go @@ -26,6 +26,7 @@ import ( "knative.dev/pkg/kmeta" "knative.dev/pkg/logging" + "github.com/google/knative-gcp/pkg/apis/intevents" "github.com/google/knative-gcp/pkg/apis/intevents/v1beta1" "github.com/google/knative-gcp/pkg/pubsub/adapter/converters" "github.com/google/knative-gcp/pkg/utils" @@ -94,6 +95,15 @@ func makeReceiveAdapterPodSpec(ctx context.Context, args *ReceiveAdapterArgs) *c transformerURI = args.TransformerURI.String() } + adapterType := args.PullSubscription.Spec.AdapterType + // If the PullSubscription has no Channel nor Source label, means that users created a PullSubscription manually. + // Then we set the adapter type to be PubSubPull. + _, isFromSource := args.PullSubscription.Labels[intevents.SourceLabelKey] + _, isFromChannel := args.PullSubscription.Labels[intevents.ChannelLabelKey] + if !isFromSource && !isFromChannel { + adapterType = string(converters.PubSubPull) + } + receiveAdapterContainer := corev1.Container{ Name: "receive-adapter", Image: args.Image, @@ -114,7 +124,7 @@ func makeReceiveAdapterPodSpec(ctx context.Context, args *ReceiveAdapterArgs) *c Value: transformerURI, }, { Name: "ADAPTER_TYPE", - Value: args.PullSubscription.Spec.AdapterType, + Value: adapterType, }, { Name: "SEND_MODE", Value: string(mode), diff --git a/pkg/reconciler/intevents/pullsubscription/resources/receive_adapter_test.go b/pkg/reconciler/intevents/pullsubscription/resources/receive_adapter_test.go index 42cb14572c..4db2b62d52 100644 --- a/pkg/reconciler/intevents/pullsubscription/resources/receive_adapter_test.go +++ b/pkg/reconciler/intevents/pullsubscription/resources/receive_adapter_test.go @@ -23,8 +23,10 @@ import ( "github.com/google/go-cmp/cmp" duckv1beta1 "github.com/google/knative-gcp/pkg/apis/duck/v1beta1" + "github.com/google/knative-gcp/pkg/apis/intevents" "github.com/google/knative-gcp/pkg/apis/intevents/v1beta1" testingmetadata "github.com/google/knative-gcp/pkg/gclient/metadata/testing" + "github.com/google/knative-gcp/pkg/pubsub/adapter/converters" v1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" @@ -38,6 +40,9 @@ func TestMakeMinimumReceiveAdapter(t *testing.T) { ObjectMeta: metav1.ObjectMeta{ Name: "testname", Namespace: "testnamespace", + Labels: map[string]string{ + intevents.SourceLabelKey: "my-source-name", + }, }, Spec: v1beta1.PullSubscriptionSpec{ PubSubSpec: duckv1beta1.PubSubSpec{ @@ -49,7 +54,8 @@ func TestMakeMinimumReceiveAdapter(t *testing.T) { }, Project: "eventing-name", }, - Topic: "topic", + Topic: "topic", + AdapterType: "source-adapter-type", }, } @@ -72,7 +78,7 @@ func TestMakeMinimumReceiveAdapter(t *testing.T) { want := &v1.Deployment{ ObjectMeta: metav1.ObjectMeta{ Namespace: "testnamespace", - Name: "cre-ps-testname-", + Name: "cre-src-testname-", Annotations: nil, Labels: map[string]string{ "test-key1": "test-value1", @@ -120,7 +126,8 @@ func TestMakeMinimumReceiveAdapter(t *testing.T) { }, { Name: "TRANSFORMER_URI", }, { - Name: "ADAPTER_TYPE", + Name: "ADAPTER_TYPE", + Value: "source-adapter-type", }, { Name: "SEND_MODE", Value: "binary", @@ -205,7 +212,7 @@ func TestMakeFullReceiveAdapter(t *testing.T) { }, }, Topic: "topic", - AdapterType: "adapter-type", + AdapterType: string(converters.PubSubPull), }, } @@ -279,7 +286,7 @@ func TestMakeFullReceiveAdapter(t *testing.T) { Value: "http://transformer-uri", }, { Name: "ADAPTER_TYPE", - Value: "adapter-type", + Value: string(converters.PubSubPull), }, { Name: "SEND_MODE", Value: "binary", @@ -442,7 +449,7 @@ func TestMakeReceiveAdapterWithServiceAccount(t *testing.T) { Value: "http://transformer-uri", }, { Name: "ADAPTER_TYPE", - Value: "adapter-type", + Value: string(converters.PubSubPull), }, { Name: "SEND_MODE", Value: "binary", diff --git a/pkg/reconciler/intevents/reconciler.go b/pkg/reconciler/intevents/reconciler.go index 8dc0eb68c4..178e673063 100644 --- a/pkg/reconciler/intevents/reconciler.go +++ b/pkg/reconciler/intevents/reconciler.go @@ -30,7 +30,7 @@ import ( corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/equality" apierrs "k8s.io/apimachinery/pkg/api/errors" - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1" "knative.dev/pkg/apis" "knative.dev/pkg/logging" pkgreconciler "knative.dev/pkg/reconciler" @@ -55,7 +55,7 @@ type PubSubBase struct { receiveAdapterName string // What type of receive adapter to use. - adapterType string + receiveAdapterType string } // ReconcilePubSub reconciles Topic / PullSubscription given a PubSubSpec. @@ -69,7 +69,7 @@ func (psb *PubSubBase) ReconcilePubSub(ctx context.Context, pubsubable duck.PubS return t, nil, err } - ps, err := psb.ReconcilePullSubscription(ctx, pubsubable, topic, resourceGroup, false) + ps, err := psb.ReconcilePullSubscription(ctx, pubsubable, topic, resourceGroup) if err != nil { return t, ps, err } @@ -128,7 +128,7 @@ func (psb *PubSubBase) reconcileTopic(ctx context.Context, pubsubable duck.PubSu return t, nil } -func (psb *PubSubBase) ReconcilePullSubscription(ctx context.Context, pubsubable duck.PubSubable, topic, resourceGroup string, isPushCompatible bool) (*inteventsv1beta1.PullSubscription, pkgreconciler.Event) { +func (psb *PubSubBase) ReconcilePullSubscription(ctx context.Context, pubsubable duck.PubSubable, topic, resourceGroup string) (*inteventsv1beta1.PullSubscription, pkgreconciler.Event) { if pubsubable == nil { logging.FromContext(ctx).Desugar().Error("Nil pubsubable passed in") return nil, pkgreconciler.NewEvent(corev1.EventTypeWarning, nilPubsubableReason, "nil pubsubable passed in") @@ -147,13 +147,11 @@ func (psb *PubSubBase) ReconcilePullSubscription(ctx context.Context, pubsubable Spec: spec, Owner: pubsubable, Topic: topic, - AdapterType: psb.adapterType, + AdapterType: psb.receiveAdapterType, Labels: resources.GetLabels(psb.receiveAdapterName, name), Annotations: resources.GetAnnotations(annotations, resourceGroup), } - if isPushCompatible { - args.Mode = inteventsv1beta1.ModePushCompatible - } + newPS := resources.MakePullSubscription(args) pullSubscriptions := psb.pubsubClient.InternalV1beta1().PullSubscriptions(namespace) diff --git a/pkg/reconciler/trigger/trigger_test.go b/pkg/reconciler/trigger/trigger_test.go index aeb67fa123..368a49f1e4 100644 --- a/pkg/reconciler/trigger/trigger_test.go +++ b/pkg/reconciler/trigger/trigger_test.go @@ -148,7 +148,9 @@ func TestAllCasesTrigger(t *testing.T) { NewTrigger(triggerName, testNS, brokerName, WithTriggerUID(testUID), WithTriggerFinalizers(finalizerName), - WithTriggerSetDefaults), + WithTriggerSetDefaults, + WithInitTriggerConditions, + ), }, WantEvents: []string{ Eventf(corev1.EventTypeNormal, "TopicDeleted", `Deleted PubSub topic "cre-tgr_testnamespace_test-trigger_abc123"`), @@ -172,7 +174,9 @@ func TestAllCasesTrigger(t *testing.T) { NewTrigger(triggerName, testNS, brokerName, WithTriggerUID(testUID), WithTriggerFinalizers(finalizerName), - WithTriggerSetDefaults), + WithTriggerSetDefaults, + WithInitTriggerConditions, + ), }, WantEvents: []string{ Eventf(corev1.EventTypeNormal, "TopicDeleted", `Deleted PubSub topic "cre-tgr_testnamespace_test-trigger_abc123"`), @@ -196,7 +200,9 @@ func TestAllCasesTrigger(t *testing.T) { NewTrigger(triggerName, testNS, brokerName, WithTriggerUID(testUID), WithTriggerFinalizers(finalizerName), - WithTriggerSetDefaults), + WithTriggerSetDefaults, + WithInitTriggerConditions, + ), }, WantEvents: []string{ Eventf(corev1.EventTypeNormal, "TopicDeleted", `Deleted PubSub topic "cre-tgr_testnamespace_test-trigger_abc123"`), @@ -260,7 +266,7 @@ func TestAllCasesTrigger(t *testing.T) { WithBrokerClass(brokerv1beta1.BrokerClass), WithInitBrokerConditions, WithBrokerReady("url"), - WithBrokerSetDefaults,), + WithBrokerSetDefaults, ), NewTrigger(triggerName, testNS, brokerName, WithTriggerUID(testUID), WithTriggerSubscriberRef(subscriberGVK, subscriberName, testNS), diff --git a/pkg/tracing/attributes.go b/pkg/tracing/attributes.go index 78c742f12b..4cdf91d386 100644 --- a/pkg/tracing/attributes.go +++ b/pkg/tracing/attributes.go @@ -16,7 +16,12 @@ limitations under the License. package tracing -import "knative.dev/eventing/pkg/tracing" +import ( + "fmt" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apimachinery/pkg/types" + "knative.dev/eventing/pkg/tracing" +) const ( PubSubProtocol = "Pub/Sub" @@ -25,3 +30,15 @@ const ( var ( PubSubProtocolAttribute = tracing.MessagingProtocolAttribute(PubSubProtocol) ) + +func SubscriptionDestination(s string) string { + return fmt.Sprintf("subscription:%s", s) +} + +func SourceDestination(resourceGroup string, src types.NamespacedName) string { + // resourceGroup is of the form .events.cloud.google.com, + // where resource can be for example cloudpubsubsources. + // We keep with the resource piece. + gr := schema.ParseGroupResource(resourceGroup) + return fmt.Sprintf("%s:%s.%s", gr.Resource, src.Name, src.Namespace) +} diff --git a/pkg/broker/ingress/args.go b/pkg/utils/clients/factories.go similarity index 67% rename from pkg/broker/ingress/args.go rename to pkg/utils/clients/factories.go index f0ea2ef75a..6e72afec98 100644 --- a/pkg/broker/ingress/args.go +++ b/pkg/utils/clients/factories.go @@ -14,10 +14,15 @@ See the License for the specific language governing permissions and limitations under the License. */ -package ingress +package clients import ( "context" + nethttp "net/http" + "time" + + "go.opencensus.io/plugin/ochttp" + "go.opencensus.io/plugin/ochttp/propagation/tracecontext" "cloud.google.com/go/pubsub" cepubsub "github.com/cloudevents/sdk-go/protocol/pubsub/v2" @@ -27,6 +32,7 @@ import ( type Port int type ProjectID string +type MaxConnsPerHost int // NewHTTPMessageReceiver wraps kncloudevents.NewHttpMessageReceiver with type-safe options. func NewHTTPMessageReceiver(port Port) *kncloudevents.HttpMessageReceiver { @@ -38,9 +44,8 @@ func NewPubsubClient(ctx context.Context, projectID ProjectID) (*pubsub.Client, return pubsub.NewClient(ctx, string(projectID)) } -// NewPubsubDecoupleClient creates a pubsub Cloudevents client to use to publish events to decouple queues. -func NewPubsubDecoupleClient(ctx context.Context, client *pubsub.Client) (cev2.Client, error) { - // Make a pubsub protocol for the CloudEvents client. +// NewObservedPubsubClient creates a pubsub Cloudevents client with observability support. +func NewObservedPubsubClient(ctx context.Context, client *pubsub.Client) (cev2.Client, error) { p, err := cepubsub.New(ctx, cepubsub.WithClient(client)) if err != nil { return nil, err @@ -53,3 +58,17 @@ func NewPubsubDecoupleClient(ctx context.Context, client *pubsub.Client) (cev2.C cev2.WithTracePropagation, ) } + +func NewHTTPClient(ctx context.Context, maxConnsPerHost MaxConnsPerHost) *nethttp.Client { + return &nethttp.Client{ + Transport: &ochttp.Transport{ + Base: &nethttp.Transport{ + MaxIdleConns: 1000, + MaxIdleConnsPerHost: int(maxConnsPerHost), + MaxConnsPerHost: int(maxConnsPerHost), + IdleConnTimeout: 30 * time.Second, + }, + Propagation: &tracecontext.HTTPFormat{}, + }, + } +} diff --git a/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/transport/pubsub/codec.go b/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/transport/pubsub/codec.go deleted file mode 100644 index 4401ef75b5..0000000000 --- a/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/transport/pubsub/codec.go +++ /dev/null @@ -1,116 +0,0 @@ -package pubsub - -import ( - "context" - "errors" - "fmt" - "sync" - - "github.com/cloudevents/sdk-go/pkg/cloudevents" - cecontext "github.com/cloudevents/sdk-go/pkg/cloudevents/context" - "github.com/cloudevents/sdk-go/pkg/cloudevents/transport" -) - -type Codec struct { - Encoding Encoding - - // DefaultEncodingSelectionFn allows for encoding selection strategies to be injected. - DefaultEncodingSelectionFn EncodingSelector - - v03 *CodecV03 - v1 *CodecV1 - - _v03 sync.Once - _v1 sync.Once -} - -const ( - prefix = "ce-" -) - -var _ transport.Codec = (*Codec)(nil) - -func (c *Codec) loadCodec(encoding Encoding) (transport.Codec, error) { - switch encoding { - case Default: - fallthrough - case BinaryV1, StructuredV1: - c._v1.Do(func() { - c.v1 = &CodecV1{DefaultEncoding: c.Encoding} - }) - return c.v1, nil - case BinaryV03, StructuredV03: - c._v03.Do(func() { - c.v03 = &CodecV03{DefaultEncoding: c.Encoding} - }) - return c.v03, nil - } - - return nil, fmt.Errorf("unknown encoding: %s", encoding) -} - -func (c *Codec) Encode(ctx context.Context, e cloudevents.Event) (transport.Message, error) { - encoding := c.Encoding - if encoding == Default && c.DefaultEncodingSelectionFn != nil { - encoding = c.DefaultEncodingSelectionFn(ctx, e) - } - codec, err := c.loadCodec(encoding) - if err != nil { - return nil, err - } - ctx = cecontext.WithEncoding(ctx, encoding.Name()) - return codec.Encode(ctx, e) -} - -func (c *Codec) Decode(ctx context.Context, msg transport.Message) (*cloudevents.Event, error) { - codec, err := c.loadCodec(c.inspectEncoding(ctx, msg)) - if err != nil { - return nil, err - } - event, err := codec.Decode(ctx, msg) - if err != nil { - return nil, err - } - return c.convertEvent(event) -} - -// Give the context back as the user expects -func (c *Codec) convertEvent(event *cloudevents.Event) (*cloudevents.Event, error) { - if event == nil { - return nil, errors.New("event is nil, can not convert") - } - - switch c.Encoding { - case Default: - return event, nil - case BinaryV03, StructuredV03: - ca := event.Context.AsV03() - event.Context = ca - return event, nil - case BinaryV1, StructuredV1: - ca := event.Context.AsV1() - event.Context = ca - return event, nil - default: - return nil, fmt.Errorf("unknown encoding: %s", c.Encoding) - } -} - -func (c *Codec) inspectEncoding(ctx context.Context, msg transport.Message) Encoding { - // Try v1.0. - _, _ = c.loadCodec(BinaryV1) - encoding := c.v1.inspectEncoding(ctx, msg) - if encoding != Unknown { - return encoding - } - - // Try v0.3. - _, _ = c.loadCodec(BinaryV03) - encoding = c.v03.inspectEncoding(ctx, msg) - if encoding != Unknown { - return encoding - } - - // We do not understand the message encoding. - return Unknown -} diff --git a/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/transport/pubsub/codec_structured.go b/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/transport/pubsub/codec_structured.go deleted file mode 100644 index 9ecafe604d..0000000000 --- a/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/transport/pubsub/codec_structured.go +++ /dev/null @@ -1,40 +0,0 @@ -package pubsub - -import ( - "context" - "encoding/json" - "fmt" - - "github.com/cloudevents/sdk-go/pkg/cloudevents" - "github.com/cloudevents/sdk-go/pkg/cloudevents/transport" -) - -// CodecStructured represents an structured http transport codec for all versions. -// Intended to be used as a base class. -type CodecStructured struct { - Encoding Encoding -} - -func (v CodecStructured) encodeStructured(ctx context.Context, e cloudevents.Event) (transport.Message, error) { - data, err := json.Marshal(e) - if err != nil { - return nil, err - } - - msg := &Message{ - Attributes: map[string]string{StructuredContentType: cloudevents.ApplicationCloudEventsJSON}, - Data: data, - } - - return msg, nil -} - -func (v CodecStructured) decodeStructured(ctx context.Context, version string, msg transport.Message) (*cloudevents.Event, error) { - m, ok := msg.(*Message) - if !ok { - return nil, fmt.Errorf("failed to convert transport.Message to pubsub.Message") - } - event := cloudevents.New(version) - err := json.Unmarshal(m.Data, &event) - return &event, err -} diff --git a/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/transport/pubsub/codec_v03.go b/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/transport/pubsub/codec_v03.go deleted file mode 100644 index d96ab3a699..0000000000 --- a/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/transport/pubsub/codec_v03.go +++ /dev/null @@ -1,286 +0,0 @@ -package pubsub - -import ( - "context" - "encoding/json" - "fmt" - "strings" - - "github.com/cloudevents/sdk-go/pkg/cloudevents" - cecontext "github.com/cloudevents/sdk-go/pkg/cloudevents/context" - "github.com/cloudevents/sdk-go/pkg/cloudevents/transport" - "github.com/cloudevents/sdk-go/pkg/cloudevents/types" -) - -const ( - StructuredContentType = "Content-Type" -) - -type CodecV03 struct { - CodecStructured - - DefaultEncoding Encoding -} - -var _ transport.Codec = (*CodecV03)(nil) - -func (v CodecV03) Encode(ctx context.Context, e cloudevents.Event) (transport.Message, error) { - encoding := v.DefaultEncoding - strEnc := cecontext.EncodingFrom(ctx) - if strEnc != "" { - switch strEnc { - case Binary: - encoding = BinaryV03 - case Structured: - encoding = StructuredV03 - } - } - switch encoding { - case Default: - fallthrough - case StructuredV03: - return v.encodeStructured(ctx, e) - case BinaryV03: - return v.encodeBinary(ctx, e) - default: - return nil, fmt.Errorf("unknown encoding: %d", encoding) - } -} - -func (v CodecV03) Decode(ctx context.Context, msg transport.Message) (*cloudevents.Event, error) { - // only structured is supported as of v0.3 - switch v.inspectEncoding(ctx, msg) { - case StructuredV03: - return v.decodeStructured(ctx, cloudevents.CloudEventsVersionV03, msg) - case BinaryV03: - event := cloudevents.New(cloudevents.CloudEventsVersionV03) - return v.decodeBinary(ctx, msg, &event) - default: - return nil, transport.NewErrMessageEncodingUnknown("v03", TransportName) - } -} - -func (v CodecV03) inspectEncoding(ctx context.Context, msg transport.Message) Encoding { - version := msg.CloudEventsVersion() - if version != cloudevents.CloudEventsVersionV03 { - return Unknown - } - m, ok := msg.(*Message) - if !ok { - return Unknown - } - if m.Attributes[StructuredContentType] == cloudevents.ApplicationCloudEventsJSON { - return StructuredV03 - } - return BinaryV03 -} - -func (v CodecV03) encodeBinary(ctx context.Context, e cloudevents.Event) (transport.Message, error) { - attributes, err := v.toAttributes(e) - if err != nil { - return nil, err - } - data, err := e.DataBytes() - if err != nil { - return nil, err - } - - msg := &Message{ - Attributes: attributes, - Data: data, - } - - return msg, nil -} - -func (v CodecV03) toAttributes(e cloudevents.Event) (map[string]string, error) { - a := make(map[string]string) - a[prefix+"specversion"] = e.SpecVersion() - a[prefix+"type"] = e.Type() - a[prefix+"source"] = e.Source() - a[prefix+"id"] = e.ID() - if !e.Time().IsZero() { - t := types.Timestamp{Time: e.Time()} // TODO: change e.Time() to return string so I don't have to do this. - a[prefix+"time"] = t.String() - } - if e.DataSchema() != "" { - a[prefix+"schemaurl"] = e.DataSchema() - } - - if e.DataContentType() != "" { - a[prefix+"datacontenttype"] = e.DataContentType() - } else { - a[prefix+"datacontenttype"] = cloudevents.ApplicationJSON - } - - if e.Subject() != "" { - a[prefix+"subject"] = e.Subject() - } - - if e.DeprecatedDataContentEncoding() != "" { - a[prefix+"datacontentencoding"] = e.DeprecatedDataContentEncoding() - } - - for k, v := range e.Extensions() { - if mapVal, ok := v.(map[string]interface{}); ok { - for subkey, subval := range mapVal { - encoded, err := json.Marshal(subval) - if err != nil { - return nil, err - } - a[prefix+k+"-"+subkey] = string(encoded) - } - continue - } - if s, ok := v.(string); ok { - a[prefix+k] = s - continue - } - encoded, err := json.Marshal(v) - if err != nil { - return nil, err - } - a[prefix+k] = string(encoded) - } - - return a, nil -} - -func (v CodecV03) decodeBinary(ctx context.Context, msg transport.Message, event *cloudevents.Event) (*cloudevents.Event, error) { - m, ok := msg.(*Message) - if !ok { - return nil, fmt.Errorf("failed to convert transport.Message to pubsub.Message") - } - err := v.fromAttributes(m.Attributes, event) - if err != nil { - return nil, err - } - var data interface{} - if len(m.Data) > 0 { - data = m.Data - } - event.Data = data - event.DataEncoded = true - return event, nil -} - -func (v CodecV03) fromAttributes(a map[string]string, event *cloudevents.Event) error { - // Normalize attributes. - for k, v := range a { - ck := strings.ToLower(k) - if k != ck { - delete(a, k) - a[ck] = v - } - } - - ec := event.Context - - if sv := a[prefix+"specversion"]; sv != "" { - if err := ec.SetSpecVersion(sv); err != nil { - return err - } - } - delete(a, prefix+"specversion") - - if id := a[prefix+"id"]; id != "" { - if err := ec.SetID(id); err != nil { - return err - } - } - delete(a, prefix+"id") - - if t := a[prefix+"type"]; t != "" { - if err := ec.SetType(t); err != nil { - return err - } - } - delete(a, prefix+"type") - - if s := a[prefix+"source"]; s != "" { - if err := ec.SetSource(s); err != nil { - return err - } - } - delete(a, prefix+"source") - - if t := a[prefix+"time"]; t != "" { - if timestamp, err := types.ParseTimestamp(t); err != nil { - return err - } else if err := ec.SetTime(timestamp.Time); err != nil { - return err - } - } - delete(a, prefix+"time") - - if s := a[prefix+"schemaurl"]; s != "" { - if err := ec.SetDataSchema(s); err != nil { - return err - } - } - delete(a, prefix+"schemaurl") - - if s := a[prefix+"subject"]; s != "" { - if err := ec.SetSubject(s); err != nil { - return err - } - } - delete(a, prefix+"subject") - - if s := a[prefix+"datacontenttype"]; s != "" { - if err := ec.SetDataContentType(s); err != nil { - return err - } - } - delete(a, prefix+"datacontenttype") - - if s := a[prefix+"datacontentencoding"]; s != "" { - if err := ec.DeprecatedSetDataContentEncoding(s); err != nil { - return err - } - } - delete(a, prefix+"datacontentencoding") - - // At this point, we have deleted all the known headers. - // Everything left is assumed to be an extension. - - extensions := make(map[string]interface{}) - for k, v := range a { - if len(k) > len(prefix) && strings.EqualFold(k[:len(prefix)], prefix) { - ak := strings.ToLower(k[len(prefix):]) - if i := strings.Index(ak, "-"); i > 0 { - // attrib-key - attrib := ak[:i] - key := ak[(i + 1):] - if xv, ok := extensions[attrib]; ok { - if m, ok := xv.(map[string]interface{}); ok { - m[key] = v - continue - } - // TODO: revisit how we want to bubble errors up. - return fmt.Errorf("failed to process map type extension") - } else { - m := make(map[string]interface{}) - m[key] = v - extensions[attrib] = m - } - } else { - // key - var tmp interface{} - if err := json.Unmarshal([]byte(v), &tmp); err == nil { - extensions[ak] = tmp - } else { - // If we can't unmarshal the data, treat it as a string. - extensions[ak] = v - } - } - } - } - event.Context = ec - if len(extensions) > 0 { - for k, v := range extensions { - event.SetExtension(k, v) - } - } - return nil -} diff --git a/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/transport/pubsub/codec_v1.go b/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/transport/pubsub/codec_v1.go deleted file mode 100644 index 2d091010a7..0000000000 --- a/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/transport/pubsub/codec_v1.go +++ /dev/null @@ -1,242 +0,0 @@ -package pubsub - -import ( - "context" - "fmt" - "strings" - - "github.com/cloudevents/sdk-go/pkg/cloudevents" - cecontext "github.com/cloudevents/sdk-go/pkg/cloudevents/context" - "github.com/cloudevents/sdk-go/pkg/cloudevents/transport" - "github.com/cloudevents/sdk-go/pkg/cloudevents/types" -) - -type CodecV1 struct { - CodecStructured - - DefaultEncoding Encoding -} - -var _ transport.Codec = (*CodecV1)(nil) - -func (v CodecV1) Encode(ctx context.Context, e cloudevents.Event) (transport.Message, error) { - encoding := v.DefaultEncoding - strEnc := cecontext.EncodingFrom(ctx) - if strEnc != "" { - switch strEnc { - case Binary: - encoding = BinaryV1 - case Structured: - encoding = StructuredV1 - } - } - switch encoding { - case Default: - fallthrough - case StructuredV1: - return v.encodeStructured(ctx, e) - case BinaryV1: - return v.encodeBinary(ctx, e) - default: - return nil, fmt.Errorf("unknown encoding: %d", v.Encoding) - } -} - -func (v CodecV1) Decode(ctx context.Context, msg transport.Message) (*cloudevents.Event, error) { - // only structured is supported as of v0.3 - switch v.inspectEncoding(ctx, msg) { - case StructuredV1: - return v.decodeStructured(ctx, cloudevents.CloudEventsVersionV1, msg) - case BinaryV1: - event := cloudevents.New(cloudevents.CloudEventsVersionV1) - return v.decodeBinary(ctx, msg, &event) - default: - return nil, transport.NewErrMessageEncodingUnknown("V1", TransportName) - } -} - -func (v CodecV1) inspectEncoding(ctx context.Context, msg transport.Message) Encoding { - version := msg.CloudEventsVersion() - if version != cloudevents.CloudEventsVersionV1 { - return Unknown - } - m, ok := msg.(*Message) - if !ok { - return Unknown - } - if m.Attributes[StructuredContentType] == cloudevents.ApplicationCloudEventsJSON { - return StructuredV1 - } - return BinaryV1 -} - -func (v CodecV1) encodeBinary(ctx context.Context, e cloudevents.Event) (transport.Message, error) { - attributes, err := v.toAttributes(e) - if err != nil { - return nil, err - } - data, err := e.DataBytes() - if err != nil { - return nil, err - } - - msg := &Message{ - Attributes: attributes, - Data: data, - } - - return msg, nil -} - -func (v CodecV1) toAttributes(e cloudevents.Event) (map[string]string, error) { - a := make(map[string]string) - a[prefix+"specversion"] = e.SpecVersion() - a[prefix+"type"] = e.Type() - a[prefix+"source"] = e.Source() - a[prefix+"id"] = e.ID() - if !e.Time().IsZero() { - t := types.Timestamp{Time: e.Time()} // TODO: change e.Time() to return string so I don't have to do this. - a[prefix+"time"] = t.String() - } - if e.DataSchema() != "" { - a[prefix+"dataschema"] = e.DataSchema() - } - - if e.DataContentType() != "" { - a[prefix+"datacontenttype"] = e.DataContentType() - } else { - a[prefix+"datacontenttype"] = cloudevents.ApplicationJSON - } - - if e.Subject() != "" { - a[prefix+"subject"] = e.Subject() - } - - if e.DeprecatedDataContentEncoding() != "" { - a[prefix+"datacontentencoding"] = e.DeprecatedDataContentEncoding() - } - - for k, v := range e.Extensions() { - k = strings.ToLower(k) - cstr, err := types.Format(v) - if err != nil { - return a, err - } - a[prefix+k] = cstr - } - return a, nil -} - -func (v CodecV1) decodeBinary(ctx context.Context, msg transport.Message, event *cloudevents.Event) (*cloudevents.Event, error) { - m, ok := msg.(*Message) - if !ok { - return nil, fmt.Errorf("failed to convert transport.Message to pubsub.Message") - } - err := v.fromAttributes(m.Attributes, event) - if err != nil { - return nil, err - } - var data interface{} - if len(m.Data) > 0 { - data = m.Data - } - event.Data = data - event.DataEncoded = true - return event, nil -} - -func (v CodecV1) fromAttributes(a map[string]string, event *cloudevents.Event) error { - // Normalize attributes. - for k, v := range a { - ck := strings.ToLower(k) - if k != ck { - delete(a, k) - a[ck] = v - } - } - - ec := event.Context - - if sv := a[prefix+"specversion"]; sv != "" { - if err := ec.SetSpecVersion(sv); err != nil { - return err - } - } - delete(a, prefix+"specversion") - - if id := a[prefix+"id"]; id != "" { - if err := ec.SetID(id); err != nil { - return err - } - } - delete(a, prefix+"id") - - if t := a[prefix+"type"]; t != "" { - if err := ec.SetType(t); err != nil { - return err - } - } - delete(a, prefix+"type") - - if s := a[prefix+"source"]; s != "" { - if err := ec.SetSource(s); err != nil { - return err - } - } - delete(a, prefix+"source") - - if t := a[prefix+"time"]; t != "" { - if timestamp, err := types.ParseTimestamp(t); err != nil { - return err - } else if err := ec.SetTime(timestamp.Time); err != nil { - return err - } - } - delete(a, prefix+"time") - - if s := a[prefix+"dataschema"]; s != "" { - if err := ec.SetDataSchema(s); err != nil { - return err - } - } - delete(a, prefix+"dataschema") - - if s := a[prefix+"subject"]; s != "" { - if err := ec.SetSubject(s); err != nil { - return err - } - } - delete(a, prefix+"subject") - - if s := a[prefix+"datacontenttype"]; s != "" { - if err := ec.SetDataContentType(s); err != nil { - return err - } - } - delete(a, prefix+"datacontenttype") - - if s := a[prefix+"datacontentencoding"]; s != "" { - if err := ec.DeprecatedSetDataContentEncoding(s); err != nil { - return err - } - } - delete(a, prefix+"datacontentencoding") - - // At this point, we have deleted all the known headers. - // Everything left is assumed to be an extension. - - extensions := make(map[string]interface{}) - for k, v := range a { - if len(k) > len(prefix) && strings.EqualFold(k[:len(prefix)], prefix) { - ak := strings.ToLower(k[len(prefix):]) - extensions[ak] = v - } - } - event.Context = ec - if len(extensions) > 0 { - for k, v := range extensions { - event.SetExtension(k, v) - } - } - return nil -} diff --git a/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/transport/pubsub/context/context.go b/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/transport/pubsub/context/context.go deleted file mode 100644 index e64a5ee71b..0000000000 --- a/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/transport/pubsub/context/context.go +++ /dev/null @@ -1,94 +0,0 @@ -package context - -import ( - "context" - "strings" - "time" - - "cloud.google.com/go/pubsub" -) - -// TransportContext allows a Receiver to understand the context of a request. -type TransportContext struct { - ID string - PublishTime time.Time - Project string - Topic string - Subscription string - Method string // push or pull -} - -// NewTransportContext creates a new TransportContext from a pubsub.Message. -func NewTransportContext(project, topic, subscription, method string, msg *pubsub.Message) TransportContext { - var tx *TransportContext - if msg != nil { - tx = &TransportContext{ - ID: msg.ID, - PublishTime: msg.PublishTime, - Project: project, - Topic: topic, - Subscription: subscription, - Method: method, - } - } else { - tx = &TransportContext{} - } - return *tx -} - -// String generates a pretty-printed version of the resource as a string. -func (tx TransportContext) String() string { - b := strings.Builder{} - - b.WriteString("Transport Context,\n") - - if tx.ID != "" { - b.WriteString(" ID: " + tx.ID + "\n") - } - if !tx.PublishTime.IsZero() { - b.WriteString(" PublishTime: " + tx.PublishTime.String() + "\n") - } - - if tx.Project != "" { - b.WriteString(" Project: " + tx.Project + "\n") - } - - if tx.Topic != "" { - b.WriteString(" Topic: " + tx.Topic + "\n") - } - - if tx.Subscription != "" { - b.WriteString(" Subscription: " + tx.Subscription + "\n") - } - - if tx.Method != "" { - b.WriteString(" Method: " + tx.Method + "\n") - } - - return b.String() -} - -// Opaque key type used to store TransportContext -type transportContextKeyType struct{} - -var transportContextKey = transportContextKeyType{} - -// WithTransportContext return a context with the given TransportContext into the provided context object. -func WithTransportContext(ctx context.Context, tcxt TransportContext) context.Context { - return context.WithValue(ctx, transportContextKey, tcxt) -} - -// TransportContextFrom pulls a TransportContext out of a context. Always -// returns a non-nil object. -func TransportContextFrom(ctx context.Context) TransportContext { - tctx := ctx.Value(transportContextKey) - if tctx != nil { - if tx, ok := tctx.(TransportContext); ok { - return tx - } - if tx, ok := tctx.(*TransportContext); ok { - return *tx - } - } - return TransportContext{} -} diff --git a/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/transport/pubsub/doc.go b/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/transport/pubsub/doc.go deleted file mode 100644 index b45504609c..0000000000 --- a/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/transport/pubsub/doc.go +++ /dev/null @@ -1,4 +0,0 @@ -/* -Package pubsub implements the CloudEvent transport implementation using pubsub. -*/ -package pubsub diff --git a/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/transport/pubsub/encoding.go b/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/transport/pubsub/encoding.go deleted file mode 100644 index 33717f720b..0000000000 --- a/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/transport/pubsub/encoding.go +++ /dev/null @@ -1,114 +0,0 @@ -package pubsub - -import ( - "context" - - "github.com/cloudevents/sdk-go/pkg/cloudevents" -) - -// Encoding to use for pubsub transport. -type Encoding int32 - -type EncodingSelector func(context.Context, cloudevents.Event) Encoding - -const ( - // Default allows pubsub transport implementation to pick. - Default Encoding = iota - // BinaryV03 is Binary CloudEvents spec v0.3. - BinaryV03 - // BinaryV1 is Binary CloudEvents spec v1.0. - BinaryV1 - // StructuredV03 is Structured CloudEvents spec v0.3. - StructuredV03 - // StructuredV1 is Structured CloudEvents spec v1.0. - StructuredV1 - - // Unknown is unknown. - Unknown - - // Binary is used for Context Based Encoding Selections to use the - // DefaultBinaryEncodingSelectionStrategy - Binary = "binary" - - // Structured is used for Context Based Encoding Selections to use the - // DefaultStructuredEncodingSelectionStrategy - Structured = "structured" -) - -// DefaultBinaryEncodingSelectionStrategy implements a selection process for -// which binary encoding to use based on spec version of the event. -func DefaultBinaryEncodingSelectionStrategy(ctx context.Context, e cloudevents.Event) Encoding { - switch e.SpecVersion() { - case cloudevents.CloudEventsVersionV01, cloudevents.CloudEventsVersionV02, cloudevents.CloudEventsVersionV03: - return BinaryV03 - case cloudevents.CloudEventsVersionV1: - return BinaryV1 - } - // Unknown version, return Default. - return Default -} - -// DefaultStructuredEncodingSelectionStrategy implements a selection process -// for which structured encoding to use based on spec version of the event. -func DefaultStructuredEncodingSelectionStrategy(ctx context.Context, e cloudevents.Event) Encoding { - switch e.SpecVersion() { - case cloudevents.CloudEventsVersionV01, cloudevents.CloudEventsVersionV02, cloudevents.CloudEventsVersionV03: - return StructuredV03 - case cloudevents.CloudEventsVersionV1: - return StructuredV1 - } - // Unknown version, return Default. - return Default -} - -// String pretty-prints the encoding as a string. -func (e Encoding) String() string { - switch e { - case Default: - return "Default Encoding " + e.Version() - - // Binary - case BinaryV03, BinaryV1: - return "Binary Encoding " + e.Version() - - // Structured - case StructuredV03, StructuredV1: - return "Structured Encoding " + e.Version() - - default: - return "Unknown Encoding" - } -} - -// Version pretty-prints the encoding version as a string. -func (e Encoding) Version() string { - switch e { - - // Version 0.2 - // Version 0.3 - case Default, BinaryV03, StructuredV03: - return "v0.3" - - // Version 1.0 - case BinaryV1, StructuredV1: - return "v1.0" - - // Unknown - default: - return "Unknown" - } -} - -// Name creates a string to represent the the codec name. -func (e Encoding) Name() string { - switch e { - case Default: - return Binary - case BinaryV03, BinaryV1: - return Binary - case StructuredV03, StructuredV1: - return Structured - default: - return Binary - } -} diff --git a/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/transport/pubsub/internal/connection.go b/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/transport/pubsub/internal/connection.go deleted file mode 100644 index 8265651618..0000000000 --- a/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/transport/pubsub/internal/connection.go +++ /dev/null @@ -1,210 +0,0 @@ -package internal - -import ( - "context" - "errors" - "fmt" - "sync" - "time" - - "cloud.google.com/go/pubsub" - "github.com/cloudevents/sdk-go/pkg/cloudevents" - pscontext "github.com/cloudevents/sdk-go/pkg/cloudevents/transport/pubsub/context" -) - -// Connection acts as either a pubsub topic or a pubsub subscription . -type Connection struct { - // AllowCreateTopic controls if the transport can create a topic if it does - // not exist. - AllowCreateTopic bool - - // AllowCreateSubscription controls if the transport can create a - // subscription if it does not exist. - AllowCreateSubscription bool - - ProjectID string - - Client *pubsub.Client - - TopicID string - topic *pubsub.Topic - topicWasCreated bool - topicOnce sync.Once - - SubscriptionID string - sub *pubsub.Subscription - subWasCreated bool - subOnce sync.Once - - // ReceiveSettings is used to configure Pubsub pull subscription. - ReceiveSettings *pubsub.ReceiveSettings - - // AckDeadline is Pub/Sub AckDeadline. - // Default is 30 seconds. - AckDeadline *time.Duration - // RetentionDuration is Pub/Sub RetentionDuration. - // Default is 25 hours. - RetentionDuration *time.Duration -} - -const ( - DefaultAckDeadline = 30 * time.Second - DefaultRetentionDuration = 25 * time.Hour -) - -var DefaultReceiveSettings = pubsub.ReceiveSettings{ - // Pubsub default receive settings will fill in other values. - // https://godoc.org/cloud.google.com/go/pubsub#Client.Subscription - - // Override the default number of goroutines. - // This is a magical number now. This has shown throughput improvements empirically - // by at least 10x (compared to the default value). - NumGoroutines: 1000, - Synchronous: false, -} - -func (c *Connection) getOrCreateTopic(ctx context.Context) (*pubsub.Topic, error) { - var err error - c.topicOnce.Do(func() { - var ok bool - // Load the topic. - topic := c.Client.Topic(c.TopicID) - ok, err = topic.Exists(ctx) - if err != nil { - return - } - // If the topic does not exist, create a new topic with the given name. - if !ok { - if !c.AllowCreateTopic { - err = fmt.Errorf("transport not allowed to create topic %q", c.TopicID) - return - } - topic, err = c.Client.CreateTopic(ctx, c.TopicID) - if err != nil { - return - } - c.topicWasCreated = true - } - // Success. - c.topic = topic - }) - if c.topic == nil { - return nil, fmt.Errorf("unable to create topic %q, %v", c.TopicID, err) - } - return c.topic, err -} - -// DeleteTopic -func (c *Connection) DeleteTopic(ctx context.Context) error { - if !c.topicWasCreated { - return errors.New("topic was not created by pubsub transport") - } - if err := c.topic.Delete(ctx); err != nil { - return err - } - c.topic = nil - c.topicWasCreated = false - c.topicOnce = sync.Once{} - return nil -} - -func (c *Connection) getOrCreateSubscription(ctx context.Context) (*pubsub.Subscription, error) { - var err error - c.subOnce.Do(func() { - // Load the subscription. - var ok bool - sub := c.Client.Subscription(c.SubscriptionID) - ok, err = sub.Exists(ctx) - if err != nil { - return - } - // If subscription doesn't exist, create it. - if !ok { - if !c.AllowCreateSubscription { - err = fmt.Errorf("transport not allowed to create subscription %q", c.SubscriptionID) - return - } - - // Load the topic. - var topic *pubsub.Topic - topic, err = c.getOrCreateTopic(ctx) - if err != nil { - return - } - // Default the ack deadline and retention duration config. - if c.AckDeadline == nil { - ackDeadline := DefaultAckDeadline - c.AckDeadline = &(ackDeadline) - } - if c.RetentionDuration == nil { - retentionDuration := DefaultRetentionDuration - c.RetentionDuration = &retentionDuration - } - - // Create a new subscription to the previously created topic - // with the given name. - // TODO: allow to use push config + allow setting the SubscriptionConfig. - sub, err = c.Client.CreateSubscription(ctx, c.SubscriptionID, pubsub.SubscriptionConfig{ - Topic: topic, - AckDeadline: *c.AckDeadline, - RetentionDuration: *c.RetentionDuration, - }) - if err != nil { - _ = c.Client.Close() - return - } - if c.ReceiveSettings == nil { - sub.ReceiveSettings = DefaultReceiveSettings - } else { - sub.ReceiveSettings = *c.ReceiveSettings - } - c.subWasCreated = true - } - // Success. - c.sub = sub - }) - if c.sub == nil { - return nil, fmt.Errorf("unable to create sunscription %q, %v", c.SubscriptionID, err) - } - return c.sub, err -} - -// DeleteSubscription -func (c *Connection) DeleteSubscription(ctx context.Context) error { - if !c.subWasCreated { - return errors.New("subscription was not created by pubsub transport") - } - if err := c.sub.Delete(ctx); err != nil { - return err - } - c.sub = nil - c.subWasCreated = false - c.subOnce = sync.Once{} - return nil -} - -// Publish -func (c *Connection) Publish(ctx context.Context, msg *pubsub.Message) (*cloudevents.Event, error) { - topic, err := c.getOrCreateTopic(ctx) - if err != nil { - return nil, err - } - - r := topic.Publish(ctx, msg) - _, err = r.Get(ctx) - return nil, err -} - -// Start -// NOTE: This is a blocking call. -func (c *Connection) Receive(ctx context.Context, fn func(context.Context, *pubsub.Message)) error { - sub, err := c.getOrCreateSubscription(ctx) - if err != nil { - return err - } - // Ok, ready to start pulling. - return sub.Receive(ctx, func(ctx context.Context, m *pubsub.Message) { - ctx = pscontext.WithTransportContext(ctx, pscontext.NewTransportContext(c.ProjectID, c.TopicID, c.SubscriptionID, "pull", m)) - fn(ctx, m) - }) -} diff --git a/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/transport/pubsub/message.go b/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/transport/pubsub/message.go deleted file mode 100644 index 3430e581b4..0000000000 --- a/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/transport/pubsub/message.go +++ /dev/null @@ -1,47 +0,0 @@ -package pubsub - -import ( - "encoding/json" - - "github.com/cloudevents/sdk-go/pkg/cloudevents/transport" -) - -// type check that this transport message impl matches the contract -var _ transport.Message = (*Message)(nil) - -// Message represents a Pub/Sub message. -type Message struct { - // Data is the actual data in the message. - Data []byte - - // Attributes represents the key-value pairs the current message - // is labelled with. - Attributes map[string]string -} - -func (m Message) CloudEventsVersion() string { - // Check as Binary encoding first. - if m.Attributes != nil { - // Binary v0.3: - if s := m.Attributes[prefix+"specversion"]; s != "" { - return s - } - } - - // Now check as Structured encoding. - raw := make(map[string]json.RawMessage) - if err := json.Unmarshal(m.Data, &raw); err != nil { - return "" - } - - // structured v0.3 - if v, ok := raw["specversion"]; ok { - var version string - if err := json.Unmarshal(v, &version); err != nil { - return "" - } - return version - } - - return "" -} diff --git a/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/transport/pubsub/options.go b/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/transport/pubsub/options.go deleted file mode 100644 index a77adb246a..0000000000 --- a/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/transport/pubsub/options.go +++ /dev/null @@ -1,207 +0,0 @@ -package pubsub - -import ( - "fmt" - "os" - - "cloud.google.com/go/pubsub" -) - -// Option is the function signature required to be considered an pubsub.Option. -type Option func(*Transport) error - -const ( - DefaultProjectEnvKey = "GOOGLE_CLOUD_PROJECT" - DefaultTopicEnvKey = "PUBSUB_TOPIC" - DefaultSubscriptionEnvKey = "PUBSUB_SUBSCRIPTION" -) - -// WithEncoding sets the encoding for pubsub transport. -func WithEncoding(encoding Encoding) Option { - return func(t *Transport) error { - t.Encoding = encoding - return nil - } -} - -// WithDefaultEncodingSelector sets the encoding selection strategy for -// default encoding selections based on Event. -func WithDefaultEncodingSelector(fn EncodingSelector) Option { - return func(t *Transport) error { - if t == nil { - return fmt.Errorf("http default encoding selector option can not set nil transport") - } - if fn != nil { - t.DefaultEncodingSelectionFn = fn - return nil - } - return fmt.Errorf("pubsub fn for DefaultEncodingSelector was nil") - } -} - -// WithBinaryEncoding sets the encoding selection strategy for -// default encoding selections based on Event, the encoded event will be the -// given version in Binary form. -func WithBinaryEncoding() Option { - return func(t *Transport) error { - if t == nil { - return fmt.Errorf("pubsub binary encoding option can not set nil transport") - } - - t.DefaultEncodingSelectionFn = DefaultBinaryEncodingSelectionStrategy - return nil - } -} - -// WithStructuredEncoding sets the encoding selection strategy for -// default encoding selections based on Event, the encoded event will be the -// given version in Structured form. -func WithStructuredEncoding() Option { - return func(t *Transport) error { - if t == nil { - return fmt.Errorf("pubsub structured encoding option can not set nil transport") - } - - t.DefaultEncodingSelectionFn = DefaultStructuredEncodingSelectionStrategy - return nil - } -} - -// WithClient sets the pubsub client for pubsub transport. Use this for explicit -// auth setup. Otherwise the env var 'GOOGLE_APPLICATION_CREDENTIALS' is used. -// See https://cloud.google.com/docs/authentication/production for more details. -func WithClient(client *pubsub.Client) Option { - return func(t *Transport) error { - t.client = client - return nil - } -} - -// WithProjectID sets the project ID for pubsub transport. -func WithProjectID(projectID string) Option { - return func(t *Transport) error { - t.projectID = projectID - return nil - } -} - -// WithProjectIDFromEnv sets the project ID for pubsub transport from a -// given environment variable name. -func WithProjectIDFromEnv(key string) Option { - return func(t *Transport) error { - v := os.Getenv(key) - if v == "" { - return fmt.Errorf("unable to load project id, %q environment variable not set", key) - } - t.projectID = v - return nil - } -} - -// WithProjectIDFromDefaultEnv sets the project ID for pubsub transport from -// the environment variable named 'GOOGLE_CLOUD_PROJECT'. -func WithProjectIDFromDefaultEnv() Option { - return WithProjectIDFromEnv(DefaultProjectEnvKey) -} - -// WithTopicID sets the topic ID for pubsub transport. -func WithTopicID(topicID string) Option { - return func(t *Transport) error { - t.topicID = topicID - return nil - } -} - -// WithTopicIDFromEnv sets the topic ID for pubsub transport from a given -// environment variable name. -func WithTopicIDFromEnv(key string) Option { - return func(t *Transport) error { - v := os.Getenv(key) - if v == "" { - return fmt.Errorf("unable to load topic id, %q environment variable not set", key) - } - t.topicID = v - return nil - } -} - -// WithTopicIDFromDefaultEnv sets the topic ID for pubsub transport from the -// environment variable named 'PUBSUB_TOPIC'. -func WithTopicIDFromDefaultEnv() Option { - return WithTopicIDFromEnv(DefaultTopicEnvKey) -} - -// WithSubscriptionID sets the subscription ID for pubsub transport. -// This option can be used multiple times. -func WithSubscriptionID(subscriptionID string) Option { - return func(t *Transport) error { - if t.subscriptions == nil { - t.subscriptions = make([]subscriptionWithTopic, 0) - } - t.subscriptions = append(t.subscriptions, subscriptionWithTopic{ - subscriptionID: subscriptionID, - }) - return nil - } -} - -// WithSubscriptionAndTopicID sets the subscription and topic IDs for pubsub transport. -// This option can be used multiple times. -func WithSubscriptionAndTopicID(subscriptionID, topicID string) Option { - return func(t *Transport) error { - if t.subscriptions == nil { - t.subscriptions = make([]subscriptionWithTopic, 0) - } - t.subscriptions = append(t.subscriptions, subscriptionWithTopic{ - subscriptionID: subscriptionID, - topicID: topicID, - }) - return nil - } -} - -// WithSubscriptionIDFromEnv sets the subscription ID for pubsub transport from -// a given environment variable name. -func WithSubscriptionIDFromEnv(key string) Option { - return func(t *Transport) error { - v := os.Getenv(key) - if v == "" { - return fmt.Errorf("unable to load subscription id, %q environment variable not set", key) - } - - opt := WithSubscriptionID(v) - return opt(t) - } -} - -// WithSubscriptionIDFromDefaultEnv sets the subscription ID for pubsub -// transport from the environment variable named 'PUBSUB_SUBSCRIPTION'. -func WithSubscriptionIDFromDefaultEnv() Option { - return WithSubscriptionIDFromEnv(DefaultSubscriptionEnvKey) -} - -// AllowCreateTopic sets if the transport can create a topic if it does not -// exist. -func AllowCreateTopic(allow bool) Option { - return func(t *Transport) error { - t.AllowCreateTopic = allow - return nil - } -} - -// AllowCreateSubscription sets if the transport can create a subscription if -// it does not exist. -func AllowCreateSubscription(allow bool) Option { - return func(t *Transport) error { - t.AllowCreateSubscription = allow - return nil - } -} - -// WithReceiveSettings sets the Pubsub ReceiveSettings for pull subscriptions. -func WithReceiveSettings(rs *pubsub.ReceiveSettings) Option { - return func(t *Transport) error { - t.ReceiveSettings = rs - return nil - } -} diff --git a/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/transport/pubsub/transport.go b/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/transport/pubsub/transport.go deleted file mode 100644 index 310d0d253f..0000000000 --- a/vendor/github.com/cloudevents/sdk-go/pkg/cloudevents/transport/pubsub/transport.go +++ /dev/null @@ -1,317 +0,0 @@ -package pubsub - -import ( - "context" - "errors" - "fmt" - "strings" - "sync" - - "go.uber.org/zap" - - "cloud.google.com/go/pubsub" - - "github.com/cloudevents/sdk-go/pkg/cloudevents" - cecontext "github.com/cloudevents/sdk-go/pkg/cloudevents/context" - "github.com/cloudevents/sdk-go/pkg/cloudevents/transport" - "github.com/cloudevents/sdk-go/pkg/cloudevents/transport/pubsub/internal" -) - -// Transport adheres to transport.Transport. -var _ transport.Transport = (*Transport)(nil) - -const ( - TransportName = "Pub/Sub" -) - -type subscriptionWithTopic struct { - topicID string - subscriptionID string -} - -// Transport acts as both a pubsub topic and a pubsub subscription . -type Transport struct { - // Encoding - Encoding Encoding - - // DefaultEncodingSelectionFn allows for other encoding selection strategies to be injected. - DefaultEncodingSelectionFn EncodingSelector - - codec transport.Codec - // Codec Mutex - coMu sync.Mutex - - // PubSub - - // ReceiveSettings is used to configure Pubsub pull subscription. - ReceiveSettings *pubsub.ReceiveSettings - - // AllowCreateTopic controls if the transport can create a topic if it does - // not exist. - AllowCreateTopic bool - - // AllowCreateSubscription controls if the transport can create a - // subscription if it does not exist. - AllowCreateSubscription bool - - projectID string - topicID string - subscriptionID string - - gccMux sync.Mutex - - subscriptions []subscriptionWithTopic - client *pubsub.Client - - connectionsBySubscription map[string]*internal.Connection - connectionsByTopic map[string]*internal.Connection - - // Receiver - Receiver transport.Receiver - - // Converter is invoked if the incoming transport receives an undecodable - // message. - Converter transport.Converter -} - -// New creates a new pubsub transport. -func New(ctx context.Context, opts ...Option) (*Transport, error) { - t := &Transport{} - if err := t.applyOptions(opts...); err != nil { - return nil, err - } - - if t.client == nil { - // Auth to pubsub. - client, err := pubsub.NewClient(ctx, t.projectID) - if err != nil { - return nil, err - } - // Success. - t.client = client - } - - if t.connectionsBySubscription == nil { - t.connectionsBySubscription = make(map[string]*internal.Connection, 0) - } - - if t.connectionsByTopic == nil { - t.connectionsByTopic = make(map[string]*internal.Connection, 0) - } - return t, nil -} - -func (t *Transport) applyOptions(opts ...Option) error { - for _, fn := range opts { - if err := fn(t); err != nil { - return err - } - } - return nil -} - -func (t *Transport) loadCodec(ctx context.Context) bool { - if t.codec == nil { - t.coMu.Lock() - if t.DefaultEncodingSelectionFn != nil && t.Encoding != Default { - logger := cecontext.LoggerFrom(ctx) - logger.Warn("transport has a DefaultEncodingSelectionFn set but Encoding is not Default. DefaultEncodingSelectionFn will be ignored.") - - t.codec = &Codec{ - Encoding: t.Encoding, - } - } else { - t.codec = &Codec{ - Encoding: t.Encoding, - DefaultEncodingSelectionFn: t.DefaultEncodingSelectionFn, - } - } - t.coMu.Unlock() - } - return true -} - -func (t *Transport) getConnection(ctx context.Context, topic, subscription string) *internal.Connection { - if subscription != "" { - if conn, ok := t.connectionsBySubscription[subscription]; ok { - return conn - } - } - if topic != "" { - if conn, ok := t.connectionsByTopic[topic]; ok { - return conn - } - } - - return nil -} - -func (t *Transport) getOrCreateConnection(ctx context.Context, topic, subscription string) *internal.Connection { - t.gccMux.Lock() - defer t.gccMux.Unlock() - - // Get. - if conn := t.getConnection(ctx, topic, subscription); conn != nil { - return conn - } - // Create. - conn := &internal.Connection{ - AllowCreateSubscription: t.AllowCreateSubscription, - AllowCreateTopic: t.AllowCreateTopic, - ReceiveSettings: t.ReceiveSettings, - Client: t.client, - ProjectID: t.projectID, - TopicID: topic, - SubscriptionID: subscription, - } - // Save for later. - if subscription != "" { - t.connectionsBySubscription[subscription] = conn - } - if topic != "" { - t.connectionsByTopic[topic] = conn - } - - return conn -} - -// Send implements Transport.Send -func (t *Transport) Send(ctx context.Context, event cloudevents.Event) (context.Context, *cloudevents.Event, error) { - // TODO populate response context properly. - if ok := t.loadCodec(ctx); !ok { - return ctx, nil, fmt.Errorf("unknown encoding set on transport: %d", t.Encoding) - } - - topic := cecontext.TopicFrom(ctx) - if topic == "" { - topic = t.topicID - } - - conn := t.getOrCreateConnection(ctx, topic, "") - - msg, err := t.codec.Encode(ctx, event) - if err != nil { - return ctx, nil, err - } - - if m, ok := msg.(*Message); ok { - respEvent, err := conn.Publish(ctx, &pubsub.Message{ - Attributes: m.Attributes, - Data: m.Data, - }) - return ctx, respEvent, err - } - - return ctx, nil, fmt.Errorf("failed to encode Event into a Message") -} - -// SetReceiver implements Transport.SetReceiver -func (t *Transport) SetReceiver(r transport.Receiver) { - t.Receiver = r -} - -// SetConverter implements Transport.SetConverter -func (t *Transport) SetConverter(c transport.Converter) { - t.Converter = c -} - -// HasConverter implements Transport.HasConverter -func (t *Transport) HasConverter() bool { - return t.Converter != nil -} - -func (t *Transport) startSubscriber(ctx context.Context, sub subscriptionWithTopic, done func(error)) { - logger := cecontext.LoggerFrom(ctx) - logger.Infof("starting subscriber for Topic %q, Subscription %q", sub.topicID, sub.subscriptionID) - conn := t.getOrCreateConnection(ctx, sub.topicID, sub.subscriptionID) - - logger.Info("conn is", conn) - if conn == nil { - err := fmt.Errorf("failed to find connection for Topic: %q, Subscription: %q", sub.topicID, sub.subscriptionID) - done(err) - return - } - // Ok, ready to start pulling. - err := conn.Receive(ctx, func(ctx context.Context, m *pubsub.Message) { - msg := &Message{ - Attributes: m.Attributes, - Data: m.Data, - } - event, err := t.codec.Decode(ctx, msg) - // If codec returns and error, try with the converter if it is set. - if err != nil && t.HasConverter() { - event, err = t.Converter.Convert(ctx, msg, err) - } - if err != nil { - logger.Errorw("failed to decode message", zap.Error(err)) - m.Nack() - return - } - - if err := t.Receiver.Receive(ctx, *event, nil); err != nil { - logger.Warnw("pubsub receiver return err", zap.Error(err)) - m.Nack() - return - } - m.Ack() - }) - done(err) -} - -// StartReceiver implements Transport.StartReceiver -// NOTE: This is a blocking call. -func (t *Transport) StartReceiver(ctx context.Context) error { - // Load the codec. - if ok := t.loadCodec(ctx); !ok { - return fmt.Errorf("unknown encoding set on transport: %d", t.Encoding) - } - - cctx, cancel := context.WithCancel(ctx) - defer cancel() - n := len(t.subscriptions) - - // Make the channels for quit and errors. - quit := make(chan struct{}, n) - errc := make(chan error, n) - - // Start up each subscription. - for _, sub := range t.subscriptions { - go t.startSubscriber(cctx, sub, func(err error) { - if err != nil { - errc <- err - } else { - quit <- struct{}{} - } - }) - } - - // Collect errors and done calls until we have n of them. - errs := []string(nil) - for success := 0; success < n; success++ { - var err error - select { - case <-ctx.Done(): // Block for parent context to finish. - success-- - case err = <-errc: // Collect errors - case <-quit: - } - if cancel != nil { - // Stop all other subscriptions. - cancel() - cancel = nil - } - if err != nil { - errs = append(errs, err.Error()) - } - } - - close(quit) - close(errc) - - return errors.New(strings.Join(errs, "\n")) -} - -// HasTracePropagation implements Transport.HasTracePropagation -func (t *Transport) HasTracePropagation() bool { - return false -} diff --git a/vendor/knative.dev/eventing/pkg/apis/eventing/v1/broker_conversion.go b/vendor/knative.dev/eventing/pkg/apis/eventing/v1/broker_conversion.go new file mode 100644 index 0000000000..30f555c43b --- /dev/null +++ b/vendor/knative.dev/eventing/pkg/apis/eventing/v1/broker_conversion.go @@ -0,0 +1,34 @@ +/* +Copyright 2020 The Knative Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1 + +import ( + "context" + "fmt" + + "knative.dev/pkg/apis" +) + +// ConvertTo implements apis.Convertible +func (source *Broker) ConvertTo(ctx context.Context, sink apis.Convertible) error { + return fmt.Errorf("v1 is the highest known version, got: %T", sink) +} + +// ConvertFrom implements apis.Convertible +func (sink *Broker) ConvertFrom(ctx context.Context, source apis.Convertible) error { + return fmt.Errorf("v1 is the highest known version, got: %T", source) +} diff --git a/vendor/knative.dev/eventing/pkg/apis/eventing/v1/broker_defaults.go b/vendor/knative.dev/eventing/pkg/apis/eventing/v1/broker_defaults.go new file mode 100644 index 0000000000..2ae42be8e7 --- /dev/null +++ b/vendor/knative.dev/eventing/pkg/apis/eventing/v1/broker_defaults.go @@ -0,0 +1,47 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1 + +import ( + "context" + + "knative.dev/eventing/pkg/apis/config" + "knative.dev/eventing/pkg/apis/eventing" + "knative.dev/pkg/apis" +) + +func (b *Broker) SetDefaults(ctx context.Context) { + // Default Spec fields. + withNS := apis.WithinParent(ctx, b.ObjectMeta) + b.Spec.SetDefaults(withNS) + eventing.DefaultBrokerClassIfUnset(withNS, &b.ObjectMeta) +} + +func (bs *BrokerSpec) SetDefaults(ctx context.Context) { + if bs.Config != nil { + // Default the namespace if not given + bs.Config.SetDefaults(ctx) + return + } + + cfg := config.FromContextOrDefaults(ctx) + c, err := cfg.Defaults.GetBrokerConfig(apis.ParentMeta(ctx).Namespace) + if err == nil { + c.SetDefaults(ctx) + bs.Config = c + } +} diff --git a/vendor/knative.dev/eventing/pkg/apis/eventing/v1/broker_lifecycle.go b/vendor/knative.dev/eventing/pkg/apis/eventing/v1/broker_lifecycle.go new file mode 100644 index 0000000000..ebd71cde53 --- /dev/null +++ b/vendor/knative.dev/eventing/pkg/apis/eventing/v1/broker_lifecycle.go @@ -0,0 +1,114 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1 + +import ( + corev1 "k8s.io/api/core/v1" + + "knative.dev/eventing/pkg/apis/duck" + duckv1 "knative.dev/eventing/pkg/apis/duck/v1" + "knative.dev/pkg/apis" +) + +var brokerCondSet = apis.NewLivingConditionSet( + BrokerConditionIngress, + BrokerConditionTriggerChannel, + BrokerConditionFilter, + BrokerConditionAddressable, +) + +const ( + BrokerConditionReady = apis.ConditionReady + BrokerConditionIngress apis.ConditionType = "IngressReady" + BrokerConditionTriggerChannel apis.ConditionType = "TriggerChannelReady" + BrokerConditionFilter apis.ConditionType = "FilterReady" + BrokerConditionAddressable apis.ConditionType = "Addressable" +) + +// GetConditionSet retrieves the condition set for this resource. Implements the KRShaped interface. +func (*Broker) GetConditionSet() apis.ConditionSet { + return brokerCondSet +} + +// GetTopLevelCondition returns the top level Condition. +func (bs *BrokerStatus) GetTopLevelCondition() *apis.Condition { + return brokerCondSet.Manage(bs).GetTopLevelCondition() +} + +// SetAddress makes this Broker addressable by setting the URI. It also +// sets the BrokerConditionAddressable to true. +func (bs *BrokerStatus) SetAddress(url *apis.URL) { + bs.Address.URL = url + if url != nil { + brokerCondSet.Manage(bs).MarkTrue(BrokerConditionAddressable) + } else { + brokerCondSet.Manage(bs).MarkFalse(BrokerConditionAddressable, "nil URL", "URL is nil") + } +} + +// GetCondition returns the condition currently associated with the given type, or nil. +func (bs *BrokerStatus) GetCondition(t apis.ConditionType) *apis.Condition { + return brokerCondSet.Manage(bs).GetCondition(t) +} + +// IsReady returns true if the resource is ready overall. +func (bs *BrokerStatus) IsReady() bool { + return brokerCondSet.Manage(bs).IsHappy() +} + +// InitializeConditions sets relevant unset conditions to Unknown state. +func (bs *BrokerStatus) InitializeConditions() { + brokerCondSet.Manage(bs).InitializeConditions() +} + +func (bs *BrokerStatus) MarkIngressFailed(reason, format string, args ...interface{}) { + brokerCondSet.Manage(bs).MarkFalse(BrokerConditionIngress, reason, format, args...) +} + +func (bs *BrokerStatus) PropagateIngressAvailability(ep *corev1.Endpoints) { + if duck.EndpointsAreAvailable(ep) { + brokerCondSet.Manage(bs).MarkTrue(BrokerConditionIngress) + } else { + bs.MarkIngressFailed("EndpointsUnavailable", "Endpoints %q are unavailable.", ep.Name) + } +} + +func (bs *BrokerStatus) MarkTriggerChannelFailed(reason, format string, args ...interface{}) { + brokerCondSet.Manage(bs).MarkFalse(BrokerConditionTriggerChannel, reason, format, args...) +} + +func (bs *BrokerStatus) PropagateTriggerChannelReadiness(cs *duckv1.ChannelableStatus) { + // TODO: Once you can get a Ready status from Channelable in a generic way, use it here... + address := cs.AddressStatus.Address + if address != nil { + brokerCondSet.Manage(bs).MarkTrue(BrokerConditionTriggerChannel) + } else { + bs.MarkTriggerChannelFailed("ChannelNotReady", "trigger Channel is not ready: not addressable") + } +} + +func (bs *BrokerStatus) MarkFilterFailed(reason, format string, args ...interface{}) { + brokerCondSet.Manage(bs).MarkFalse(BrokerConditionFilter, reason, format, args...) +} + +func (bs *BrokerStatus) PropagateFilterAvailability(ep *corev1.Endpoints) { + if duck.EndpointsAreAvailable(ep) { + brokerCondSet.Manage(bs).MarkTrue(BrokerConditionFilter) + } else { + bs.MarkFilterFailed("EndpointsUnavailable", "Endpoints %q are unavailable.", ep.Name) + } +} diff --git a/vendor/knative.dev/eventing/pkg/apis/eventing/v1/broker_types.go b/vendor/knative.dev/eventing/pkg/apis/eventing/v1/broker_types.go new file mode 100644 index 0000000000..0fc1b1177d --- /dev/null +++ b/vendor/knative.dev/eventing/pkg/apis/eventing/v1/broker_types.go @@ -0,0 +1,119 @@ +/* + * Copyright 2020 The Knative Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package v1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + + eventingduckv1 "knative.dev/eventing/pkg/apis/duck/v1" + "knative.dev/pkg/apis" + duckv1 "knative.dev/pkg/apis/duck/v1" + "knative.dev/pkg/kmeta" +) + +// +genclient +// +genreconciler:class=eventing.knative.dev/broker.class,krshapedlogic=true +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// Broker collects a pool of events that are consumable using Triggers. Brokers +// provide a well-known endpoint for event delivery that senders can use with +// minimal knowledge of the event routing strategy. Receivers use Triggers to +// request delivery of events from a Broker's pool to a specific URL or +// Addressable endpoint. +type Broker struct { + metav1.TypeMeta `json:",inline"` + // +optional + metav1.ObjectMeta `json:"metadata,omitempty"` + + // Spec defines the desired state of the Broker. + Spec BrokerSpec `json:"spec,omitempty"` + + // Status represents the current state of the Broker. This data may be out of + // date. + // +optional + Status BrokerStatus `json:"status,omitempty"` +} + +var ( + // Check that Broker can be validated, can be defaulted, and has immutable fields. + _ apis.Validatable = (*Broker)(nil) + _ apis.Defaultable = (*Broker)(nil) + + // Check that Broker can return its spec untyped. + _ apis.HasSpec = (*Broker)(nil) + + _ runtime.Object = (*Broker)(nil) + + // Check that we can create OwnerReferences to a Broker. + _ kmeta.OwnerRefable = (*Broker)(nil) + + // Check that the type conforms to the duck Knative Resource shape. + _ duckv1.KRShaped = (*Broker)(nil) +) + +type BrokerSpec struct { + // Config is a KReference to the configuration that specifies + // configuration options for this Broker. For example, this could be + // a pointer to a ConfigMap. + // +optional + Config *duckv1.KReference `json:"config,omitempty"` + + // Delivery is the delivery specification for Events within the Broker mesh. + // This includes things like retries, DLQ, etc. + // +optional + Delivery *eventingduckv1.DeliverySpec `json:"delivery,omitempty"` +} + +// BrokerStatus represents the current state of a Broker. +type BrokerStatus struct { + // inherits duck/v1 Status, which currently provides: + // * ObservedGeneration - the 'Generation' of the Broker that was last processed by the controller. + // * Conditions - the latest available observations of a resource's current state. + duckv1.Status `json:",inline"` + + // Broker is Addressable. It exposes the endpoint as an URI to get events + // delivered into the Broker mesh. + Address duckv1.Addressable `json:"address,omitempty"` +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// BrokerList is a collection of Brokers. +type BrokerList struct { + metav1.TypeMeta `json:",inline"` + // +optional + metav1.ListMeta `json:"metadata,omitempty"` + + Items []Broker `json:"items"` +} + +// GetGroupVersionKind returns GroupVersionKind for Brokers +func (t *Broker) GetGroupVersionKind() schema.GroupVersionKind { + return SchemeGroupVersion.WithKind("Broker") +} + +// GetUntypedSpec returns the spec of the Broker. +func (b *Broker) GetUntypedSpec() interface{} { + return b.Spec +} + +// GetStatus retrieves the status of the Broker. Implements the KRShaped interface. +func (t *Broker) GetStatus() *duckv1.Status { + return &t.Status.Status +} diff --git a/vendor/knative.dev/eventing/pkg/apis/eventing/v1/broker_validation.go b/vendor/knative.dev/eventing/pkg/apis/eventing/v1/broker_validation.go new file mode 100644 index 0000000000..e7e0e8a3c4 --- /dev/null +++ b/vendor/knative.dev/eventing/pkg/apis/eventing/v1/broker_validation.go @@ -0,0 +1,76 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1 + +import ( + "context" + + "knative.dev/pkg/apis" + "knative.dev/pkg/kmp" +) + +const ( + BrokerClassAnnotationKey = "eventing.knative.dev/broker.class" +) + +func (b *Broker) Validate(ctx context.Context) *apis.FieldError { + withNS := apis.AllowDifferentNamespace(apis.WithinParent(ctx, b.ObjectMeta)) + return b.Spec.Validate(withNS).ViaField("spec") +} + +func (bs *BrokerSpec) Validate(ctx context.Context) *apis.FieldError { + var errs *apis.FieldError + + // Validate the Config + if bs.Config != nil { + if ce := bs.Config.Validate(ctx); ce != nil { + errs = errs.Also(ce.ViaField("config")) + } + } + + if bs.Delivery != nil { + if de := bs.Delivery.Validate(ctx); de != nil { + errs = errs.Also(de.ViaField("delivery")) + } + } + return errs +} + +func (b *Broker) CheckImmutableFields(ctx context.Context, original *Broker) *apis.FieldError { + if original == nil { + return nil + } + + // Make sure you can't change the class annotation. + diff, err := kmp.ShortDiff(original.GetAnnotations()[BrokerClassAnnotationKey], b.GetAnnotations()[BrokerClassAnnotationKey]) + + if err != nil { + return &apis.FieldError{ + Message: "couldn't diff the Broker objects", + Details: err.Error(), + } + } + + if diff != "" { + return &apis.FieldError{ + Message: "Immutable fields changed (-old +new)", + Paths: []string{"annotations"}, + Details: diff, + } + } + return nil +} diff --git a/vendor/knative.dev/eventing/pkg/apis/eventing/v1/doc.go b/vendor/knative.dev/eventing/pkg/apis/eventing/v1/doc.go new file mode 100644 index 0000000000..312443ded7 --- /dev/null +++ b/vendor/knative.dev/eventing/pkg/apis/eventing/v1/doc.go @@ -0,0 +1,20 @@ +/* + * Copyright 2020 The Knative Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// Package v1 is the v1 version of the API. +// +k8s:deepcopy-gen=package +// +groupName=eventing.knative.dev +package v1 diff --git a/vendor/knative.dev/eventing/pkg/apis/eventing/v1/register.go b/vendor/knative.dev/eventing/pkg/apis/eventing/v1/register.go new file mode 100644 index 0000000000..0ff47f32ff --- /dev/null +++ b/vendor/knative.dev/eventing/pkg/apis/eventing/v1/register.go @@ -0,0 +1,55 @@ +/* + * Copyright 2020 The Knative Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package v1 + +import ( + "knative.dev/eventing/pkg/apis/eventing" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" +) + +// SchemeGroupVersion is group version used to register these objects +var SchemeGroupVersion = schema.GroupVersion{Group: eventing.GroupName, Version: "v1"} + +// Kind takes an unqualified kind and returns back a Group qualified GroupKind +func Kind(kind string) schema.GroupKind { + return SchemeGroupVersion.WithKind(kind).GroupKind() +} + +// Resource takes an unqualified resource and returns a Group qualified GroupResource +func Resource(resource string) schema.GroupResource { + return SchemeGroupVersion.WithResource(resource).GroupResource() +} + +var ( + SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes) + AddToScheme = SchemeBuilder.AddToScheme +) + +// Adds the list of known types to Scheme. +func addKnownTypes(scheme *runtime.Scheme) error { + scheme.AddKnownTypes(SchemeGroupVersion, + &Broker{}, + &BrokerList{}, + &Trigger{}, + &TriggerList{}, + ) + metav1.AddToGroupVersion(scheme, SchemeGroupVersion) + return nil +} diff --git a/vendor/knative.dev/eventing/pkg/apis/eventing/v1/test_helper.go b/vendor/knative.dev/eventing/pkg/apis/eventing/v1/test_helper.go new file mode 100644 index 0000000000..64e8d112c7 --- /dev/null +++ b/vendor/knative.dev/eventing/pkg/apis/eventing/v1/test_helper.go @@ -0,0 +1,122 @@ +/* + * Copyright 2020 The Knative Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package v1 + +import ( + corev1 "k8s.io/api/core/v1" + + eventingduckv1 "knative.dev/eventing/pkg/apis/duck/v1" + messagingv1beta1 "knative.dev/eventing/pkg/apis/messaging/v1beta1" + "knative.dev/pkg/apis" + duckv1 "knative.dev/pkg/apis/duck/v1" +) + +type testHelper struct{} + +// TestHelper contains helpers for unit tests. +var TestHelper = testHelper{} + +func (testHelper) ReadySubscriptionCondition() *apis.Condition { + return &apis.Condition{ + Type: apis.ConditionReady, + Status: corev1.ConditionTrue, + Severity: apis.ConditionSeverityError, + } +} + +func (testHelper) FalseSubscriptionCondition() *apis.Condition { + return &apis.Condition{ + Type: apis.ConditionReady, + Status: corev1.ConditionFalse, + Severity: apis.ConditionSeverityError, + Message: "test induced failure condition", + } +} + +func (testHelper) ReadySubscriptionStatus() *messagingv1beta1.SubscriptionStatus { + ss := &messagingv1beta1.SubscriptionStatus{} + ss.MarkChannelReady() + ss.MarkReferencesResolved() + ss.MarkAddedToChannel() + return ss +} + +func (t testHelper) ReadyBrokerStatus() *BrokerStatus { + bs := &BrokerStatus{} + bs.PropagateIngressAvailability(t.AvailableEndpoints()) + bs.PropagateTriggerChannelReadiness(t.ReadyChannelStatus()) + bs.PropagateFilterAvailability(t.AvailableEndpoints()) + bs.SetAddress(apis.HTTP("example.com")) + return bs +} + +func (testHelper) ReadyBrokerCondition() *apis.Condition { + return &apis.Condition{ + Type: apis.ConditionReady, + Status: corev1.ConditionTrue, + Severity: apis.ConditionSeverityError, + } +} + +func (testHelper) UnknownBrokerStatus() *BrokerStatus { + bs := &BrokerStatus{} + return bs +} + +func (testHelper) FalseBrokerStatus() *BrokerStatus { + bs := &BrokerStatus{} + bs.SetAddress(nil) + return bs +} + +func (testHelper) UnavailableEndpoints() *corev1.Endpoints { + ep := &corev1.Endpoints{} + ep.Name = "unavailable" + ep.Subsets = []corev1.EndpointSubset{{ + NotReadyAddresses: []corev1.EndpointAddress{{ + IP: "127.0.0.1", + }}, + }} + return ep +} + +func (testHelper) AvailableEndpoints() *corev1.Endpoints { + ep := &corev1.Endpoints{} + ep.Name = "available" + ep.Subsets = []corev1.EndpointSubset{{ + Addresses: []corev1.EndpointAddress{{ + IP: "127.0.0.1", + }}, + }} + return ep +} + +func (testHelper) ReadyChannelStatus() *eventingduckv1.ChannelableStatus { + cs := &eventingduckv1.ChannelableStatus{ + Status: duckv1.Status{}, + AddressStatus: duckv1.AddressStatus{ + Address: &duckv1.Addressable{ + URL: &apis.URL{Scheme: "http", Host: "foo"}, + }, + }, + SubscribableStatus: eventingduckv1.SubscribableStatus{}} + return cs +} + +func (t testHelper) NotReadyChannelStatus() *eventingduckv1.ChannelableStatus { + return &eventingduckv1.ChannelableStatus{} +} diff --git a/vendor/knative.dev/eventing/pkg/apis/eventing/v1/trigger_conversion.go b/vendor/knative.dev/eventing/pkg/apis/eventing/v1/trigger_conversion.go new file mode 100644 index 0000000000..0df6b92555 --- /dev/null +++ b/vendor/knative.dev/eventing/pkg/apis/eventing/v1/trigger_conversion.go @@ -0,0 +1,34 @@ +/* +Copyright 2020 The Knative Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1 + +import ( + "context" + "fmt" + + "knative.dev/pkg/apis" +) + +// ConvertTo implements apis.Convertible +func (source *Trigger) ConvertTo(ctx context.Context, sink apis.Convertible) error { + return fmt.Errorf("v1 is the highest known version, got: %T", sink) +} + +// ConvertFrom implements apis.Convertible +func (sink *Trigger) ConvertFrom(ctx context.Context, source apis.Convertible) error { + return fmt.Errorf("v1 is the highest known version, got: %T", source) +} diff --git a/vendor/knative.dev/eventing/pkg/apis/eventing/v1/trigger_defaults.go b/vendor/knative.dev/eventing/pkg/apis/eventing/v1/trigger_defaults.go new file mode 100644 index 0000000000..6a2682d70f --- /dev/null +++ b/vendor/knative.dev/eventing/pkg/apis/eventing/v1/trigger_defaults.go @@ -0,0 +1,52 @@ +/* + * Copyright 2020 The Knative Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package v1 + +import ( + "context" + + "knative.dev/pkg/apis" +) + +const ( + brokerLabel = "eventing.knative.dev/broker" +) + +func (t *Trigger) SetDefaults(ctx context.Context) { + withNS := apis.WithinParent(ctx, t.ObjectMeta) + t.Spec.SetDefaults(withNS) + setLabels(t) +} + +func (ts *TriggerSpec) SetDefaults(ctx context.Context) { + if ts.Broker == "" { + ts.Broker = "default" + } + // Make a default filter that allows anything. + if ts.Filter == nil { + ts.Filter = &TriggerFilter{} + } + // Default the Subscriber namespace + ts.Subscriber.SetDefaults(ctx) +} + +func setLabels(t *Trigger) { + if len(t.Labels) == 0 { + t.Labels = map[string]string{} + } + t.Labels[brokerLabel] = t.Spec.Broker +} diff --git a/vendor/knative.dev/eventing/pkg/apis/eventing/v1/trigger_lifecycle.go b/vendor/knative.dev/eventing/pkg/apis/eventing/v1/trigger_lifecycle.go new file mode 100644 index 0000000000..2ad85b219f --- /dev/null +++ b/vendor/knative.dev/eventing/pkg/apis/eventing/v1/trigger_lifecycle.go @@ -0,0 +1,187 @@ +/* + * Copyright 2020 The Knative Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package v1 + +import ( + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/runtime/schema" + "knative.dev/pkg/apis" + duckv1 "knative.dev/pkg/apis/duck/v1" +) + +var triggerCondSet = apis.NewLivingConditionSet(TriggerConditionBroker, TriggerConditionSubscribed, TriggerConditionDependency, TriggerConditionSubscriberResolved) + +const ( + // TriggerConditionReady has status True when all subconditions below have been set to True. + TriggerConditionReady = apis.ConditionReady + + TriggerConditionBroker apis.ConditionType = "BrokerReady" + + TriggerConditionSubscribed apis.ConditionType = "SubscriptionReady" + + TriggerConditionDependency apis.ConditionType = "DependencyReady" + + TriggerConditionSubscriberResolved apis.ConditionType = "SubscriberResolved" + + // TriggerAnyFilter Constant to represent that we should allow anything. + TriggerAnyFilter = "" +) + +// GetConditionSet retrieves the condition set for this resource. Implements the KRShaped interface. +func (*Trigger) GetConditionSet() apis.ConditionSet { + return triggerCondSet +} + +// GetGroupVersionKind returns GroupVersionKind for Triggers +func (t *Trigger) GetGroupVersionKind() schema.GroupVersionKind { + return SchemeGroupVersion.WithKind("Trigger") +} + +// GetUntypedSpec returns the spec of the Trigger. +func (t *Trigger) GetUntypedSpec() interface{} { + return t.Spec +} + +// GetCondition returns the condition currently associated with the given type, or nil. +func (ts *TriggerStatus) GetCondition(t apis.ConditionType) *apis.Condition { + return triggerCondSet.Manage(ts).GetCondition(t) +} + +// GetTopLevelCondition returns the top level Condition. +func (ts *TriggerStatus) GetTopLevelCondition() *apis.Condition { + return triggerCondSet.Manage(ts).GetTopLevelCondition() +} + +// IsReady returns true if the resource is ready overall. +func (ts *TriggerStatus) IsReady() bool { + return triggerCondSet.Manage(ts).IsHappy() +} + +// InitializeConditions sets relevant unset conditions to Unknown state. +func (ts *TriggerStatus) InitializeConditions() { + triggerCondSet.Manage(ts).InitializeConditions() +} + +func (ts *TriggerStatus) PropagateBrokerCondition(bc *apis.Condition) { + if bc == nil { + ts.MarkBrokerNotConfigured() + return + } + + switch { + case bc.Status == corev1.ConditionUnknown: + ts.MarkBrokerUnknown(bc.Reason, bc.Message) + case bc.Status == corev1.ConditionTrue: + triggerCondSet.Manage(ts).MarkTrue(TriggerConditionBroker) + case bc.Status == corev1.ConditionFalse: + ts.MarkBrokerFailed(bc.Reason, bc.Message) + default: + ts.MarkBrokerUnknown("BrokerUnknown", "The status of Broker is invalid: %v", bc.Status) + } +} + +func (ts *TriggerStatus) MarkBrokerFailed(reason, messageFormat string, messageA ...interface{}) { + triggerCondSet.Manage(ts).MarkFalse(TriggerConditionBroker, reason, messageFormat, messageA...) +} + +func (ts *TriggerStatus) MarkBrokerUnknown(reason, messageFormat string, messageA ...interface{}) { + triggerCondSet.Manage(ts).MarkUnknown(TriggerConditionBroker, reason, messageFormat, messageA...) +} + +func (ts *TriggerStatus) MarkBrokerNotConfigured() { + triggerCondSet.Manage(ts).MarkUnknown(TriggerConditionBroker, + "BrokerNotConfigured", "Broker has not yet been reconciled.") +} + +func (ts *TriggerStatus) PropagateSubscriptionCondition(sc *apis.Condition) { + if sc == nil { + ts.MarkSubscriptionNotConfigured() + return + } + + switch { + case sc.Status == corev1.ConditionUnknown: + ts.MarkSubscribedUnknown(sc.Reason, sc.Message) + case sc.Status == corev1.ConditionTrue: + triggerCondSet.Manage(ts).MarkTrue(TriggerConditionSubscribed) + case sc.Status == corev1.ConditionFalse: + ts.MarkNotSubscribed(sc.Reason, sc.Message) + default: + ts.MarkSubscribedUnknown("SubscriptionUnknown", "The status of Subscription is invalid: %v", sc.Status) + } +} + +func (ts *TriggerStatus) MarkNotSubscribed(reason, messageFormat string, messageA ...interface{}) { + triggerCondSet.Manage(ts).MarkFalse(TriggerConditionSubscribed, reason, messageFormat, messageA...) +} + +func (ts *TriggerStatus) MarkSubscribedUnknown(reason, messageFormat string, messageA ...interface{}) { + triggerCondSet.Manage(ts).MarkUnknown(TriggerConditionSubscribed, reason, messageFormat, messageA...) +} + +func (ts *TriggerStatus) MarkSubscriptionNotConfigured() { + triggerCondSet.Manage(ts).MarkUnknown(TriggerConditionSubscribed, + "SubscriptionNotConfigured", "Subscription has not yet been reconciled.") +} + +func (ts *TriggerStatus) MarkSubscriberResolvedSucceeded() { + triggerCondSet.Manage(ts).MarkTrue(TriggerConditionSubscriberResolved) +} + +func (ts *TriggerStatus) MarkSubscriberResolvedFailed(reason, messageFormat string, messageA ...interface{}) { + triggerCondSet.Manage(ts).MarkFalse(TriggerConditionSubscriberResolved, reason, messageFormat, messageA...) +} + +func (ts *TriggerStatus) MarkSubscriberResolvedUnknown(reason, messageFormat string, messageA ...interface{}) { + triggerCondSet.Manage(ts).MarkUnknown(TriggerConditionSubscriberResolved, reason, messageFormat, messageA...) +} + +func (ts *TriggerStatus) MarkDependencySucceeded() { + triggerCondSet.Manage(ts).MarkTrue(TriggerConditionDependency) +} + +func (ts *TriggerStatus) MarkDependencyFailed(reason, messageFormat string, messageA ...interface{}) { + triggerCondSet.Manage(ts).MarkFalse(TriggerConditionDependency, reason, messageFormat, messageA...) +} + +func (ts *TriggerStatus) MarkDependencyUnknown(reason, messageFormat string, messageA ...interface{}) { + triggerCondSet.Manage(ts).MarkUnknown(TriggerConditionDependency, reason, messageFormat, messageA...) +} + +func (ts *TriggerStatus) MarkDependencyNotConfigured() { + triggerCondSet.Manage(ts).MarkUnknown(TriggerConditionDependency, + "DependencyNotConfigured", "Dependency has not yet been reconciled.") +} + +func (ts *TriggerStatus) PropagateDependencyStatus(ks *duckv1.KResource) { + kc := ks.Status.GetCondition(apis.ConditionReady) + if kc == nil { + ts.MarkDependencyNotConfigured() + return + } + + switch { + case kc.Status == corev1.ConditionUnknown: + ts.MarkDependencyUnknown(kc.Reason, kc.Message) + case kc.Status == corev1.ConditionTrue: + ts.MarkDependencySucceeded() + case kc.Status == corev1.ConditionFalse: + ts.MarkDependencyFailed(kc.Reason, kc.Message) + default: + ts.MarkDependencyUnknown("DependencyUnknown", "The status of Dependency is invalid: %v", kc.Status) + } +} diff --git a/vendor/knative.dev/eventing/pkg/apis/eventing/v1/trigger_types.go b/vendor/knative.dev/eventing/pkg/apis/eventing/v1/trigger_types.go new file mode 100644 index 0000000000..ae1005ce40 --- /dev/null +++ b/vendor/knative.dev/eventing/pkg/apis/eventing/v1/trigger_types.go @@ -0,0 +1,130 @@ +/* + * Copyright 2020 The Knative Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package v1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "knative.dev/pkg/apis" + duckv1 "knative.dev/pkg/apis/duck/v1" + "knative.dev/pkg/kmeta" +) + +const ( + // DependencyAnnotation is the annotation key used to mark the sources that the Trigger depends on. + // This will be used when the kn client creates a source and trigger pair for the user such that the trigger only receives events produced by the paired source. + DependencyAnnotation = "knative.dev/dependency" + // InjectionAnnotation is the annotation key used to enable knative eventing injection for a namespace and automatically create a default broker. + // This will be used when the client creates a trigger paired with default broker and the default broker doesn't exist in the namespace + InjectionAnnotation = "knative-eventing-injection" +) + +// +genclient +// +genreconciler:krshapedlogic=true +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// Trigger represents a request to have events delivered to a consumer from a +// Broker's event pool. +type Trigger struct { + metav1.TypeMeta `json:",inline"` + // +optional + metav1.ObjectMeta `json:"metadata,omitempty"` + + // Spec defines the desired state of the Trigger. + Spec TriggerSpec `json:"spec,omitempty"` + + // Status represents the current state of the Trigger. This data may be out of + // date. + // +optional + Status TriggerStatus `json:"status,omitempty"` +} + +var ( + // Check that Trigger can be validated, can be defaulted, and has immutable fields. + _ apis.Validatable = (*Trigger)(nil) + _ apis.Defaultable = (*Trigger)(nil) + + // Check that Trigger can return its spec untyped. + _ apis.HasSpec = (*Trigger)(nil) + + _ runtime.Object = (*Trigger)(nil) + + // Check that we can create OwnerReferences to a Trigger. + _ kmeta.OwnerRefable = (*Trigger)(nil) + + // Check that the type conforms to the duck Knative Resource shape. + _ duckv1.KRShaped = (*Trigger)(nil) +) + +type TriggerSpec struct { + // Broker is the broker that this trigger receives events from. If not specified, will default + // to 'default'. + Broker string `json:"broker,omitempty"` + + // Filter is the filter to apply against all events from the Broker. Only events that pass this + // filter will be sent to the Subscriber. If not specified, will default to allowing all events. + // + // +optional + Filter *TriggerFilter `json:"filter,omitempty"` + + // Subscriber is the addressable that receives events from the Broker that pass the Filter. It + // is required. + Subscriber duckv1.Destination `json:"subscriber"` +} + +type TriggerFilter struct { + // Attributes filters events by exact match on event context attributes. + // Each key in the map is compared with the equivalent key in the event + // context. An event passes the filter if all values are equal to the + // specified values. + // + // Nested context attributes are not supported as keys. Only string values are supported. + // + // +optional + Attributes TriggerFilterAttributes `json:"attributes,omitempty"` +} + +// TriggerFilterAttributes is a map of context attribute names to values for +// filtering by equality. Only exact matches will pass the filter. You can use the value '' +// to indicate all strings match. +type TriggerFilterAttributes map[string]string + +// TriggerStatus represents the current state of a Trigger. +type TriggerStatus struct { + // inherits duck/v1 Status, which currently provides: + // * ObservedGeneration - the 'Generation' of the Trigger that was last processed by the controller. + // * Conditions - the latest available observations of a resource's current state. + duckv1.Status `json:",inline"` + + // SubscriberURI is the resolved URI of the receiver for this Trigger. + SubscriberURI *apis.URL `json:"subscriberUri,omitempty"` +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// TriggerList is a collection of Triggers. +type TriggerList struct { + metav1.TypeMeta `json:",inline"` + // +optional + metav1.ListMeta `json:"metadata,omitempty"` + Items []Trigger `json:"items"` +} + +// GetStatus retrieves the status of the Trigger. Implements the KRShaped interface. +func (t *Trigger) GetStatus() *duckv1.Status { + return &t.Status.Status +} diff --git a/vendor/knative.dev/eventing/pkg/apis/eventing/v1/trigger_validation.go b/vendor/knative.dev/eventing/pkg/apis/eventing/v1/trigger_validation.go new file mode 100644 index 0000000000..8a18a89e18 --- /dev/null +++ b/vendor/knative.dev/eventing/pkg/apis/eventing/v1/trigger_validation.go @@ -0,0 +1,155 @@ +/* + * Copyright 2020 The Knative Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package v1 + +import ( + "context" + "encoding/json" + "fmt" + "regexp" + + "knative.dev/pkg/apis" + "knative.dev/pkg/kmp" + + corev1 "k8s.io/api/core/v1" +) + +var ( + // Only allow lowercase alphanumeric, starting with letters. + validAttributeName = regexp.MustCompile(`^[a-z][a-z0-9]*$`) +) + +// Validate the Trigger. +func (t *Trigger) Validate(ctx context.Context) *apis.FieldError { + errs := t.Spec.Validate(ctx).ViaField("spec") + errs = t.validateAnnotation(errs, DependencyAnnotation, t.validateDependencyAnnotation) + errs = t.validateAnnotation(errs, InjectionAnnotation, t.validateInjectionAnnotation) + return errs +} + +// Validate the TriggerSpec. +func (ts *TriggerSpec) Validate(ctx context.Context) *apis.FieldError { + var errs *apis.FieldError + if ts.Broker == "" { + fe := apis.ErrMissingField("broker") + errs = errs.Also(fe) + } + + if ts.Filter != nil { + for attr := range map[string]string(ts.Filter.Attributes) { + if !validAttributeName.MatchString(attr) { + fe := &apis.FieldError{ + Message: fmt.Sprintf("Invalid attribute name: %q", attr), + Paths: []string{"filter.attributes"}, + } + errs = errs.Also(fe) + } + } + } + + if fe := ts.Subscriber.Validate(ctx); fe != nil { + errs = errs.Also(fe.ViaField("subscriber")) + } + + return errs +} + +// CheckImmutableFields checks that any immutable fields were not changed. +func (t *Trigger) CheckImmutableFields(ctx context.Context, original *Trigger) *apis.FieldError { + if original == nil { + return nil + } + + if diff, err := kmp.ShortDiff(original.Spec.Broker, t.Spec.Broker); err != nil { + return &apis.FieldError{ + Message: "Failed to diff Trigger", + Paths: []string{"spec"}, + Details: err.Error(), + } + } else if diff != "" { + return &apis.FieldError{ + Message: "Immutable fields changed (-old +new)", + Paths: []string{"spec", "broker"}, + Details: diff, + } + } + return nil +} + +func GetObjRefFromDependencyAnnotation(dependencyAnnotation string) (corev1.ObjectReference, error) { + var objectRef corev1.ObjectReference + if err := json.Unmarshal([]byte(dependencyAnnotation), &objectRef); err != nil { + return objectRef, err + } + return objectRef, nil +} + +func (t *Trigger) validateAnnotation(errs *apis.FieldError, annotation string, function func(string) *apis.FieldError) *apis.FieldError { + if annotationValue, ok := t.GetAnnotations()[annotation]; ok { + annotationPrefix := fmt.Sprintf("metadata.annotations[%s]", annotation) + errs = errs.Also(function(annotationValue).ViaField(annotationPrefix)) + } + return errs +} + +func (t *Trigger) validateDependencyAnnotation(dependencyAnnotation string) *apis.FieldError { + depObjRef, err := GetObjRefFromDependencyAnnotation(dependencyAnnotation) + if err != nil { + return &apis.FieldError{ + Message: fmt.Sprintf("The provided annotation was not a corev1.ObjectReference: %q", dependencyAnnotation), + Details: err.Error(), + Paths: []string{""}, + } + } + var errs *apis.FieldError + if depObjRef.Namespace != "" && depObjRef.Namespace != t.GetNamespace() { + fe := &apis.FieldError{ + Message: fmt.Sprintf("Namespace must be empty or equal to the trigger namespace %q", t.GetNamespace()), + Paths: []string{"namespace"}, + } + errs = errs.Also(fe) + } + if depObjRef.Kind == "" { + fe := apis.ErrMissingField("kind") + errs = errs.Also(fe) + } + if depObjRef.Name == "" { + fe := apis.ErrMissingField("name") + errs = errs.Also(fe) + } + if depObjRef.APIVersion == "" { + fe := apis.ErrMissingField("apiVersion") + errs = errs.Also(fe) + } + return errs +} + +func (t *Trigger) validateInjectionAnnotation(injectionAnnotation string) *apis.FieldError { + if injectionAnnotation != "enabled" { + return &apis.FieldError{ + Message: fmt.Sprintf(`The provided injection annotation value can only be "enabled", not %q`, injectionAnnotation), + Paths: []string{""}, + } + } + if t.Spec.Broker != "default" { + return &apis.FieldError{ + Message: fmt.Sprintf("The provided injection annotation is only used for default broker, but non-default broker specified here: %q", t.Spec.Broker), + Paths: []string{""}, + } + } + return nil +} diff --git a/vendor/knative.dev/eventing/pkg/apis/eventing/v1/zz_generated.deepcopy.go b/vendor/knative.dev/eventing/pkg/apis/eventing/v1/zz_generated.deepcopy.go new file mode 100644 index 0000000000..41b8f75e6d --- /dev/null +++ b/vendor/knative.dev/eventing/pkg/apis/eventing/v1/zz_generated.deepcopy.go @@ -0,0 +1,283 @@ +// +build !ignore_autogenerated + +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by deepcopy-gen. DO NOT EDIT. + +package v1 + +import ( + runtime "k8s.io/apimachinery/pkg/runtime" + apisduckv1 "knative.dev/eventing/pkg/apis/duck/v1" + apis "knative.dev/pkg/apis" + duckv1 "knative.dev/pkg/apis/duck/v1" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Broker) DeepCopyInto(out *Broker) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Broker. +func (in *Broker) DeepCopy() *Broker { + if in == nil { + return nil + } + out := new(Broker) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *Broker) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *BrokerList) DeepCopyInto(out *BrokerList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]Broker, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BrokerList. +func (in *BrokerList) DeepCopy() *BrokerList { + if in == nil { + return nil + } + out := new(BrokerList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *BrokerList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *BrokerSpec) DeepCopyInto(out *BrokerSpec) { + *out = *in + if in.Config != nil { + in, out := &in.Config, &out.Config + *out = new(duckv1.KReference) + **out = **in + } + if in.Delivery != nil { + in, out := &in.Delivery, &out.Delivery + *out = new(apisduckv1.DeliverySpec) + (*in).DeepCopyInto(*out) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BrokerSpec. +func (in *BrokerSpec) DeepCopy() *BrokerSpec { + if in == nil { + return nil + } + out := new(BrokerSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *BrokerStatus) DeepCopyInto(out *BrokerStatus) { + *out = *in + in.Status.DeepCopyInto(&out.Status) + in.Address.DeepCopyInto(&out.Address) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BrokerStatus. +func (in *BrokerStatus) DeepCopy() *BrokerStatus { + if in == nil { + return nil + } + out := new(BrokerStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Trigger) DeepCopyInto(out *Trigger) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Trigger. +func (in *Trigger) DeepCopy() *Trigger { + if in == nil { + return nil + } + out := new(Trigger) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *Trigger) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TriggerFilter) DeepCopyInto(out *TriggerFilter) { + *out = *in + if in.Attributes != nil { + in, out := &in.Attributes, &out.Attributes + *out = make(TriggerFilterAttributes, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TriggerFilter. +func (in *TriggerFilter) DeepCopy() *TriggerFilter { + if in == nil { + return nil + } + out := new(TriggerFilter) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in TriggerFilterAttributes) DeepCopyInto(out *TriggerFilterAttributes) { + { + in := &in + *out = make(TriggerFilterAttributes, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + return + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TriggerFilterAttributes. +func (in TriggerFilterAttributes) DeepCopy() TriggerFilterAttributes { + if in == nil { + return nil + } + out := new(TriggerFilterAttributes) + in.DeepCopyInto(out) + return *out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TriggerList) DeepCopyInto(out *TriggerList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]Trigger, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TriggerList. +func (in *TriggerList) DeepCopy() *TriggerList { + if in == nil { + return nil + } + out := new(TriggerList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *TriggerList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TriggerSpec) DeepCopyInto(out *TriggerSpec) { + *out = *in + if in.Filter != nil { + in, out := &in.Filter, &out.Filter + *out = new(TriggerFilter) + (*in).DeepCopyInto(*out) + } + in.Subscriber.DeepCopyInto(&out.Subscriber) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TriggerSpec. +func (in *TriggerSpec) DeepCopy() *TriggerSpec { + if in == nil { + return nil + } + out := new(TriggerSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TriggerStatus) DeepCopyInto(out *TriggerStatus) { + *out = *in + in.Status.DeepCopyInto(&out.Status) + if in.SubscriberURI != nil { + in, out := &in.SubscriberURI, &out.SubscriberURI + *out = new(apis.URL) + (*in).DeepCopyInto(*out) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TriggerStatus. +func (in *TriggerStatus) DeepCopy() *TriggerStatus { + if in == nil { + return nil + } + out := new(TriggerStatus) + in.DeepCopyInto(out) + return out +} diff --git a/vendor/knative.dev/eventing/pkg/apis/eventing/v1beta1/broker_conversion.go b/vendor/knative.dev/eventing/pkg/apis/eventing/v1beta1/broker_conversion.go index f0c61ca95c..8f1cd7c9e6 100644 --- a/vendor/knative.dev/eventing/pkg/apis/eventing/v1beta1/broker_conversion.go +++ b/vendor/knative.dev/eventing/pkg/apis/eventing/v1beta1/broker_conversion.go @@ -20,15 +20,38 @@ import ( "context" "fmt" + v1 "knative.dev/eventing/pkg/apis/eventing/v1" "knative.dev/pkg/apis" ) // ConvertTo implements apis.Convertible -func (source *Broker) ConvertTo(ctx context.Context, sink apis.Convertible) error { - return fmt.Errorf("v1beta1 is the highest known version, got: %T", sink) +func (source *Broker) ConvertTo(ctx context.Context, to apis.Convertible) error { + switch sink := to.(type) { + case *v1.Broker: + sink.Spec.Config = source.Spec.Config + if err := source.Spec.Delivery.ConvertTo(ctx, sink.Spec.Delivery); err != nil { + return err + } + sink.Status.Status = source.Status.Status + sink.Status.Address = source.Status.Address + return nil + default: + return fmt.Errorf("unknown version, got: %T", sink) + } } // ConvertFrom implements apis.Convertible -func (sink *Broker) ConvertFrom(ctx context.Context, source apis.Convertible) error { - return fmt.Errorf("v1beta1 is the highest known version, got: %T", source) +func (sink *Broker) ConvertFrom(ctx context.Context, from apis.Convertible) error { + switch source := from.(type) { + case *v1.Broker: + sink.Spec.Config = source.Spec.Config + if err := source.Spec.Delivery.ConvertFrom(ctx, sink.Spec.Delivery); err != nil { + return err + } + sink.Status.Status = source.Status.Status + sink.Status.Address = source.Status.Address + return nil + default: + return fmt.Errorf("unknown version, got: %T", source) + } } diff --git a/vendor/knative.dev/eventing/pkg/apis/eventing/v1beta1/eventtype_conversion.go b/vendor/knative.dev/eventing/pkg/apis/eventing/v1beta1/eventtype_conversion.go index 6ef342c873..011a013eea 100644 --- a/vendor/knative.dev/eventing/pkg/apis/eventing/v1beta1/eventtype_conversion.go +++ b/vendor/knative.dev/eventing/pkg/apis/eventing/v1beta1/eventtype_conversion.go @@ -24,11 +24,11 @@ import ( ) // ConvertTo implements apis.Convertible -func (source *EventType) ConvertTo(ctx context.Context, sink apis.Convertible) error { - return fmt.Errorf("v1beta1 is the highest known version, got: %T", sink) +func (source *EventType) ConvertTo(ctx context.Context, to apis.Convertible) error { + return fmt.Errorf("v1beta1 is the highest known version, got: %T", to) } // ConvertFrom implements apis.Convertible -func (sink *EventType) ConvertFrom(ctx context.Context, source apis.Convertible) error { - return fmt.Errorf("v1beta1 is the highest known version, got: %T", source) +func (sink *EventType) ConvertFrom(ctx context.Context, from apis.Convertible) error { + return fmt.Errorf("v1beta1 is the highest known version, got: %T", from) } diff --git a/vendor/knative.dev/eventing/pkg/apis/eventing/v1beta1/trigger_conversion.go b/vendor/knative.dev/eventing/pkg/apis/eventing/v1beta1/trigger_conversion.go index dc96d461d1..455b492926 100644 --- a/vendor/knative.dev/eventing/pkg/apis/eventing/v1beta1/trigger_conversion.go +++ b/vendor/knative.dev/eventing/pkg/apis/eventing/v1beta1/trigger_conversion.go @@ -20,15 +20,46 @@ import ( "context" "fmt" + v1 "knative.dev/eventing/pkg/apis/eventing/v1" "knative.dev/pkg/apis" ) // ConvertTo implements apis.Convertible -func (source *Trigger) ConvertTo(ctx context.Context, sink apis.Convertible) error { - return fmt.Errorf("v1beta1 is the highest known version, got: %T", sink) +func (source *Trigger) ConvertTo(ctx context.Context, to apis.Convertible) error { + switch sink := to.(type) { + case *v1.Trigger: + sink.Spec.Broker = source.Spec.Broker + sink.Spec.Subscriber = source.Spec.Subscriber + if source.Spec.Filter != nil { + sink.Spec.Filter = &v1.TriggerFilter{} + } + for k, v := range source.Spec.Filter.Attributes { + sink.Spec.Filter.Attributes[k] = v + } + sink.Status.Status = source.Status.Status + sink.Status.SubscriberURI = source.Status.SubscriberURI + return nil + default: + return fmt.Errorf("unknown version, got: %T", sink) + } } // ConvertFrom implements apis.Convertible -func (sink *Trigger) ConvertFrom(ctx context.Context, source apis.Convertible) error { - return fmt.Errorf("v1beta1 is the highest known version, got: %T", source) +func (sink *Trigger) ConvertFrom(ctx context.Context, from apis.Convertible) error { + switch source := from.(type) { + case *v1.Trigger: + sink.Spec.Broker = source.Spec.Broker + sink.Spec.Subscriber = source.Spec.Subscriber + if source.Spec.Filter != nil { + sink.Spec.Filter = &TriggerFilter{} + } + for k, v := range source.Spec.Filter.Attributes { + sink.Spec.Filter.Attributes[k] = v + } + sink.Status.Status = source.Status.Status + sink.Status.SubscriberURI = source.Status.SubscriberURI + return nil + default: + return fmt.Errorf("unknown version, got: %T", source) + } } diff --git a/vendor/knative.dev/eventing/pkg/client/clientset/versioned/clientset.go b/vendor/knative.dev/eventing/pkg/client/clientset/versioned/clientset.go index 7b5f994fcd..21897073e1 100644 --- a/vendor/knative.dev/eventing/pkg/client/clientset/versioned/clientset.go +++ b/vendor/knative.dev/eventing/pkg/client/clientset/versioned/clientset.go @@ -25,6 +25,7 @@ import ( rest "k8s.io/client-go/rest" flowcontrol "k8s.io/client-go/util/flowcontrol" configsv1alpha1 "knative.dev/eventing/pkg/client/clientset/versioned/typed/configs/v1alpha1" + eventingv1 "knative.dev/eventing/pkg/client/clientset/versioned/typed/eventing/v1" eventingv1beta1 "knative.dev/eventing/pkg/client/clientset/versioned/typed/eventing/v1beta1" flowsv1beta1 "knative.dev/eventing/pkg/client/clientset/versioned/typed/flows/v1beta1" messagingv1beta1 "knative.dev/eventing/pkg/client/clientset/versioned/typed/messaging/v1beta1" @@ -36,6 +37,7 @@ type Interface interface { Discovery() discovery.DiscoveryInterface ConfigsV1alpha1() configsv1alpha1.ConfigsV1alpha1Interface EventingV1beta1() eventingv1beta1.EventingV1beta1Interface + EventingV1() eventingv1.EventingV1Interface FlowsV1beta1() flowsv1beta1.FlowsV1beta1Interface MessagingV1beta1() messagingv1beta1.MessagingV1beta1Interface SourcesV1alpha1() sourcesv1alpha1.SourcesV1alpha1Interface @@ -48,6 +50,7 @@ type Clientset struct { *discovery.DiscoveryClient configsV1alpha1 *configsv1alpha1.ConfigsV1alpha1Client eventingV1beta1 *eventingv1beta1.EventingV1beta1Client + eventingV1 *eventingv1.EventingV1Client flowsV1beta1 *flowsv1beta1.FlowsV1beta1Client messagingV1beta1 *messagingv1beta1.MessagingV1beta1Client sourcesV1alpha1 *sourcesv1alpha1.SourcesV1alpha1Client @@ -64,6 +67,11 @@ func (c *Clientset) EventingV1beta1() eventingv1beta1.EventingV1beta1Interface { return c.eventingV1beta1 } +// EventingV1 retrieves the EventingV1Client +func (c *Clientset) EventingV1() eventingv1.EventingV1Interface { + return c.eventingV1 +} + // FlowsV1beta1 retrieves the FlowsV1beta1Client func (c *Clientset) FlowsV1beta1() flowsv1beta1.FlowsV1beta1Interface { return c.flowsV1beta1 @@ -113,6 +121,10 @@ func NewForConfig(c *rest.Config) (*Clientset, error) { if err != nil { return nil, err } + cs.eventingV1, err = eventingv1.NewForConfig(&configShallowCopy) + if err != nil { + return nil, err + } cs.flowsV1beta1, err = flowsv1beta1.NewForConfig(&configShallowCopy) if err != nil { return nil, err @@ -143,6 +155,7 @@ func NewForConfigOrDie(c *rest.Config) *Clientset { var cs Clientset cs.configsV1alpha1 = configsv1alpha1.NewForConfigOrDie(c) cs.eventingV1beta1 = eventingv1beta1.NewForConfigOrDie(c) + cs.eventingV1 = eventingv1.NewForConfigOrDie(c) cs.flowsV1beta1 = flowsv1beta1.NewForConfigOrDie(c) cs.messagingV1beta1 = messagingv1beta1.NewForConfigOrDie(c) cs.sourcesV1alpha1 = sourcesv1alpha1.NewForConfigOrDie(c) @@ -157,6 +170,7 @@ func New(c rest.Interface) *Clientset { var cs Clientset cs.configsV1alpha1 = configsv1alpha1.New(c) cs.eventingV1beta1 = eventingv1beta1.New(c) + cs.eventingV1 = eventingv1.New(c) cs.flowsV1beta1 = flowsv1beta1.New(c) cs.messagingV1beta1 = messagingv1beta1.New(c) cs.sourcesV1alpha1 = sourcesv1alpha1.New(c) diff --git a/vendor/knative.dev/eventing/pkg/client/clientset/versioned/fake/clientset_generated.go b/vendor/knative.dev/eventing/pkg/client/clientset/versioned/fake/clientset_generated.go index 5f55ecc909..a3c066cafe 100644 --- a/vendor/knative.dev/eventing/pkg/client/clientset/versioned/fake/clientset_generated.go +++ b/vendor/knative.dev/eventing/pkg/client/clientset/versioned/fake/clientset_generated.go @@ -27,6 +27,8 @@ import ( clientset "knative.dev/eventing/pkg/client/clientset/versioned" configsv1alpha1 "knative.dev/eventing/pkg/client/clientset/versioned/typed/configs/v1alpha1" fakeconfigsv1alpha1 "knative.dev/eventing/pkg/client/clientset/versioned/typed/configs/v1alpha1/fake" + eventingv1 "knative.dev/eventing/pkg/client/clientset/versioned/typed/eventing/v1" + fakeeventingv1 "knative.dev/eventing/pkg/client/clientset/versioned/typed/eventing/v1/fake" eventingv1beta1 "knative.dev/eventing/pkg/client/clientset/versioned/typed/eventing/v1beta1" fakeeventingv1beta1 "knative.dev/eventing/pkg/client/clientset/versioned/typed/eventing/v1beta1/fake" flowsv1beta1 "knative.dev/eventing/pkg/client/clientset/versioned/typed/flows/v1beta1" @@ -96,6 +98,11 @@ func (c *Clientset) EventingV1beta1() eventingv1beta1.EventingV1beta1Interface { return &fakeeventingv1beta1.FakeEventingV1beta1{Fake: &c.Fake} } +// EventingV1 retrieves the EventingV1Client +func (c *Clientset) EventingV1() eventingv1.EventingV1Interface { + return &fakeeventingv1.FakeEventingV1{Fake: &c.Fake} +} + // FlowsV1beta1 retrieves the FlowsV1beta1Client func (c *Clientset) FlowsV1beta1() flowsv1beta1.FlowsV1beta1Interface { return &fakeflowsv1beta1.FakeFlowsV1beta1{Fake: &c.Fake} diff --git a/vendor/knative.dev/eventing/pkg/client/clientset/versioned/fake/register.go b/vendor/knative.dev/eventing/pkg/client/clientset/versioned/fake/register.go index 6b46a004e4..d767c43548 100644 --- a/vendor/knative.dev/eventing/pkg/client/clientset/versioned/fake/register.go +++ b/vendor/knative.dev/eventing/pkg/client/clientset/versioned/fake/register.go @@ -25,6 +25,7 @@ import ( serializer "k8s.io/apimachinery/pkg/runtime/serializer" utilruntime "k8s.io/apimachinery/pkg/util/runtime" configsv1alpha1 "knative.dev/eventing/pkg/apis/configs/v1alpha1" + eventingv1 "knative.dev/eventing/pkg/apis/eventing/v1" eventingv1beta1 "knative.dev/eventing/pkg/apis/eventing/v1beta1" flowsv1beta1 "knative.dev/eventing/pkg/apis/flows/v1beta1" messagingv1beta1 "knative.dev/eventing/pkg/apis/messaging/v1beta1" @@ -38,6 +39,7 @@ var parameterCodec = runtime.NewParameterCodec(scheme) var localSchemeBuilder = runtime.SchemeBuilder{ configsv1alpha1.AddToScheme, eventingv1beta1.AddToScheme, + eventingv1.AddToScheme, flowsv1beta1.AddToScheme, messagingv1beta1.AddToScheme, sourcesv1alpha1.AddToScheme, diff --git a/vendor/knative.dev/eventing/pkg/client/clientset/versioned/scheme/register.go b/vendor/knative.dev/eventing/pkg/client/clientset/versioned/scheme/register.go index 76c104bc5b..a6cb9e4ac2 100644 --- a/vendor/knative.dev/eventing/pkg/client/clientset/versioned/scheme/register.go +++ b/vendor/knative.dev/eventing/pkg/client/clientset/versioned/scheme/register.go @@ -25,6 +25,7 @@ import ( serializer "k8s.io/apimachinery/pkg/runtime/serializer" utilruntime "k8s.io/apimachinery/pkg/util/runtime" configsv1alpha1 "knative.dev/eventing/pkg/apis/configs/v1alpha1" + eventingv1 "knative.dev/eventing/pkg/apis/eventing/v1" eventingv1beta1 "knative.dev/eventing/pkg/apis/eventing/v1beta1" flowsv1beta1 "knative.dev/eventing/pkg/apis/flows/v1beta1" messagingv1beta1 "knative.dev/eventing/pkg/apis/messaging/v1beta1" @@ -38,6 +39,7 @@ var ParameterCodec = runtime.NewParameterCodec(Scheme) var localSchemeBuilder = runtime.SchemeBuilder{ configsv1alpha1.AddToScheme, eventingv1beta1.AddToScheme, + eventingv1.AddToScheme, flowsv1beta1.AddToScheme, messagingv1beta1.AddToScheme, sourcesv1alpha1.AddToScheme, diff --git a/vendor/knative.dev/eventing/pkg/client/clientset/versioned/typed/eventing/v1/broker.go b/vendor/knative.dev/eventing/pkg/client/clientset/versioned/typed/eventing/v1/broker.go new file mode 100644 index 0000000000..f7309d95a9 --- /dev/null +++ b/vendor/knative.dev/eventing/pkg/client/clientset/versioned/typed/eventing/v1/broker.go @@ -0,0 +1,191 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package v1 + +import ( + "time" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + rest "k8s.io/client-go/rest" + v1 "knative.dev/eventing/pkg/apis/eventing/v1" + scheme "knative.dev/eventing/pkg/client/clientset/versioned/scheme" +) + +// BrokersGetter has a method to return a BrokerInterface. +// A group's client should implement this interface. +type BrokersGetter interface { + Brokers(namespace string) BrokerInterface +} + +// BrokerInterface has methods to work with Broker resources. +type BrokerInterface interface { + Create(*v1.Broker) (*v1.Broker, error) + Update(*v1.Broker) (*v1.Broker, error) + UpdateStatus(*v1.Broker) (*v1.Broker, error) + Delete(name string, options *metav1.DeleteOptions) error + DeleteCollection(options *metav1.DeleteOptions, listOptions metav1.ListOptions) error + Get(name string, options metav1.GetOptions) (*v1.Broker, error) + List(opts metav1.ListOptions) (*v1.BrokerList, error) + Watch(opts metav1.ListOptions) (watch.Interface, error) + Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1.Broker, err error) + BrokerExpansion +} + +// brokers implements BrokerInterface +type brokers struct { + client rest.Interface + ns string +} + +// newBrokers returns a Brokers +func newBrokers(c *EventingV1Client, namespace string) *brokers { + return &brokers{ + client: c.RESTClient(), + ns: namespace, + } +} + +// Get takes name of the broker, and returns the corresponding broker object, and an error if there is any. +func (c *brokers) Get(name string, options metav1.GetOptions) (result *v1.Broker, err error) { + result = &v1.Broker{} + err = c.client.Get(). + Namespace(c.ns). + Resource("brokers"). + Name(name). + VersionedParams(&options, scheme.ParameterCodec). + Do(). + Into(result) + return +} + +// List takes label and field selectors, and returns the list of Brokers that match those selectors. +func (c *brokers) List(opts metav1.ListOptions) (result *v1.BrokerList, err error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + result = &v1.BrokerList{} + err = c.client.Get(). + Namespace(c.ns). + Resource("brokers"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Do(). + Into(result) + return +} + +// Watch returns a watch.Interface that watches the requested brokers. +func (c *brokers) Watch(opts metav1.ListOptions) (watch.Interface, error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + opts.Watch = true + return c.client.Get(). + Namespace(c.ns). + Resource("brokers"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Watch() +} + +// Create takes the representation of a broker and creates it. Returns the server's representation of the broker, and an error, if there is any. +func (c *brokers) Create(broker *v1.Broker) (result *v1.Broker, err error) { + result = &v1.Broker{} + err = c.client.Post(). + Namespace(c.ns). + Resource("brokers"). + Body(broker). + Do(). + Into(result) + return +} + +// Update takes the representation of a broker and updates it. Returns the server's representation of the broker, and an error, if there is any. +func (c *brokers) Update(broker *v1.Broker) (result *v1.Broker, err error) { + result = &v1.Broker{} + err = c.client.Put(). + Namespace(c.ns). + Resource("brokers"). + Name(broker.Name). + Body(broker). + Do(). + Into(result) + return +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). + +func (c *brokers) UpdateStatus(broker *v1.Broker) (result *v1.Broker, err error) { + result = &v1.Broker{} + err = c.client.Put(). + Namespace(c.ns). + Resource("brokers"). + Name(broker.Name). + SubResource("status"). + Body(broker). + Do(). + Into(result) + return +} + +// Delete takes name of the broker and deletes it. Returns an error if one occurs. +func (c *brokers) Delete(name string, options *metav1.DeleteOptions) error { + return c.client.Delete(). + Namespace(c.ns). + Resource("brokers"). + Name(name). + Body(options). + Do(). + Error() +} + +// DeleteCollection deletes a collection of objects. +func (c *brokers) DeleteCollection(options *metav1.DeleteOptions, listOptions metav1.ListOptions) error { + var timeout time.Duration + if listOptions.TimeoutSeconds != nil { + timeout = time.Duration(*listOptions.TimeoutSeconds) * time.Second + } + return c.client.Delete(). + Namespace(c.ns). + Resource("brokers"). + VersionedParams(&listOptions, scheme.ParameterCodec). + Timeout(timeout). + Body(options). + Do(). + Error() +} + +// Patch applies the patch and returns the patched broker. +func (c *brokers) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1.Broker, err error) { + result = &v1.Broker{} + err = c.client.Patch(pt). + Namespace(c.ns). + Resource("brokers"). + SubResource(subresources...). + Name(name). + Body(data). + Do(). + Into(result) + return +} diff --git a/vendor/knative.dev/eventing/pkg/client/clientset/versioned/typed/eventing/v1/doc.go b/vendor/knative.dev/eventing/pkg/client/clientset/versioned/typed/eventing/v1/doc.go new file mode 100644 index 0000000000..5b83bd1f41 --- /dev/null +++ b/vendor/knative.dev/eventing/pkg/client/clientset/versioned/typed/eventing/v1/doc.go @@ -0,0 +1,20 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +// This package has the automatically generated typed clients. +package v1 diff --git a/vendor/knative.dev/eventing/pkg/client/clientset/versioned/typed/eventing/v1/eventing_client.go b/vendor/knative.dev/eventing/pkg/client/clientset/versioned/typed/eventing/v1/eventing_client.go new file mode 100644 index 0000000000..c777463401 --- /dev/null +++ b/vendor/knative.dev/eventing/pkg/client/clientset/versioned/typed/eventing/v1/eventing_client.go @@ -0,0 +1,94 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package v1 + +import ( + rest "k8s.io/client-go/rest" + v1 "knative.dev/eventing/pkg/apis/eventing/v1" + "knative.dev/eventing/pkg/client/clientset/versioned/scheme" +) + +type EventingV1Interface interface { + RESTClient() rest.Interface + BrokersGetter + TriggersGetter +} + +// EventingV1Client is used to interact with features provided by the eventing.knative.dev group. +type EventingV1Client struct { + restClient rest.Interface +} + +func (c *EventingV1Client) Brokers(namespace string) BrokerInterface { + return newBrokers(c, namespace) +} + +func (c *EventingV1Client) Triggers(namespace string) TriggerInterface { + return newTriggers(c, namespace) +} + +// NewForConfig creates a new EventingV1Client for the given config. +func NewForConfig(c *rest.Config) (*EventingV1Client, error) { + config := *c + if err := setConfigDefaults(&config); err != nil { + return nil, err + } + client, err := rest.RESTClientFor(&config) + if err != nil { + return nil, err + } + return &EventingV1Client{client}, nil +} + +// NewForConfigOrDie creates a new EventingV1Client for the given config and +// panics if there is an error in the config. +func NewForConfigOrDie(c *rest.Config) *EventingV1Client { + client, err := NewForConfig(c) + if err != nil { + panic(err) + } + return client +} + +// New creates a new EventingV1Client for the given RESTClient. +func New(c rest.Interface) *EventingV1Client { + return &EventingV1Client{c} +} + +func setConfigDefaults(config *rest.Config) error { + gv := v1.SchemeGroupVersion + config.GroupVersion = &gv + config.APIPath = "/apis" + config.NegotiatedSerializer = scheme.Codecs.WithoutConversion() + + if config.UserAgent == "" { + config.UserAgent = rest.DefaultKubernetesUserAgent() + } + + return nil +} + +// RESTClient returns a RESTClient that is used to communicate +// with API server by this client implementation. +func (c *EventingV1Client) RESTClient() rest.Interface { + if c == nil { + return nil + } + return c.restClient +} diff --git a/vendor/knative.dev/eventing/pkg/client/clientset/versioned/typed/eventing/v1/fake/doc.go b/vendor/knative.dev/eventing/pkg/client/clientset/versioned/typed/eventing/v1/fake/doc.go new file mode 100644 index 0000000000..c7f6e65cab --- /dev/null +++ b/vendor/knative.dev/eventing/pkg/client/clientset/versioned/typed/eventing/v1/fake/doc.go @@ -0,0 +1,20 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +// Package fake has the automatically generated clients. +package fake diff --git a/vendor/knative.dev/eventing/pkg/client/clientset/versioned/typed/eventing/v1/fake/fake_broker.go b/vendor/knative.dev/eventing/pkg/client/clientset/versioned/typed/eventing/v1/fake/fake_broker.go new file mode 100644 index 0000000000..fff607109c --- /dev/null +++ b/vendor/knative.dev/eventing/pkg/client/clientset/versioned/typed/eventing/v1/fake/fake_broker.go @@ -0,0 +1,140 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + testing "k8s.io/client-go/testing" + eventingv1 "knative.dev/eventing/pkg/apis/eventing/v1" +) + +// FakeBrokers implements BrokerInterface +type FakeBrokers struct { + Fake *FakeEventingV1 + ns string +} + +var brokersResource = schema.GroupVersionResource{Group: "eventing.knative.dev", Version: "v1", Resource: "brokers"} + +var brokersKind = schema.GroupVersionKind{Group: "eventing.knative.dev", Version: "v1", Kind: "Broker"} + +// Get takes name of the broker, and returns the corresponding broker object, and an error if there is any. +func (c *FakeBrokers) Get(name string, options v1.GetOptions) (result *eventingv1.Broker, err error) { + obj, err := c.Fake. + Invokes(testing.NewGetAction(brokersResource, c.ns, name), &eventingv1.Broker{}) + + if obj == nil { + return nil, err + } + return obj.(*eventingv1.Broker), err +} + +// List takes label and field selectors, and returns the list of Brokers that match those selectors. +func (c *FakeBrokers) List(opts v1.ListOptions) (result *eventingv1.BrokerList, err error) { + obj, err := c.Fake. + Invokes(testing.NewListAction(brokersResource, brokersKind, c.ns, opts), &eventingv1.BrokerList{}) + + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &eventingv1.BrokerList{ListMeta: obj.(*eventingv1.BrokerList).ListMeta} + for _, item := range obj.(*eventingv1.BrokerList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested brokers. +func (c *FakeBrokers) Watch(opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewWatchAction(brokersResource, c.ns, opts)) + +} + +// Create takes the representation of a broker and creates it. Returns the server's representation of the broker, and an error, if there is any. +func (c *FakeBrokers) Create(broker *eventingv1.Broker) (result *eventingv1.Broker, err error) { + obj, err := c.Fake. + Invokes(testing.NewCreateAction(brokersResource, c.ns, broker), &eventingv1.Broker{}) + + if obj == nil { + return nil, err + } + return obj.(*eventingv1.Broker), err +} + +// Update takes the representation of a broker and updates it. Returns the server's representation of the broker, and an error, if there is any. +func (c *FakeBrokers) Update(broker *eventingv1.Broker) (result *eventingv1.Broker, err error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateAction(brokersResource, c.ns, broker), &eventingv1.Broker{}) + + if obj == nil { + return nil, err + } + return obj.(*eventingv1.Broker), err +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). +func (c *FakeBrokers) UpdateStatus(broker *eventingv1.Broker) (*eventingv1.Broker, error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateSubresourceAction(brokersResource, "status", c.ns, broker), &eventingv1.Broker{}) + + if obj == nil { + return nil, err + } + return obj.(*eventingv1.Broker), err +} + +// Delete takes name of the broker and deletes it. Returns an error if one occurs. +func (c *FakeBrokers) Delete(name string, options *v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewDeleteAction(brokersResource, c.ns, name), &eventingv1.Broker{}) + + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeBrokers) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error { + action := testing.NewDeleteCollectionAction(brokersResource, c.ns, listOptions) + + _, err := c.Fake.Invokes(action, &eventingv1.BrokerList{}) + return err +} + +// Patch applies the patch and returns the patched broker. +func (c *FakeBrokers) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *eventingv1.Broker, err error) { + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(brokersResource, c.ns, name, pt, data, subresources...), &eventingv1.Broker{}) + + if obj == nil { + return nil, err + } + return obj.(*eventingv1.Broker), err +} diff --git a/vendor/knative.dev/eventing/pkg/client/clientset/versioned/typed/eventing/v1/fake/fake_eventing_client.go b/vendor/knative.dev/eventing/pkg/client/clientset/versioned/typed/eventing/v1/fake/fake_eventing_client.go new file mode 100644 index 0000000000..4da4be359c --- /dev/null +++ b/vendor/knative.dev/eventing/pkg/client/clientset/versioned/typed/eventing/v1/fake/fake_eventing_client.go @@ -0,0 +1,44 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + rest "k8s.io/client-go/rest" + testing "k8s.io/client-go/testing" + v1 "knative.dev/eventing/pkg/client/clientset/versioned/typed/eventing/v1" +) + +type FakeEventingV1 struct { + *testing.Fake +} + +func (c *FakeEventingV1) Brokers(namespace string) v1.BrokerInterface { + return &FakeBrokers{c, namespace} +} + +func (c *FakeEventingV1) Triggers(namespace string) v1.TriggerInterface { + return &FakeTriggers{c, namespace} +} + +// RESTClient returns a RESTClient that is used to communicate +// with API server by this client implementation. +func (c *FakeEventingV1) RESTClient() rest.Interface { + var ret *rest.RESTClient + return ret +} diff --git a/vendor/knative.dev/eventing/pkg/client/clientset/versioned/typed/eventing/v1/fake/fake_trigger.go b/vendor/knative.dev/eventing/pkg/client/clientset/versioned/typed/eventing/v1/fake/fake_trigger.go new file mode 100644 index 0000000000..6b3795b6fb --- /dev/null +++ b/vendor/knative.dev/eventing/pkg/client/clientset/versioned/typed/eventing/v1/fake/fake_trigger.go @@ -0,0 +1,140 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + testing "k8s.io/client-go/testing" + eventingv1 "knative.dev/eventing/pkg/apis/eventing/v1" +) + +// FakeTriggers implements TriggerInterface +type FakeTriggers struct { + Fake *FakeEventingV1 + ns string +} + +var triggersResource = schema.GroupVersionResource{Group: "eventing.knative.dev", Version: "v1", Resource: "triggers"} + +var triggersKind = schema.GroupVersionKind{Group: "eventing.knative.dev", Version: "v1", Kind: "Trigger"} + +// Get takes name of the trigger, and returns the corresponding trigger object, and an error if there is any. +func (c *FakeTriggers) Get(name string, options v1.GetOptions) (result *eventingv1.Trigger, err error) { + obj, err := c.Fake. + Invokes(testing.NewGetAction(triggersResource, c.ns, name), &eventingv1.Trigger{}) + + if obj == nil { + return nil, err + } + return obj.(*eventingv1.Trigger), err +} + +// List takes label and field selectors, and returns the list of Triggers that match those selectors. +func (c *FakeTriggers) List(opts v1.ListOptions) (result *eventingv1.TriggerList, err error) { + obj, err := c.Fake. + Invokes(testing.NewListAction(triggersResource, triggersKind, c.ns, opts), &eventingv1.TriggerList{}) + + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &eventingv1.TriggerList{ListMeta: obj.(*eventingv1.TriggerList).ListMeta} + for _, item := range obj.(*eventingv1.TriggerList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested triggers. +func (c *FakeTriggers) Watch(opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewWatchAction(triggersResource, c.ns, opts)) + +} + +// Create takes the representation of a trigger and creates it. Returns the server's representation of the trigger, and an error, if there is any. +func (c *FakeTriggers) Create(trigger *eventingv1.Trigger) (result *eventingv1.Trigger, err error) { + obj, err := c.Fake. + Invokes(testing.NewCreateAction(triggersResource, c.ns, trigger), &eventingv1.Trigger{}) + + if obj == nil { + return nil, err + } + return obj.(*eventingv1.Trigger), err +} + +// Update takes the representation of a trigger and updates it. Returns the server's representation of the trigger, and an error, if there is any. +func (c *FakeTriggers) Update(trigger *eventingv1.Trigger) (result *eventingv1.Trigger, err error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateAction(triggersResource, c.ns, trigger), &eventingv1.Trigger{}) + + if obj == nil { + return nil, err + } + return obj.(*eventingv1.Trigger), err +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). +func (c *FakeTriggers) UpdateStatus(trigger *eventingv1.Trigger) (*eventingv1.Trigger, error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateSubresourceAction(triggersResource, "status", c.ns, trigger), &eventingv1.Trigger{}) + + if obj == nil { + return nil, err + } + return obj.(*eventingv1.Trigger), err +} + +// Delete takes name of the trigger and deletes it. Returns an error if one occurs. +func (c *FakeTriggers) Delete(name string, options *v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewDeleteAction(triggersResource, c.ns, name), &eventingv1.Trigger{}) + + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeTriggers) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error { + action := testing.NewDeleteCollectionAction(triggersResource, c.ns, listOptions) + + _, err := c.Fake.Invokes(action, &eventingv1.TriggerList{}) + return err +} + +// Patch applies the patch and returns the patched trigger. +func (c *FakeTriggers) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *eventingv1.Trigger, err error) { + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(triggersResource, c.ns, name, pt, data, subresources...), &eventingv1.Trigger{}) + + if obj == nil { + return nil, err + } + return obj.(*eventingv1.Trigger), err +} diff --git a/vendor/knative.dev/eventing/pkg/client/clientset/versioned/typed/eventing/v1/generated_expansion.go b/vendor/knative.dev/eventing/pkg/client/clientset/versioned/typed/eventing/v1/generated_expansion.go new file mode 100644 index 0000000000..9877b5eba3 --- /dev/null +++ b/vendor/knative.dev/eventing/pkg/client/clientset/versioned/typed/eventing/v1/generated_expansion.go @@ -0,0 +1,23 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package v1 + +type BrokerExpansion interface{} + +type TriggerExpansion interface{} diff --git a/vendor/knative.dev/eventing/pkg/client/clientset/versioned/typed/eventing/v1/trigger.go b/vendor/knative.dev/eventing/pkg/client/clientset/versioned/typed/eventing/v1/trigger.go new file mode 100644 index 0000000000..9726e4e3c8 --- /dev/null +++ b/vendor/knative.dev/eventing/pkg/client/clientset/versioned/typed/eventing/v1/trigger.go @@ -0,0 +1,191 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package v1 + +import ( + "time" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + rest "k8s.io/client-go/rest" + v1 "knative.dev/eventing/pkg/apis/eventing/v1" + scheme "knative.dev/eventing/pkg/client/clientset/versioned/scheme" +) + +// TriggersGetter has a method to return a TriggerInterface. +// A group's client should implement this interface. +type TriggersGetter interface { + Triggers(namespace string) TriggerInterface +} + +// TriggerInterface has methods to work with Trigger resources. +type TriggerInterface interface { + Create(*v1.Trigger) (*v1.Trigger, error) + Update(*v1.Trigger) (*v1.Trigger, error) + UpdateStatus(*v1.Trigger) (*v1.Trigger, error) + Delete(name string, options *metav1.DeleteOptions) error + DeleteCollection(options *metav1.DeleteOptions, listOptions metav1.ListOptions) error + Get(name string, options metav1.GetOptions) (*v1.Trigger, error) + List(opts metav1.ListOptions) (*v1.TriggerList, error) + Watch(opts metav1.ListOptions) (watch.Interface, error) + Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1.Trigger, err error) + TriggerExpansion +} + +// triggers implements TriggerInterface +type triggers struct { + client rest.Interface + ns string +} + +// newTriggers returns a Triggers +func newTriggers(c *EventingV1Client, namespace string) *triggers { + return &triggers{ + client: c.RESTClient(), + ns: namespace, + } +} + +// Get takes name of the trigger, and returns the corresponding trigger object, and an error if there is any. +func (c *triggers) Get(name string, options metav1.GetOptions) (result *v1.Trigger, err error) { + result = &v1.Trigger{} + err = c.client.Get(). + Namespace(c.ns). + Resource("triggers"). + Name(name). + VersionedParams(&options, scheme.ParameterCodec). + Do(). + Into(result) + return +} + +// List takes label and field selectors, and returns the list of Triggers that match those selectors. +func (c *triggers) List(opts metav1.ListOptions) (result *v1.TriggerList, err error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + result = &v1.TriggerList{} + err = c.client.Get(). + Namespace(c.ns). + Resource("triggers"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Do(). + Into(result) + return +} + +// Watch returns a watch.Interface that watches the requested triggers. +func (c *triggers) Watch(opts metav1.ListOptions) (watch.Interface, error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + opts.Watch = true + return c.client.Get(). + Namespace(c.ns). + Resource("triggers"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Watch() +} + +// Create takes the representation of a trigger and creates it. Returns the server's representation of the trigger, and an error, if there is any. +func (c *triggers) Create(trigger *v1.Trigger) (result *v1.Trigger, err error) { + result = &v1.Trigger{} + err = c.client.Post(). + Namespace(c.ns). + Resource("triggers"). + Body(trigger). + Do(). + Into(result) + return +} + +// Update takes the representation of a trigger and updates it. Returns the server's representation of the trigger, and an error, if there is any. +func (c *triggers) Update(trigger *v1.Trigger) (result *v1.Trigger, err error) { + result = &v1.Trigger{} + err = c.client.Put(). + Namespace(c.ns). + Resource("triggers"). + Name(trigger.Name). + Body(trigger). + Do(). + Into(result) + return +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). + +func (c *triggers) UpdateStatus(trigger *v1.Trigger) (result *v1.Trigger, err error) { + result = &v1.Trigger{} + err = c.client.Put(). + Namespace(c.ns). + Resource("triggers"). + Name(trigger.Name). + SubResource("status"). + Body(trigger). + Do(). + Into(result) + return +} + +// Delete takes name of the trigger and deletes it. Returns an error if one occurs. +func (c *triggers) Delete(name string, options *metav1.DeleteOptions) error { + return c.client.Delete(). + Namespace(c.ns). + Resource("triggers"). + Name(name). + Body(options). + Do(). + Error() +} + +// DeleteCollection deletes a collection of objects. +func (c *triggers) DeleteCollection(options *metav1.DeleteOptions, listOptions metav1.ListOptions) error { + var timeout time.Duration + if listOptions.TimeoutSeconds != nil { + timeout = time.Duration(*listOptions.TimeoutSeconds) * time.Second + } + return c.client.Delete(). + Namespace(c.ns). + Resource("triggers"). + VersionedParams(&listOptions, scheme.ParameterCodec). + Timeout(timeout). + Body(options). + Do(). + Error() +} + +// Patch applies the patch and returns the patched trigger. +func (c *triggers) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1.Trigger, err error) { + result = &v1.Trigger{} + err = c.client.Patch(pt). + Namespace(c.ns). + Resource("triggers"). + SubResource(subresources...). + Name(name). + Body(data). + Do(). + Into(result) + return +} diff --git a/vendor/knative.dev/eventing/pkg/client/informers/externalversions/eventing/interface.go b/vendor/knative.dev/eventing/pkg/client/informers/externalversions/eventing/interface.go index c4e662bafb..531a3c7721 100644 --- a/vendor/knative.dev/eventing/pkg/client/informers/externalversions/eventing/interface.go +++ b/vendor/knative.dev/eventing/pkg/client/informers/externalversions/eventing/interface.go @@ -19,6 +19,7 @@ limitations under the License. package eventing import ( + v1 "knative.dev/eventing/pkg/client/informers/externalversions/eventing/v1" v1beta1 "knative.dev/eventing/pkg/client/informers/externalversions/eventing/v1beta1" internalinterfaces "knative.dev/eventing/pkg/client/informers/externalversions/internalinterfaces" ) @@ -27,6 +28,8 @@ import ( type Interface interface { // V1beta1 provides access to shared informers for resources in V1beta1. V1beta1() v1beta1.Interface + // V1 provides access to shared informers for resources in V1. + V1() v1.Interface } type group struct { @@ -44,3 +47,8 @@ func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakList func (g *group) V1beta1() v1beta1.Interface { return v1beta1.New(g.factory, g.namespace, g.tweakListOptions) } + +// V1 returns a new v1.Interface. +func (g *group) V1() v1.Interface { + return v1.New(g.factory, g.namespace, g.tweakListOptions) +} diff --git a/vendor/knative.dev/eventing/pkg/client/informers/externalversions/eventing/v1/broker.go b/vendor/knative.dev/eventing/pkg/client/informers/externalversions/eventing/v1/broker.go new file mode 100644 index 0000000000..b35aa4ee2f --- /dev/null +++ b/vendor/knative.dev/eventing/pkg/client/informers/externalversions/eventing/v1/broker.go @@ -0,0 +1,89 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package v1 + +import ( + time "time" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + watch "k8s.io/apimachinery/pkg/watch" + cache "k8s.io/client-go/tools/cache" + eventingv1 "knative.dev/eventing/pkg/apis/eventing/v1" + versioned "knative.dev/eventing/pkg/client/clientset/versioned" + internalinterfaces "knative.dev/eventing/pkg/client/informers/externalversions/internalinterfaces" + v1 "knative.dev/eventing/pkg/client/listers/eventing/v1" +) + +// BrokerInformer provides access to a shared informer and lister for +// Brokers. +type BrokerInformer interface { + Informer() cache.SharedIndexInformer + Lister() v1.BrokerLister +} + +type brokerInformer struct { + factory internalinterfaces.SharedInformerFactory + tweakListOptions internalinterfaces.TweakListOptionsFunc + namespace string +} + +// NewBrokerInformer constructs a new informer for Broker type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewBrokerInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { + return NewFilteredBrokerInformer(client, namespace, resyncPeriod, indexers, nil) +} + +// NewFilteredBrokerInformer constructs a new informer for Broker type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewFilteredBrokerInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer { + return cache.NewSharedIndexInformer( + &cache.ListWatch{ + ListFunc: func(options metav1.ListOptions) (runtime.Object, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.EventingV1().Brokers(namespace).List(options) + }, + WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.EventingV1().Brokers(namespace).Watch(options) + }, + }, + &eventingv1.Broker{}, + resyncPeriod, + indexers, + ) +} + +func (f *brokerInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { + return NewFilteredBrokerInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) +} + +func (f *brokerInformer) Informer() cache.SharedIndexInformer { + return f.factory.InformerFor(&eventingv1.Broker{}, f.defaultInformer) +} + +func (f *brokerInformer) Lister() v1.BrokerLister { + return v1.NewBrokerLister(f.Informer().GetIndexer()) +} diff --git a/vendor/knative.dev/eventing/pkg/client/informers/externalversions/eventing/v1/interface.go b/vendor/knative.dev/eventing/pkg/client/informers/externalversions/eventing/v1/interface.go new file mode 100644 index 0000000000..8c36a48dfd --- /dev/null +++ b/vendor/knative.dev/eventing/pkg/client/informers/externalversions/eventing/v1/interface.go @@ -0,0 +1,52 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package v1 + +import ( + internalinterfaces "knative.dev/eventing/pkg/client/informers/externalversions/internalinterfaces" +) + +// Interface provides access to all the informers in this group version. +type Interface interface { + // Brokers returns a BrokerInformer. + Brokers() BrokerInformer + // Triggers returns a TriggerInformer. + Triggers() TriggerInformer +} + +type version struct { + factory internalinterfaces.SharedInformerFactory + namespace string + tweakListOptions internalinterfaces.TweakListOptionsFunc +} + +// New returns a new Interface. +func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface { + return &version{factory: f, namespace: namespace, tweakListOptions: tweakListOptions} +} + +// Brokers returns a BrokerInformer. +func (v *version) Brokers() BrokerInformer { + return &brokerInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} +} + +// Triggers returns a TriggerInformer. +func (v *version) Triggers() TriggerInformer { + return &triggerInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} +} diff --git a/vendor/knative.dev/eventing/pkg/client/informers/externalversions/eventing/v1/trigger.go b/vendor/knative.dev/eventing/pkg/client/informers/externalversions/eventing/v1/trigger.go new file mode 100644 index 0000000000..6f99981bf7 --- /dev/null +++ b/vendor/knative.dev/eventing/pkg/client/informers/externalversions/eventing/v1/trigger.go @@ -0,0 +1,89 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package v1 + +import ( + time "time" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + watch "k8s.io/apimachinery/pkg/watch" + cache "k8s.io/client-go/tools/cache" + eventingv1 "knative.dev/eventing/pkg/apis/eventing/v1" + versioned "knative.dev/eventing/pkg/client/clientset/versioned" + internalinterfaces "knative.dev/eventing/pkg/client/informers/externalversions/internalinterfaces" + v1 "knative.dev/eventing/pkg/client/listers/eventing/v1" +) + +// TriggerInformer provides access to a shared informer and lister for +// Triggers. +type TriggerInformer interface { + Informer() cache.SharedIndexInformer + Lister() v1.TriggerLister +} + +type triggerInformer struct { + factory internalinterfaces.SharedInformerFactory + tweakListOptions internalinterfaces.TweakListOptionsFunc + namespace string +} + +// NewTriggerInformer constructs a new informer for Trigger type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewTriggerInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { + return NewFilteredTriggerInformer(client, namespace, resyncPeriod, indexers, nil) +} + +// NewFilteredTriggerInformer constructs a new informer for Trigger type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewFilteredTriggerInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer { + return cache.NewSharedIndexInformer( + &cache.ListWatch{ + ListFunc: func(options metav1.ListOptions) (runtime.Object, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.EventingV1().Triggers(namespace).List(options) + }, + WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.EventingV1().Triggers(namespace).Watch(options) + }, + }, + &eventingv1.Trigger{}, + resyncPeriod, + indexers, + ) +} + +func (f *triggerInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { + return NewFilteredTriggerInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) +} + +func (f *triggerInformer) Informer() cache.SharedIndexInformer { + return f.factory.InformerFor(&eventingv1.Trigger{}, f.defaultInformer) +} + +func (f *triggerInformer) Lister() v1.TriggerLister { + return v1.NewTriggerLister(f.Informer().GetIndexer()) +} diff --git a/vendor/knative.dev/eventing/pkg/client/informers/externalversions/generic.go b/vendor/knative.dev/eventing/pkg/client/informers/externalversions/generic.go index c91f5c4758..83ba875db8 100644 --- a/vendor/knative.dev/eventing/pkg/client/informers/externalversions/generic.go +++ b/vendor/knative.dev/eventing/pkg/client/informers/externalversions/generic.go @@ -24,6 +24,7 @@ import ( schema "k8s.io/apimachinery/pkg/runtime/schema" cache "k8s.io/client-go/tools/cache" v1alpha1 "knative.dev/eventing/pkg/apis/configs/v1alpha1" + v1 "knative.dev/eventing/pkg/apis/eventing/v1" v1beta1 "knative.dev/eventing/pkg/apis/eventing/v1beta1" flowsv1beta1 "knative.dev/eventing/pkg/apis/flows/v1beta1" messagingv1beta1 "knative.dev/eventing/pkg/apis/messaging/v1beta1" @@ -61,6 +62,12 @@ func (f *sharedInformerFactory) ForResource(resource schema.GroupVersionResource case v1alpha1.SchemeGroupVersion.WithResource("configmappropagations"): return &genericInformer{resource: resource.GroupResource(), informer: f.Configs().V1alpha1().ConfigMapPropagations().Informer()}, nil + // Group=eventing.knative.dev, Version=v1 + case v1.SchemeGroupVersion.WithResource("brokers"): + return &genericInformer{resource: resource.GroupResource(), informer: f.Eventing().V1().Brokers().Informer()}, nil + case v1.SchemeGroupVersion.WithResource("triggers"): + return &genericInformer{resource: resource.GroupResource(), informer: f.Eventing().V1().Triggers().Informer()}, nil + // Group=eventing.knative.dev, Version=v1beta1 case v1beta1.SchemeGroupVersion.WithResource("brokers"): return &genericInformer{resource: resource.GroupResource(), informer: f.Eventing().V1beta1().Brokers().Informer()}, nil diff --git a/vendor/knative.dev/eventing/pkg/client/listers/eventing/v1/broker.go b/vendor/knative.dev/eventing/pkg/client/listers/eventing/v1/broker.go new file mode 100644 index 0000000000..c6dca9da07 --- /dev/null +++ b/vendor/knative.dev/eventing/pkg/client/listers/eventing/v1/broker.go @@ -0,0 +1,94 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by lister-gen. DO NOT EDIT. + +package v1 + +import ( + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/client-go/tools/cache" + v1 "knative.dev/eventing/pkg/apis/eventing/v1" +) + +// BrokerLister helps list Brokers. +type BrokerLister interface { + // List lists all Brokers in the indexer. + List(selector labels.Selector) (ret []*v1.Broker, err error) + // Brokers returns an object that can list and get Brokers. + Brokers(namespace string) BrokerNamespaceLister + BrokerListerExpansion +} + +// brokerLister implements the BrokerLister interface. +type brokerLister struct { + indexer cache.Indexer +} + +// NewBrokerLister returns a new BrokerLister. +func NewBrokerLister(indexer cache.Indexer) BrokerLister { + return &brokerLister{indexer: indexer} +} + +// List lists all Brokers in the indexer. +func (s *brokerLister) List(selector labels.Selector) (ret []*v1.Broker, err error) { + err = cache.ListAll(s.indexer, selector, func(m interface{}) { + ret = append(ret, m.(*v1.Broker)) + }) + return ret, err +} + +// Brokers returns an object that can list and get Brokers. +func (s *brokerLister) Brokers(namespace string) BrokerNamespaceLister { + return brokerNamespaceLister{indexer: s.indexer, namespace: namespace} +} + +// BrokerNamespaceLister helps list and get Brokers. +type BrokerNamespaceLister interface { + // List lists all Brokers in the indexer for a given namespace. + List(selector labels.Selector) (ret []*v1.Broker, err error) + // Get retrieves the Broker from the indexer for a given namespace and name. + Get(name string) (*v1.Broker, error) + BrokerNamespaceListerExpansion +} + +// brokerNamespaceLister implements the BrokerNamespaceLister +// interface. +type brokerNamespaceLister struct { + indexer cache.Indexer + namespace string +} + +// List lists all Brokers in the indexer for a given namespace. +func (s brokerNamespaceLister) List(selector labels.Selector) (ret []*v1.Broker, err error) { + err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) { + ret = append(ret, m.(*v1.Broker)) + }) + return ret, err +} + +// Get retrieves the Broker from the indexer for a given namespace and name. +func (s brokerNamespaceLister) Get(name string) (*v1.Broker, error) { + obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name) + if err != nil { + return nil, err + } + if !exists { + return nil, errors.NewNotFound(v1.Resource("broker"), name) + } + return obj.(*v1.Broker), nil +} diff --git a/vendor/knative.dev/eventing/pkg/client/listers/eventing/v1/expansion_generated.go b/vendor/knative.dev/eventing/pkg/client/listers/eventing/v1/expansion_generated.go new file mode 100644 index 0000000000..7a8772ae63 --- /dev/null +++ b/vendor/knative.dev/eventing/pkg/client/listers/eventing/v1/expansion_generated.go @@ -0,0 +1,35 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by lister-gen. DO NOT EDIT. + +package v1 + +// BrokerListerExpansion allows custom methods to be added to +// BrokerLister. +type BrokerListerExpansion interface{} + +// BrokerNamespaceListerExpansion allows custom methods to be added to +// BrokerNamespaceLister. +type BrokerNamespaceListerExpansion interface{} + +// TriggerListerExpansion allows custom methods to be added to +// TriggerLister. +type TriggerListerExpansion interface{} + +// TriggerNamespaceListerExpansion allows custom methods to be added to +// TriggerNamespaceLister. +type TriggerNamespaceListerExpansion interface{} diff --git a/vendor/knative.dev/eventing/pkg/client/listers/eventing/v1/trigger.go b/vendor/knative.dev/eventing/pkg/client/listers/eventing/v1/trigger.go new file mode 100644 index 0000000000..bd362b5c5f --- /dev/null +++ b/vendor/knative.dev/eventing/pkg/client/listers/eventing/v1/trigger.go @@ -0,0 +1,94 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by lister-gen. DO NOT EDIT. + +package v1 + +import ( + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/client-go/tools/cache" + v1 "knative.dev/eventing/pkg/apis/eventing/v1" +) + +// TriggerLister helps list Triggers. +type TriggerLister interface { + // List lists all Triggers in the indexer. + List(selector labels.Selector) (ret []*v1.Trigger, err error) + // Triggers returns an object that can list and get Triggers. + Triggers(namespace string) TriggerNamespaceLister + TriggerListerExpansion +} + +// triggerLister implements the TriggerLister interface. +type triggerLister struct { + indexer cache.Indexer +} + +// NewTriggerLister returns a new TriggerLister. +func NewTriggerLister(indexer cache.Indexer) TriggerLister { + return &triggerLister{indexer: indexer} +} + +// List lists all Triggers in the indexer. +func (s *triggerLister) List(selector labels.Selector) (ret []*v1.Trigger, err error) { + err = cache.ListAll(s.indexer, selector, func(m interface{}) { + ret = append(ret, m.(*v1.Trigger)) + }) + return ret, err +} + +// Triggers returns an object that can list and get Triggers. +func (s *triggerLister) Triggers(namespace string) TriggerNamespaceLister { + return triggerNamespaceLister{indexer: s.indexer, namespace: namespace} +} + +// TriggerNamespaceLister helps list and get Triggers. +type TriggerNamespaceLister interface { + // List lists all Triggers in the indexer for a given namespace. + List(selector labels.Selector) (ret []*v1.Trigger, err error) + // Get retrieves the Trigger from the indexer for a given namespace and name. + Get(name string) (*v1.Trigger, error) + TriggerNamespaceListerExpansion +} + +// triggerNamespaceLister implements the TriggerNamespaceLister +// interface. +type triggerNamespaceLister struct { + indexer cache.Indexer + namespace string +} + +// List lists all Triggers in the indexer for a given namespace. +func (s triggerNamespaceLister) List(selector labels.Selector) (ret []*v1.Trigger, err error) { + err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) { + ret = append(ret, m.(*v1.Trigger)) + }) + return ret, err +} + +// Get retrieves the Trigger from the indexer for a given namespace and name. +func (s triggerNamespaceLister) Get(name string) (*v1.Trigger, error) { + obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name) + if err != nil { + return nil, err + } + if !exists { + return nil, errors.NewNotFound(v1.Resource("trigger"), name) + } + return obj.(*v1.Trigger), nil +} diff --git a/vendor/knative.dev/pkg/codegen/cmd/injection-gen/generators/packages.go b/vendor/knative.dev/pkg/codegen/cmd/injection-gen/generators/packages.go index c54d6f915c..50f3cb4618 100644 --- a/vendor/knative.dev/pkg/codegen/cmd/injection-gen/generators/packages.go +++ b/vendor/knative.dev/pkg/codegen/cmd/injection-gen/generators/packages.go @@ -201,7 +201,7 @@ func isKRShaped(tags map[string]map[string]string) bool { if !has { return false } - return vals["krshapedlogic"] == "true" + return vals["krshapedlogic"] != "false" } func isNonNamespaced(tags map[string]map[string]string) bool { diff --git a/vendor/knative.dev/pkg/test/spoof/spoof.go b/vendor/knative.dev/pkg/test/spoof/spoof.go index 9ac2073183..c3a0f7b877 100644 --- a/vendor/knative.dev/pkg/test/spoof/spoof.go +++ b/vendor/knative.dev/pkg/test/spoof/spoof.go @@ -34,9 +34,9 @@ import ( "knative.dev/pkg/test/ingress" "knative.dev/pkg/test/logging" "knative.dev/pkg/test/zipkin" + "knative.dev/pkg/tracing/propagation/tracecontextb3" "go.opencensus.io/plugin/ochttp" - "go.opencensus.io/plugin/ochttp/propagation/b3" "go.opencensus.io/trace" ) @@ -135,7 +135,7 @@ func New( // Enable Zipkin tracing roundTripper := &ochttp.Transport{ Base: transport, - Propagation: &b3.HTTPFormat{}, + Propagation: tracecontextb3.TraceContextEgress, } sc := SpoofingClient{ diff --git a/vendor/knative.dev/pkg/tracing/http.go b/vendor/knative.dev/pkg/tracing/http.go index 2a5d65c521..89509ed0b0 100644 --- a/vendor/knative.dev/pkg/tracing/http.go +++ b/vendor/knative.dev/pkg/tracing/http.go @@ -22,6 +22,7 @@ import ( "go.opencensus.io/plugin/ochttp" "go.opencensus.io/trace" "k8s.io/apimachinery/pkg/util/sets" + "knative.dev/pkg/tracing/propagation/tracecontextb3" ) var ( @@ -50,6 +51,7 @@ func HTTPSpanIgnoringPaths(pathsToIgnore ...string) func(http.Handler) http.Hand } return underlyingSampling }, + Propagation: tracecontextb3.TraceContextEgress, } } } diff --git a/vendor/knative.dev/pkg/tracing/propagation/http_format_sequence.go b/vendor/knative.dev/pkg/tracing/propagation/http_format_sequence.go new file mode 100644 index 0000000000..9a11cbfe9e --- /dev/null +++ b/vendor/knative.dev/pkg/tracing/propagation/http_format_sequence.go @@ -0,0 +1,53 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package propagation + +import ( + "net/http" + + "go.opencensus.io/trace" + "go.opencensus.io/trace/propagation" +) + +// HTTPFormatSequence is a propagation.HTTPFormat that applies multiple other propagation formats. +// For incoming requests, it will use the first SpanContext it can find, checked in the order of +// HTTPFormatSequence.Ingress. +// For outgoing requests, it will apply all the formats to the outgoing request, in the order of +// HTTPFormatSequence.Egress. +type HTTPFormatSequence struct { + Ingress []propagation.HTTPFormat + Egress []propagation.HTTPFormat +} + +var _ propagation.HTTPFormat = (*HTTPFormatSequence)(nil) + +// SpanContextFromRequest satisfies the propagation.HTTPFormat interface. +func (h *HTTPFormatSequence) SpanContextFromRequest(req *http.Request) (trace.SpanContext, bool) { + for _, format := range h.Ingress { + if sc, ok := format.SpanContextFromRequest(req); ok { + return sc, true + } + } + return trace.SpanContext{}, false +} + +// SpanContextToRequest satisfies the propagation.HTTPFormat interface. +func (h *HTTPFormatSequence) SpanContextToRequest(sc trace.SpanContext, req *http.Request) { + for _, format := range h.Egress { + format.SpanContextToRequest(sc, req) + } +} diff --git a/vendor/knative.dev/pkg/tracing/propagation/tracecontextb3/http_format.go b/vendor/knative.dev/pkg/tracing/propagation/tracecontextb3/http_format.go new file mode 100644 index 0000000000..0853ff06c6 --- /dev/null +++ b/vendor/knative.dev/pkg/tracing/propagation/tracecontextb3/http_format.go @@ -0,0 +1,61 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package tracecontextb3 + +import ( + "go.opencensus.io/plugin/ochttp/propagation/b3" + "go.opencensus.io/plugin/ochttp/propagation/tracecontext" + ocpropagation "go.opencensus.io/trace/propagation" + "knative.dev/pkg/tracing/propagation" +) + +// TraceContextB3Egress is a propagation.HTTPFormat that reads both TraceContext and B3 tracing +// formats, preferring TraceContext. It always writes both formats. +var TraceContextB3Egress = &propagation.HTTPFormatSequence{ + Ingress: []ocpropagation.HTTPFormat{ + &tracecontext.HTTPFormat{}, + &b3.HTTPFormat{}, + }, + Egress: []ocpropagation.HTTPFormat{ + &tracecontext.HTTPFormat{}, + &b3.HTTPFormat{}, + }, +} + +// TraceContextEgress is a propagation.HTTPFormat that reads both TraceContext and B3 tracing +// formats, preferring TraceContext. It always writes TraceContext format exclusively. +var TraceContextEgress = &propagation.HTTPFormatSequence{ + Ingress: []ocpropagation.HTTPFormat{ + &tracecontext.HTTPFormat{}, + &b3.HTTPFormat{}, + }, + Egress: []ocpropagation.HTTPFormat{ + &tracecontext.HTTPFormat{}, + }, +} + +// B3Egress is a propagation.HTTPFormat that reads both TraceContext and B3 tracing formats, +// preferring TraceContext. It always writes B3 format exclusively. +var B3Egress = &propagation.HTTPFormatSequence{ + Ingress: []ocpropagation.HTTPFormat{ + &tracecontext.HTTPFormat{}, + &b3.HTTPFormat{}, + }, + Egress: []ocpropagation.HTTPFormat{ + &b3.HTTPFormat{}, + }, +} diff --git a/vendor/knative.dev/serving/pkg/apis/config/features.go b/vendor/knative.dev/serving/pkg/apis/config/features.go index 78f3f4620c..415ff1d95b 100644 --- a/vendor/knative.dev/serving/pkg/apis/config/features.go +++ b/vendor/knative.dev/serving/pkg/apis/config/features.go @@ -40,9 +40,9 @@ const ( func defaultFeaturesConfig() *Features { return &Features{ - MultiContainer: Disabled, - FieldRef: Disabled, - PodSpecDryRun: Allowed, + MultiContainer: Disabled, + PodSpecFieldRef: Disabled, + PodSpecDryRun: Allowed, } } @@ -52,7 +52,7 @@ func NewFeaturesConfigFromMap(data map[string]string) (*Features, error) { if err := cm.Parse(data, asFlag("multi-container", &nc.MultiContainer), - asFlag("kubernetes/field-ref", &nc.FieldRef), + asFlag("kubernetes/podspec-fieldref", &nc.PodSpecFieldRef), asFlag("kubernetes/podspec-dryrun", &nc.PodSpecDryRun)); err != nil { return nil, err } @@ -66,9 +66,9 @@ func NewFeaturesConfigFromConfigMap(config *corev1.ConfigMap) (*Features, error) // Features specifies which features are allowed by the webhook. type Features struct { - MultiContainer Flag - FieldRef Flag - PodSpecDryRun Flag + MultiContainer Flag + PodSpecFieldRef Flag + PodSpecDryRun Flag } // asFlag parses the value at key as a Flag into the target, if it exists. diff --git a/vendor/knative.dev/serving/pkg/apis/serving/k8s_validation.go b/vendor/knative.dev/serving/pkg/apis/serving/k8s_validation.go index 14bffe5899..000b1b288b 100644 --- a/vendor/knative.dev/serving/pkg/apis/serving/k8s_validation.go +++ b/vendor/knative.dev/serving/pkg/apis/serving/k8s_validation.go @@ -186,7 +186,7 @@ func validateEnvValueFrom(ctx context.Context, source *corev1.EnvVarSource) *api return nil } features := config.FromContextOrDefaults(ctx).Features - return apis.CheckDisallowedFields(*source, *EnvVarSourceMask(source, features.FieldRef != config.Disabled)) + return apis.CheckDisallowedFields(*source, *EnvVarSourceMask(source, features.PodSpecFieldRef != config.Disabled)) } func validateEnvVar(ctx context.Context, env corev1.EnvVar) *apis.FieldError { diff --git a/vendor/modules.txt b/vendor/modules.txt index fe3783f41e..db49f2ef48 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -111,9 +111,6 @@ github.com/cloudevents/sdk-go/pkg/cloudevents/extensions github.com/cloudevents/sdk-go/pkg/cloudevents/observability github.com/cloudevents/sdk-go/pkg/cloudevents/transport github.com/cloudevents/sdk-go/pkg/cloudevents/transport/http -github.com/cloudevents/sdk-go/pkg/cloudevents/transport/pubsub -github.com/cloudevents/sdk-go/pkg/cloudevents/transport/pubsub/context -github.com/cloudevents/sdk-go/pkg/cloudevents/transport/pubsub/internal github.com/cloudevents/sdk-go/pkg/cloudevents/types # github.com/cloudevents/sdk-go/protocol/pubsub/v2 v2.0.1-0.20200602143929-d07dc0510d45 ## explicit @@ -1026,7 +1023,7 @@ k8s.io/utils/buffer k8s.io/utils/integer k8s.io/utils/pointer k8s.io/utils/trace -# knative.dev/eventing v0.15.1-0.20200623095326-e1e5e1a81ca8 +# knative.dev/eventing v0.15.1-0.20200623172931-13e513727e77 ## explicit knative.dev/eventing/pkg/apis/config knative.dev/eventing/pkg/apis/configs @@ -1036,6 +1033,7 @@ knative.dev/eventing/pkg/apis/duck/v1 knative.dev/eventing/pkg/apis/duck/v1alpha1 knative.dev/eventing/pkg/apis/duck/v1beta1 knative.dev/eventing/pkg/apis/eventing +knative.dev/eventing/pkg/apis/eventing/v1 knative.dev/eventing/pkg/apis/eventing/v1beta1 knative.dev/eventing/pkg/apis/flows knative.dev/eventing/pkg/apis/flows/v1beta1 @@ -1050,6 +1048,8 @@ knative.dev/eventing/pkg/client/clientset/versioned/fake knative.dev/eventing/pkg/client/clientset/versioned/scheme knative.dev/eventing/pkg/client/clientset/versioned/typed/configs/v1alpha1 knative.dev/eventing/pkg/client/clientset/versioned/typed/configs/v1alpha1/fake +knative.dev/eventing/pkg/client/clientset/versioned/typed/eventing/v1 +knative.dev/eventing/pkg/client/clientset/versioned/typed/eventing/v1/fake knative.dev/eventing/pkg/client/clientset/versioned/typed/eventing/v1beta1 knative.dev/eventing/pkg/client/clientset/versioned/typed/eventing/v1beta1/fake knative.dev/eventing/pkg/client/clientset/versioned/typed/flows/v1beta1 @@ -1064,6 +1064,7 @@ knative.dev/eventing/pkg/client/informers/externalversions knative.dev/eventing/pkg/client/informers/externalversions/configs knative.dev/eventing/pkg/client/informers/externalversions/configs/v1alpha1 knative.dev/eventing/pkg/client/informers/externalversions/eventing +knative.dev/eventing/pkg/client/informers/externalversions/eventing/v1 knative.dev/eventing/pkg/client/informers/externalversions/eventing/v1beta1 knative.dev/eventing/pkg/client/informers/externalversions/flows knative.dev/eventing/pkg/client/informers/externalversions/flows/v1beta1 @@ -1079,6 +1080,7 @@ knative.dev/eventing/pkg/client/injection/informers/eventing/v1beta1/broker knative.dev/eventing/pkg/client/injection/informers/factory knative.dev/eventing/pkg/client/injection/reconciler/eventing/v1beta1/broker knative.dev/eventing/pkg/client/listers/configs/v1alpha1 +knative.dev/eventing/pkg/client/listers/eventing/v1 knative.dev/eventing/pkg/client/listers/eventing/v1beta1 knative.dev/eventing/pkg/client/listers/flows/v1beta1 knative.dev/eventing/pkg/client/listers/messaging/v1beta1 @@ -1117,7 +1119,7 @@ knative.dev/eventing/test/test_images/transformevents knative.dev/networking/pkg/apis/config knative.dev/networking/pkg/apis/networking knative.dev/networking/pkg/apis/networking/v1alpha1 -# knative.dev/pkg v0.0.0-20200623024526-fb0320d9287e +# knative.dev/pkg v0.0.0-20200623173527-5658d93fb07e ## explicit knative.dev/pkg/apis knative.dev/pkg/apis/duck @@ -1212,6 +1214,8 @@ knative.dev/pkg/testutils/clustermanager/perf-tests/pkg knative.dev/pkg/third_party/mako/proto/quickstore_go_proto knative.dev/pkg/tracing knative.dev/pkg/tracing/config +knative.dev/pkg/tracing/propagation +knative.dev/pkg/tracing/propagation/tracecontextb3 knative.dev/pkg/tracker knative.dev/pkg/version knative.dev/pkg/webhook @@ -1222,7 +1226,7 @@ knative.dev/pkg/webhook/resourcesemantics knative.dev/pkg/webhook/resourcesemantics/conversion knative.dev/pkg/webhook/resourcesemantics/defaulting knative.dev/pkg/webhook/resourcesemantics/validation -# knative.dev/serving v0.15.1-0.20200623132926-f3cdbb37c9d3 +# knative.dev/serving v0.15.1-0.20200623190335-3459a76f9976 ## explicit knative.dev/serving/pkg/apis/autoscaling knative.dev/serving/pkg/apis/autoscaling/v1alpha1 @@ -1261,7 +1265,7 @@ knative.dev/serving/pkg/client/listers/autoscaling/v1alpha1 knative.dev/serving/pkg/client/listers/serving/v1 knative.dev/serving/pkg/client/listers/serving/v1alpha1 knative.dev/serving/pkg/client/listers/serving/v1beta1 -# knative.dev/test-infra v0.0.0-20200623005026-1f7e5f05c52b +# knative.dev/test-infra v0.0.0-20200623184427-74a5e5b3bd23 ## explicit knative.dev/test-infra/scripts # sigs.k8s.io/yaml v1.2.0 => sigs.k8s.io/yaml v1.1.0