diff --git a/Gopkg.lock b/Gopkg.lock index 2f8d804cf71..ec64693600a 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -1327,6 +1327,8 @@ "client/injection/kube/informers/admissionregistration/v1beta1/validatingwebhookconfiguration", "client/injection/kube/informers/apps/v1/deployment", "client/injection/kube/informers/apps/v1/deployment/fake", + "client/injection/kube/informers/core/v1/configmap", + "client/injection/kube/informers/core/v1/configmap/fake", "client/injection/kube/informers/core/v1/endpoints", "client/injection/kube/informers/core/v1/endpoints/fake", "client/injection/kube/informers/core/v1/namespace", @@ -1532,6 +1534,8 @@ "knative.dev/pkg/client/injection/kube/client/fake", "knative.dev/pkg/client/injection/kube/informers/apps/v1/deployment", "knative.dev/pkg/client/injection/kube/informers/apps/v1/deployment/fake", + "knative.dev/pkg/client/injection/kube/informers/core/v1/configmap", + "knative.dev/pkg/client/injection/kube/informers/core/v1/configmap/fake", "knative.dev/pkg/client/injection/kube/informers/core/v1/endpoints", "knative.dev/pkg/client/injection/kube/informers/core/v1/endpoints/fake", "knative.dev/pkg/client/injection/kube/informers/core/v1/namespace", @@ -1560,6 +1564,7 @@ "knative.dev/pkg/metrics/metricstest", "knative.dev/pkg/metrics/testing", "knative.dev/pkg/profiling", + "knative.dev/pkg/ptr", "knative.dev/pkg/reconciler/testing", "knative.dev/pkg/resolver", "knative.dev/pkg/signals", diff --git a/cmd/broker/config.go b/cmd/broker/config.go new file mode 100644 index 00000000000..89d5454e1b2 --- /dev/null +++ b/cmd/broker/config.go @@ -0,0 +1,38 @@ +/* + * Copyright 2019 The Knative Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package broker + +import ( + "context" + + apierrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + kubeclient "knative.dev/pkg/client/injection/kube/client" + "knative.dev/pkg/logging" +) + +// GetLoggingConfig will get config from a specific namespace +func GetLoggingConfig(ctx context.Context, namespace, loggingConfigMapName string) (*logging.Config, error) { + loggingConfigMap, err := kubeclient.Get(ctx).CoreV1().ConfigMaps(namespace).Get(loggingConfigMapName, metav1.GetOptions{}) + if apierrors.IsNotFound(err) { + return logging.NewConfigFromMap(nil) + } else if err != nil { + return nil, err + } + return logging.NewConfigFromConfigMap(loggingConfigMap) +} diff --git a/cmd/broker/filter/main.go b/cmd/broker/filter/main.go index f0ede0c40ac..86ecf1e7584 100644 --- a/cmd/broker/filter/main.go +++ b/cmd/broker/filter/main.go @@ -25,6 +25,11 @@ import ( "go.opencensus.io/stats/view" "go.uber.org/zap" + "knative.dev/eventing/cmd/broker" + "knative.dev/eventing/pkg/broker/filter" + cmpresources "knative.dev/eventing/pkg/reconciler/configmappropagation/resources" + namespaceresources "knative.dev/eventing/pkg/reconciler/namespace/resources" + "knative.dev/eventing/pkg/tracing" kubeclient "knative.dev/pkg/client/injection/kube/client" "knative.dev/pkg/configmap" "knative.dev/pkg/controller" @@ -32,10 +37,7 @@ import ( "knative.dev/pkg/logging" "knative.dev/pkg/metrics" "knative.dev/pkg/signals" - "knative.dev/pkg/system" - - "knative.dev/eventing/pkg/broker/filter" - "knative.dev/eventing/pkg/tracing" + tracingconfig "knative.dev/pkg/tracing/config" "knative.dev/pkg/injection/sharedmain" @@ -77,10 +79,18 @@ func main() { log.Fatal("Error building kubeconfig", err) } + var env envConfig + if err := envconfig.Process("", &env); err != nil { + log.Fatal("Failed to process env var", zap.Error(err)) + } + ctx, _ = injection.Default.SetupInformers(ctx, cfg) kubeClient := kubeclient.Get(ctx) - loggingConfig, err := sharedmain.GetLoggingConfig(ctx) + loggingConfigMapName := cmpresources.MakeCopyConfigMapName(namespaceresources.DefaultConfigMapPropagationName, logging.ConfigMapName()) + metricsConfigMapName := cmpresources.MakeCopyConfigMapName(namespaceresources.DefaultConfigMapPropagationName, metrics.ConfigMapName()) + + loggingConfig, err := broker.GetLoggingConfig(ctx, env.Namespace, loggingConfigMapName) if err != nil { log.Fatal("Error loading/parsing logging configuration:", err) } @@ -90,11 +100,6 @@ func main() { logger.Info("Starting the Broker Filter") - var env envConfig - if err := envconfig.Process("", &env); err != nil { - logger.Fatal("Failed to process env var", zap.Error(err)) - } - eventingClient := eventingv1alpha1.NewForConfigOrDie(cfg) eventingFactory := eventinginformers.NewSharedInformerFactoryWithOptions(eventingClient, controller.GetResyncPeriod(ctx), @@ -102,7 +107,7 @@ func main() { triggerInformer := eventingFactory.Eventing().V1alpha1().Triggers() // Watch the logging config map and dynamically update logging levels. - configMapWatcher := configmap.NewInformedWatcher(kubeClient, system.Namespace()) + configMapWatcher := configmap.NewInformedWatcher(kubeClient, env.Namespace) // Watch the observability config map and dynamically update metrics exporter. updateFunc, err := metrics.UpdateExporterFromConfigMapWithOpts(metrics.ExporterOptions{ Component: component, @@ -111,16 +116,17 @@ func main() { if err != nil { logger.Fatal("Failed to create metrics exporter update function", zap.Error(err)) } - configMapWatcher.Watch(metrics.ConfigMapName(), updateFunc) + configMapWatcher.Watch(metricsConfigMapName, updateFunc) // TODO change the component name to broker once Stackdriver metrics are approved. // Watch the observability config map and dynamically update request logs. - configMapWatcher.Watch(logging.ConfigMapName(), logging.UpdateLevelFromConfigMap(sl, atomicLevel, component)) + configMapWatcher.Watch(loggingConfigMapName, logging.UpdateLevelFromConfigMap(sl, atomicLevel, component)) bin := tracing.BrokerFilterName(tracing.BrokerFilterNameArgs{ Namespace: env.Namespace, BrokerName: env.Broker, }) - if err = tracing.SetupDynamicPublishing(sl, configMapWatcher, bin); err != nil { + if err = tracing.SetupDynamicPublishing(sl, configMapWatcher, bin, + cmpresources.MakeCopyConfigMapName(namespaceresources.DefaultConfigMapPropagationName, tracingconfig.ConfigName)); err != nil { logger.Fatal("Error setting up trace publishing", zap.Error(err)) } diff --git a/cmd/broker/ingress/main.go b/cmd/broker/ingress/main.go index ea969a1cbee..8cf66b5dfc4 100644 --- a/cmd/broker/ingress/main.go +++ b/cmd/broker/ingress/main.go @@ -31,9 +31,12 @@ import ( "go.opencensus.io/stats/view" "go.uber.org/zap" + cmdbroker "knative.dev/eventing/cmd/broker" "knative.dev/eventing/pkg/broker" "knative.dev/eventing/pkg/broker/ingress" "knative.dev/eventing/pkg/kncloudevents" + cmpresources "knative.dev/eventing/pkg/reconciler/configmappropagation/resources" + namespaceresources "knative.dev/eventing/pkg/reconciler/namespace/resources" "knative.dev/eventing/pkg/tracing" kubeclient "knative.dev/pkg/client/injection/kube/client" "knative.dev/pkg/configmap" @@ -43,8 +46,8 @@ import ( "knative.dev/pkg/logging" "knative.dev/pkg/metrics" "knative.dev/pkg/signals" - "knative.dev/pkg/system" pkgtracing "knative.dev/pkg/tracing" + tracingconfig "knative.dev/pkg/tracing/config" ) var ( @@ -91,13 +94,21 @@ func main() { log.Fatal("Error building kubeconfig", err) } + var env envConfig + if err := envconfig.Process("", &env); err != nil { + log.Fatal("Failed to process env var", zap.Error(err)) + } + log.Printf("Registering %d clients", len(injection.Default.GetClients())) log.Printf("Registering %d informer factories", len(injection.Default.GetInformerFactories())) log.Printf("Registering %d informers", len(injection.Default.GetInformers())) ctx, informers := injection.Default.SetupInformers(ctx, cfg) - loggingConfig, err := sharedmain.GetLoggingConfig(ctx) + loggingConfigMapName := cmpresources.MakeCopyConfigMapName(namespaceresources.DefaultConfigMapPropagationName, logging.ConfigMapName()) + metricsConfigMapName := cmpresources.MakeCopyConfigMapName(namespaceresources.DefaultConfigMapPropagationName, metrics.ConfigMapName()) + + loggingConfig, err := cmdbroker.GetLoggingConfig(ctx, env.Namespace, loggingConfigMapName) if err != nil { log.Fatal("Error loading/parsing logging configuration:", err) } @@ -107,11 +118,6 @@ func main() { logger.Info("Starting the Broker Ingress") - var env envConfig - if err := envconfig.Process("", &env); err != nil { - logger.Fatal("Failed to process env var", zap.Error(err)) - } - channelURI := &url.URL{ Scheme: "http", Host: env.Channel, @@ -119,7 +125,7 @@ func main() { } // Watch the logging config map and dynamically update logging levels. - configMapWatcher := configmap.NewInformedWatcher(kubeclient.Get(ctx), system.Namespace()) + configMapWatcher := configmap.NewInformedWatcher(kubeclient.Get(ctx), env.Namespace) // Watch the observability config map and dynamically update metrics exporter. updateFunc, err := metrics.UpdateExporterFromConfigMapWithOpts(metrics.ExporterOptions{ Component: component, @@ -128,16 +134,17 @@ func main() { if err != nil { logger.Fatal("Failed to create metrics exporter update function", zap.Error(err)) } - configMapWatcher.Watch(metrics.ConfigMapName(), updateFunc) + configMapWatcher.Watch(metricsConfigMapName, updateFunc) // TODO change the component name to broker once Stackdriver metrics are approved. // Watch the observability config map and dynamically update request logs. - configMapWatcher.Watch(logging.ConfigMapName(), logging.UpdateLevelFromConfigMap(sl, atomicLevel, component)) + configMapWatcher.Watch(loggingConfigMapName, logging.UpdateLevelFromConfigMap(sl, atomicLevel, component)) bin := tracing.BrokerIngressName(tracing.BrokerIngressNameArgs{ Namespace: env.Namespace, BrokerName: env.Broker, }) - if err = tracing.SetupDynamicPublishing(sl, configMapWatcher, bin); err != nil { + if err = tracing.SetupDynamicPublishing(sl, configMapWatcher, bin, + cmpresources.MakeCopyConfigMapName(namespaceresources.DefaultConfigMapPropagationName, tracingconfig.ConfigName)); err != nil { logger.Fatal("Error setting up trace publishing", zap.Error(err)) } diff --git a/cmd/controller/main.go b/cmd/controller/main.go index 54dca64b957..118e65f211c 100644 --- a/cmd/controller/main.go +++ b/cmd/controller/main.go @@ -25,6 +25,7 @@ import ( "knative.dev/eventing/pkg/reconciler/apiserversource" "knative.dev/eventing/pkg/reconciler/broker" "knative.dev/eventing/pkg/reconciler/channel" + "knative.dev/eventing/pkg/reconciler/configmappropagation" "knative.dev/eventing/pkg/reconciler/eventtype" "knative.dev/eventing/pkg/reconciler/legacyapiserversource" "knative.dev/eventing/pkg/reconciler/legacycontainersource" @@ -51,6 +52,7 @@ func main() { // Flows parallel.NewController, + configmappropagation.NewController, sequence.NewController, // Sources diff --git a/cmd/webhook/main.go b/cmd/webhook/main.go index fb972f6d9fc..c5b22ad636f 100644 --- a/cmd/webhook/main.go +++ b/cmd/webhook/main.go @@ -23,6 +23,7 @@ import ( "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/types" + configsv1alpha1 "knative.dev/eventing/pkg/apis/configs/v1alpha1" eventingduckv1alpha1 "knative.dev/eventing/pkg/apis/duck/v1alpha1" eventingv1alpha1 "knative.dev/eventing/pkg/apis/eventing/v1alpha1" flowsv1alpha1 "knative.dev/eventing/pkg/apis/flows/v1alpha1" @@ -73,6 +74,9 @@ var ourTypes = map[schema.GroupVersionKind]resourcesemantics.GenericCRD{ // For group flows.knative.dev flowsv1alpha1.SchemeGroupVersion.WithKind("Parallel"): &flowsv1alpha1.Parallel{}, flowsv1alpha1.SchemeGroupVersion.WithKind("Sequence"): &flowsv1alpha1.Sequence{}, + + // For group configs.knative.dev + configsv1alpha1.SchemeGroupVersion.WithKind("ConfigMapPropagation"): &configsv1alpha1.ConfigMapPropagation{}, } func NewDefaultingAdmissionController(ctx context.Context, cmw configmap.Watcher) *controller.Impl { diff --git a/config/300-configmappropagation.yaml b/config/300-configmappropagation.yaml new file mode 120000 index 00000000000..cba754c58ea --- /dev/null +++ b/config/300-configmappropagation.yaml @@ -0,0 +1 @@ +core/resources/configmappropagation.yaml \ No newline at end of file diff --git a/config/core/configmaps/logging.yaml b/config/core/configmaps/logging.yaml index c65449a6ebb..a43deb49e86 100644 --- a/config/core/configmaps/logging.yaml +++ b/config/core/configmaps/logging.yaml @@ -19,6 +19,8 @@ metadata: namespace: knative-eventing labels: eventing.knative.dev/release: devel + knative.dev/config-propagation: original + knative.dev/config-category: eventing data: # Common configuration for all Knative codebase zap-logger-config: | diff --git a/config/core/configmaps/observability.yaml b/config/core/configmaps/observability.yaml index 6f5b114afc8..df9f5d4a5e4 100644 --- a/config/core/configmaps/observability.yaml +++ b/config/core/configmaps/observability.yaml @@ -19,6 +19,8 @@ metadata: namespace: knative-eventing labels: eventing.knative.dev/release: devel + knative.dev/config-propagation: original + knative.dev/config-category: eventing data: _example: | ################################ diff --git a/config/core/configmaps/tracing.yaml b/config/core/configmaps/tracing.yaml index ac03d87cbd9..06fd6710b04 100644 --- a/config/core/configmaps/tracing.yaml +++ b/config/core/configmaps/tracing.yaml @@ -19,6 +19,8 @@ metadata: namespace: knative-eventing labels: eventing.knative.dev/release: devel + knative.dev/config-propagation: original + knative.dev/config-category: eventing data: _example: | ################################ diff --git a/config/core/resources/configmappropagation.yaml b/config/core/resources/configmappropagation.yaml new file mode 100644 index 00000000000..714a2eed36e --- /dev/null +++ b/config/core/resources/configmappropagation.yaml @@ -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. + +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + name: configmappropagations.configs.internal.knative.dev + labels: + eventing.knative.dev/release: devel + knative.dev/crd-install: "true" +spec: + group: configs.internal.knative.dev + versions: + - name: v1alpha1 + served: true + storage: true + names: + kind: ConfigMapPropagation + plural: configmappropagations + singular: configmappropagation + categories: + - all + - knative + - eventing + shortNames: + - kcmp + - cmp + scope: Namespaced + subresources: + status: {} + additionalPrinterColumns: + - name: Ready + type: string + JSONPath: ".status.conditions[?(@.type==\"Ready\")].status" + - name: Reason + type: string + JSONPath: ".status.conditions[?(@.type==\"Ready\")].reason" + - name: OriginalNamespace + type: string + JSONPath: ".spec.originalNamespace" + validation: + openAPIV3Schema: + properties: + spec: + required: + - originalNamespace + properties: + originalNamespace: + type: string + description: "The namespace where original ConfigMaps exist in." diff --git a/config/core/roles/controller-clusterroles.yaml b/config/core/roles/controller-clusterroles.yaml index eb97da57e94..a8b3436bbcd 100644 --- a/config/core/roles/controller-clusterroles.yaml +++ b/config/core/roles/controller-clusterroles.yaml @@ -96,6 +96,14 @@ rules: - "parallels/status" verbs: *everything + # Configs resources and status we care about. + - apiGroups: + - "configs.internal.knative.dev" + resources: + - "configmappropagations" + - "configmappropagations/status" + verbs: *everything + # Messaging resources and finalizers we care about. - apiGroups: - "messaging.knative.dev" diff --git a/hack/update-codegen.sh b/hack/update-codegen.sh index b5d57c1eaf4..00ddd9574eb 100755 --- a/hack/update-codegen.sh +++ b/hack/update-codegen.sh @@ -30,7 +30,7 @@ KNATIVE_CODEGEN_PKG=${KNATIVE_CODEGEN_PKG:-$(cd ${REPO_ROOT_DIR}; ls -d -1 $(dir # instead of the $GOPATH directly. For normal projects this can be dropped. ${CODEGEN_PKG}/generate-groups.sh "deepcopy,client,informer,lister" \ knative.dev/eventing/pkg/client knative.dev/eventing/pkg/apis \ - "eventing:v1alpha1 eventing:v1beta1 messaging:v1alpha1 messaging:v1beta1 flows:v1alpha1 flows:v1beta1 sources:v1alpha1" \ + "eventing:v1alpha1 eventing:v1beta1 messaging:v1alpha1 messaging:v1beta1 flows:v1alpha1 flows:v1beta1 sources:v1alpha1 configs:v1alpha1" \ --go-header-file ${REPO_ROOT_DIR}/hack/boilerplate/boilerplate.go.txt # TODO(#2312): Remove this after v0.13. @@ -48,7 +48,7 @@ ${CODEGEN_PKG}/generate-groups.sh "deepcopy" \ # Knative Injection ${KNATIVE_CODEGEN_PKG}/hack/generate-knative.sh "injection" \ knative.dev/eventing/pkg/client knative.dev/eventing/pkg/apis \ - "eventing:v1alpha1 eventing:v1beta1 messaging:v1alpha1 messaging:v1beta1 flows:v1alpha1 flows:v1beta1 sources:v1alpha1 duck:v1alpha1 duck:v1beta1" \ + "eventing:v1alpha1 eventing:v1beta1 messaging:v1alpha1 messaging:v1beta1 flows:v1alpha1 flows:v1beta1 sources:v1alpha1 duck:v1alpha1 duck:v1beta1 configs:v1alpha1" \ --go-header-file ${REPO_ROOT_DIR}/hack/boilerplate/boilerplate.go.txt # TODO(#2312): Remove this after v0.13. diff --git a/pkg/apis/configs/register.go b/pkg/apis/configs/register.go new file mode 100644 index 00000000000..77becd24253 --- /dev/null +++ b/pkg/apis/configs/register.go @@ -0,0 +1,21 @@ +/* +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 configs + +const ( + GroupName = "configs.internal.knative.dev" +) diff --git a/pkg/apis/configs/v1alpha1/configmappropagation_defaults.go b/pkg/apis/configs/v1alpha1/configmappropagation_defaults.go new file mode 100644 index 00000000000..09942e9e4a1 --- /dev/null +++ b/pkg/apis/configs/v1alpha1/configmappropagation_defaults.go @@ -0,0 +1,30 @@ +/* +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 v1alpha1 + +import ( + "context" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +func (cmp *ConfigMapPropagation) SetDefaults(ctx context.Context) { + // If we haven't configured the selector, + // then set the default selector to be an empty map + if cmp != nil && cmp.Spec.Selector == nil { + cmp.Spec.Selector = &metav1.LabelSelector{} + } +} diff --git a/pkg/apis/configs/v1alpha1/configmappropagation_defaults_test.go b/pkg/apis/configs/v1alpha1/configmappropagation_defaults_test.go new file mode 100644 index 00000000000..cef3e1837ed --- /dev/null +++ b/pkg/apis/configs/v1alpha1/configmappropagation_defaults_test.go @@ -0,0 +1,60 @@ +/* +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 v1alpha1 + +import ( + "context" + "testing" + + "github.com/google/go-cmp/cmp" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +var ( + namespace = "testing-eventing" + defaultSelector = metav1.LabelSelector{} + otherSelector = metav1.LabelSelector{MatchLabels: map[string]string{"testing": "testing"}} +) + +func TestConfigMapPropagationDefaults(t *testing.T) { + testCases := map[string]struct { + initial ConfigMapPropagation + expected ConfigMapPropagation + }{ + "nil spec": { + initial: ConfigMapPropagation{}, + expected: ConfigMapPropagation{Spec: ConfigMapPropagationSpec{Selector: &defaultSelector}}, + }, + "selector empty": { + initial: ConfigMapPropagation{Spec: ConfigMapPropagationSpec{OriginalNamespace: namespace}}, + expected: ConfigMapPropagation{Spec: ConfigMapPropagationSpec{OriginalNamespace: namespace, Selector: &defaultSelector}}, + }, + "with selector": { + initial: ConfigMapPropagation{Spec: ConfigMapPropagationSpec{Selector: &otherSelector}}, + expected: ConfigMapPropagation{Spec: ConfigMapPropagationSpec{Selector: &otherSelector}}, + }, + } + for n, tc := range testCases { + t.Run(n, func(t *testing.T) { + tc.initial.SetDefaults(context.Background()) + if diff := cmp.Diff(tc.expected, tc.initial); diff != "" { + t.Errorf("Unexpected defaults (-want, +got): %s", diff) + } + }) + } +} diff --git a/pkg/apis/configs/v1alpha1/configmappropagation_lifecycle.go b/pkg/apis/configs/v1alpha1/configmappropagation_lifecycle.go new file mode 100644 index 00000000000..b87cdbdd66a --- /dev/null +++ b/pkg/apis/configs/v1alpha1/configmappropagation_lifecycle.go @@ -0,0 +1,63 @@ +/* +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 v1alpha1 + +import ( + "knative.dev/pkg/apis" +) + +var configMapPropagationCondSet = apis.NewLivingConditionSet(ConfigMapPropagationConditionReady, ConfigMapPropagationConditionPropagated) + +const ( + // ConfigMapPropagationConditionReady has status True when all subconditions below have been set to True. + ConfigMapPropagationConditionReady = apis.ConditionReady + // ConfigMapPropagationConditionPropagated has status True when the ConfigMaps in original namespace are all propagated to target namespace. + ConfigMapPropagationConditionPropagated apis.ConditionType = "Propagated" +) + +// GetCondition returns the condition currently associated with the given type, or nil. +func (cmps *ConfigMapPropagationStatus) GetCondition(t apis.ConditionType) *apis.Condition { + return configMapPropagationCondSet.Manage(cmps).GetCondition(t) +} + +// IsReady returns true if the resource is ready overall. +func (cmps *ConfigMapPropagationStatus) IsReady() bool { + return configMapPropagationCondSet.Manage(cmps).IsHappy() +} + +// InitializeConditions sets relevant unset conditions to Unknown state. +func (cmps *ConfigMapPropagationStatus) InitializeConditions() { + configMapPropagationCondSet.Manage(cmps).InitializeConditions() +} + +func (cmps *ConfigMapPropagationStatus) MarkPropagated() { + configMapPropagationCondSet.Manage(cmps).MarkTrue(ConfigMapPropagationConditionPropagated) +} + +func (cmps *ConfigMapPropagationStatus) MarkNotPropagated() { + configMapPropagationCondSet.Manage(cmps).MarkFalse(ConfigMapPropagationConditionPropagated, "PropagationFailed", + "ConfigMapPropagation could not fully propagate ConfigMaps from original namespace to current namespace") +} + +func (cmpsc *ConfigMapPropagationStatusCopyConfigMap) SetCopyConfigMapStatus(name, source, operation, ready, reason, resourceVersion string) { + cmpsc.Name = name + cmpsc.Source = source + cmpsc.Operation = operation + cmpsc.Ready = ready + cmpsc.Reason = reason + cmpsc.ResourceVersion = resourceVersion +} diff --git a/pkg/apis/configs/v1alpha1/configmappropagation_lifecycle_test.go b/pkg/apis/configs/v1alpha1/configmappropagation_lifecycle_test.go new file mode 100644 index 00000000000..4c0ff73ca39 --- /dev/null +++ b/pkg/apis/configs/v1alpha1/configmappropagation_lifecycle_test.go @@ -0,0 +1,224 @@ +/* +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 v1alpha1 + +import ( + "reflect" + "testing" + + "github.com/google/go-cmp/cmp" + "github.com/google/go-cmp/cmp/cmpopts" + + corev1 "k8s.io/api/core/v1" + + "knative.dev/pkg/apis" + duckv1 "knative.dev/pkg/apis/duck/v1" + "knative.dev/pkg/ptr" +) + +var ignoreAllButTypeAndStatus = cmpopts.IgnoreFields( + apis.Condition{}, + "LastTransitionTime", "Message", "Reason", "Severity") + +var ( + configMapPropagationConditionReady = apis.Condition{ + Type: ConfigMapPropagationConditionReady, + Status: corev1.ConditionTrue, + } + + configMapPropagationConditionPropagated = apis.Condition{ + Type: ConfigMapPropagationConditionPropagated, + Status: corev1.ConditionTrue, + } +) + +func TestConfigMapPropagationGetCondition(t *testing.T) { + tests := []struct { + name string + cmps *ConfigMapPropagationStatus + condQuery apis.ConditionType + want *apis.Condition + }{{ + name: "single condition", + cmps: &ConfigMapPropagationStatus{ + Status: duckv1.Status{ + Conditions: []apis.Condition{ + configMapPropagationConditionReady, + }, + }, + }, + condQuery: apis.ConditionReady, + want: &configMapPropagationConditionReady, + }, { + name: "multiple conditions", + cmps: &ConfigMapPropagationStatus{ + Status: duckv1.Status{ + Conditions: []apis.Condition{ + configMapPropagationConditionPropagated, + }, + }, + }, + condQuery: ConfigMapPropagationConditionPropagated, + want: &configMapPropagationConditionPropagated, + }, { + name: "unknown condition", + cmps: &ConfigMapPropagationStatus{ + Status: duckv1.Status{ + Conditions: []apis.Condition{ + configMapPropagationConditionPropagated, + }, + }, + }, + condQuery: apis.ConditionType("foo"), + want: nil, + }} + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got := test.cmps.GetCondition(test.condQuery) + if diff := cmp.Diff(test.want, got); diff != "" { + t.Errorf("unexpected condition (-want, +got) = %v", diff) + } + }) + } +} + +func TestConfigMapPropagationInitializeConditions(t *testing.T) { + tests := []struct { + name string + cmps *ConfigMapPropagationStatus + want *ConfigMapPropagationStatus + }{{ + name: "empty", + cmps: &ConfigMapPropagationStatus{}, + want: &ConfigMapPropagationStatus{ + Status: duckv1.Status{ + Conditions: []apis.Condition{{ + Type: ConfigMapPropagationConditionPropagated, + Status: corev1.ConditionUnknown, + }, { + Type: ConfigMapPropagationConditionReady, + Status: corev1.ConditionUnknown, + }}, + }, + }, + }, { + name: "one false", + cmps: &ConfigMapPropagationStatus{ + Status: duckv1.Status{ + Conditions: []apis.Condition{{ + Type: ConfigMapPropagationConditionPropagated, + Status: corev1.ConditionFalse, + }}, + }, + }, + want: &ConfigMapPropagationStatus{ + Status: duckv1.Status{ + Conditions: []apis.Condition{{ + Type: ConfigMapPropagationConditionPropagated, + Status: corev1.ConditionFalse, + }, { + Type: ConfigMapPropagationConditionReady, + Status: corev1.ConditionUnknown, + }}, + }, + }, + }, { + name: "one true", + cmps: &ConfigMapPropagationStatus{ + Status: duckv1.Status{ + Conditions: []apis.Condition{{ + Type: ConfigMapPropagationConditionPropagated, + Status: corev1.ConditionTrue, + }}, + }, + }, + want: &ConfigMapPropagationStatus{ + Status: duckv1.Status{ + Conditions: []apis.Condition{{ + Type: ConfigMapPropagationConditionPropagated, + Status: corev1.ConditionTrue, + }, { + Type: ConfigMapPropagationConditionReady, + Status: corev1.ConditionUnknown, + }}, + }, + }, + }} + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + test.cmps.InitializeConditions() + if diff := cmp.Diff(test.want, test.cmps, ignoreAllButTypeAndStatus); diff != "" { + t.Errorf("unexpected conditions (-want, +got) = %v", diff) + } + }) + } +} + +func TestConfigMapPropagationIsReady(t *testing.T) { + tests := []struct { + name string + markPropagation *bool + wantReady bool + }{{ + name: "all happy", + markPropagation: ptr.Bool(true), + wantReady: true, + }, { + name: "propagation sad", + markPropagation: ptr.Bool(false), + wantReady: false, + }} + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + cmps := &ConfigMapPropagationStatus{} + if test.markPropagation != nil { + if *test.markPropagation { + cmps.MarkPropagated() + } else { + cmps.MarkNotPropagated() + } + } + if got := cmps.IsReady(); test.wantReady != got { + t.Errorf("unexpected readiness: want %v, got %v", test.wantReady, got) + } + }) + } +} + +func TestSetCopyConfigMapStatus(t *testing.T) { + tests := []struct { + name string + cmpsc *ConfigMapPropagationStatusCopyConfigMap + want *ConfigMapPropagationStatusCopyConfigMap + }{{ + name: "all happy", + cmpsc: &ConfigMapPropagationStatusCopyConfigMap{}, + want: &ConfigMapPropagationStatusCopyConfigMap{ + "name", "source", "operation", "ready", "reason", "resourceVersion", + }, + }} + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + test.cmpsc.SetCopyConfigMapStatus("name", "source", "operation", "ready", "reason", "resourceVersion") + if got := test.cmpsc; !reflect.DeepEqual(test.want, got) { + t.Errorf("unexpected readiness: want %v, got %v", test.want, got) + } + }) + } +} diff --git a/pkg/apis/configs/v1alpha1/configmappropagation_types.go b/pkg/apis/configs/v1alpha1/configmappropagation_types.go new file mode 100644 index 00000000000..7df9db31825 --- /dev/null +++ b/pkg/apis/configs/v1alpha1/configmappropagation_types.go @@ -0,0 +1,123 @@ +/* +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 v1alpha1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "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" +) + +// +genclient +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// ConfigMapPropagation is used to propagate configMaps from original namespace to current namespace +type ConfigMapPropagation struct { + metav1.TypeMeta `json:",inline"` + // +optional + metav1.ObjectMeta `json:"metadata,omitempty"` + + // Spec defines the desired state of the ConfigMapPropagation + Spec ConfigMapPropagationSpec `json:"spec,omitempty"` + + // Status represents the current state of the EventType. + // This data may be out of date. + // +optional + Status ConfigMapPropagationStatus `json:"status,omitempty"` +} + +var ( + // Check that ConfigMapPropagation can be validated, can be defaulted, and has immutable fields. + _ apis.Validatable = (*ConfigMapPropagation)(nil) + _ apis.Defaultable = (*ConfigMapPropagation)(nil) + + // Check that ConfigMapPropagation can return its spec untyped. + _ apis.HasSpec = (*ConfigMapPropagation)(nil) + + _ runtime.Object = (*ConfigMapPropagation)(nil) + + // Check that we can create OwnerReferences to a ConfigMapPropagation. + _ kmeta.OwnerRefable = (*ConfigMapPropagation)(nil) +) + +type ConfigMapPropagationSpec struct { + // OriginalNamespace is the namespace where the original configMaps are in + OriginalNamespace string `json:"originalNamespace,omitempty"` + // Selector only selects original configMaps with corresponding labels + // +optional + Selector *metav1.LabelSelector `json:"selector,omitempty"` +} + +// ConfigMapPropagationStatus represents the current state of a ConfigMapPropagation. +type ConfigMapPropagationStatus struct { + // inherits duck/v1 Status, which currently provides: + // * ObservedGeneration - the 'Generation' of the Service that was last processed by the controller. + // * Conditions - the latest available observations of a resource's current state. + duckv1.Status `json:",inline"` + + //CopyConfigMaps is the status for each copied configmap. + // +optional + // +patchMergeKey=name + // +patchStrategy=merge + CopyConfigMaps []ConfigMapPropagationStatusCopyConfigMap `json:"copyConfigmaps" patchStrategy:"merge" patchMergeKey:"name"` +} + +// ConfigMapPropagationStatusCopyConfigMap represents the status of a copied configmap +type ConfigMapPropagationStatusCopyConfigMap struct { + // Name is copy configmap's name + // +required + Name string `json:"name,omitempty"` + + // Source is "originalNamespace/originalConfigMapName" + Source string `json:"source,omitempty"` + + // Operation represents the operation CMP takes for this configmap. The operations are copy|delete|stop + Operation string `json:"operation,omitempty"` + + // Ready represents the operation is ready or not + Ready string `json:"ready,omitempty"` + + // Reason indicates reasons if the operation is not ready + Reason string `json:"reason,omitempty"` + + // ResourceVersion is the resourceVersion of original configmap + ResourceVersion string `json:"resourceVersionFromSource,omitempty" protobuf:"bytes,6,opt,name=resourceVersion"` +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// ConfigMapPropagationList is a collection of ConfigMapPropagation. +type ConfigMapPropagationList struct { + metav1.TypeMeta `json:",inline"` + // +optional + metav1.ListMeta `json:"metadata,omitempty"` + Items []ConfigMapPropagation `json:"items"` +} + +// GetGroupVersionKind returns GroupVersionKind for ConfigMapPropagation +func (cmp *ConfigMapPropagation) GetGroupVersionKind() schema.GroupVersionKind { + return SchemeGroupVersion.WithKind("ConfigMapPropagation") +} + +// GetUntypedSpec returns the spec of the ConfigMapPropagation. +func (cmp *ConfigMapPropagation) GetUntypedSpec() interface{} { + return cmp.Spec +} diff --git a/pkg/apis/configs/v1alpha1/configmappropagation_types_test.go b/pkg/apis/configs/v1alpha1/configmappropagation_types_test.go new file mode 100644 index 00000000000..bd2d8285665 --- /dev/null +++ b/pkg/apis/configs/v1alpha1/configmappropagation_types_test.go @@ -0,0 +1,37 @@ +/* + * 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 v1alpha1 + +import ( + "reflect" + "testing" +) + +func TestConfigMapPropagation_GetGroupVersionKind(t *testing.T) { + cmp := ConfigMapPropagation{} + gvk := cmp.GetGroupVersionKind() + if gvk.Kind != "ConfigMapPropagation" { + t.Errorf("Should be ConfigMapPropagation.") + } +} +func TestConfigMapPropagation_GetUntypedSpec(t *testing.T) { + cmp := ConfigMapPropagation{} + in := cmp.GetUntypedSpec() + if !reflect.DeepEqual(in, cmp.Spec) { + t.Errorf("Should be ConfigMapPropagationSpec.") + } +} diff --git a/pkg/apis/configs/v1alpha1/configmappropagation_validation.go b/pkg/apis/configs/v1alpha1/configmappropagation_validation.go new file mode 100644 index 00000000000..aa08074b0c0 --- /dev/null +++ b/pkg/apis/configs/v1alpha1/configmappropagation_validation.go @@ -0,0 +1,93 @@ +/* +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 v1alpha1 + +import ( + "context" + "fmt" + "strings" + + "k8s.io/apimachinery/pkg/util/validation" + + "knative.dev/pkg/apis" + "knative.dev/pkg/kmp" +) + +// Validate the ConfigMapPropagation. +func (cmp *ConfigMapPropagation) Validate(ctx context.Context) *apis.FieldError { + return cmp.Spec.Validate(ctx).ViaField("spec") +} + +// Validate the ConfigMapPropagationSpec. +func (cmps *ConfigMapPropagationSpec) Validate(ctx context.Context) *apis.FieldError { + var errs *apis.FieldError + if cmps.OriginalNamespace == "" { + fe := apis.ErrMissingField("originalNamespace") + errs = errs.Also(fe) + } + + if cmps.Selector != nil { + for key, value := range cmps.Selector.MatchLabels { + if err := validation.IsQualifiedName(key); len(err) != 0 { + fe := &apis.FieldError{ + Message: fmt.Sprintf("Invalid selector matchLabels key: %v", key), + Paths: []string{"selector"}, + Details: strings.Join(err, "; "), + } + errs = errs.Also(fe) + } + if err := validation.IsValidLabelValue(value); len(err) != 0 { + fe := &apis.FieldError{ + Message: fmt.Sprintf("Invalid selector matchLabels value: %v", value), + Paths: []string{"selector"}, + Details: strings.Join(err, "; "), + } + errs = errs.Also(fe) + } + } + if cmps.Selector.MatchExpressions != nil { + fe := &apis.FieldError{ + Message: fmt.Sprintf("MatchExpressions isn't supported yet"), + Paths: []string{"selector"}, + } + errs = errs.Also(fe) + } + } + return errs +} + +// CheckImmutableFields checks that any immutable fields were not changed. +func (cmp *ConfigMapPropagation) CheckImmutableFields(ctx context.Context, original *ConfigMapPropagation) *apis.FieldError { + if original == nil { + return nil + } + + if diff, err := kmp.ShortDiff(original.Spec, cmp.Spec); err != nil { + return &apis.FieldError{ + Message: "Failed to diff ConfigMapPropagation", + Paths: []string{"spec"}, + Details: err.Error(), + } + } else if diff != "" { + return &apis.FieldError{ + Message: "Immutable fields changed (-old +new)", + Paths: []string{"spec"}, + Details: diff, + } + } + return nil +} diff --git a/pkg/apis/configs/v1alpha1/configmappropagation_validation_test.go b/pkg/apis/configs/v1alpha1/configmappropagation_validation_test.go new file mode 100644 index 00000000000..595e4fef725 --- /dev/null +++ b/pkg/apis/configs/v1alpha1/configmappropagation_validation_test.go @@ -0,0 +1,169 @@ +/* +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 v1alpha1 + +import ( + "context" + "testing" + + "github.com/google/go-cmp/cmp" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "knative.dev/pkg/apis" +) + +var ( + originalNamespace = "original" + currentNamespace = "current" + validSelector = metav1.LabelSelector{MatchLabels: map[string]string{"testing": "testing"}} +) + +func TestConfigMapPropagationValidation(t *testing.T) { + tests := []struct { + name string + cmp *ConfigMapPropagation + want *apis.FieldError + }{{ + name: "empty configmappropagation spec", + cmp: &ConfigMapPropagation{Spec: ConfigMapPropagationSpec{}}, + want: &apis.FieldError{ + Paths: []string{"spec.originalNamespace"}, + Message: "missing field(s)", + }, + }, + } + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got := test.cmp.Validate(context.Background()) + if diff := cmp.Diff(test.want.Error(), got.Error()); diff != "" { + t.Errorf("ConfigMapPropagation.Validate (-want, +got) = %v", diff) + } + }) + } +} + +func TestConfigMapPropagationSpecValidation(t *testing.T) { + tests := []struct { + name string + cmps *ConfigMapPropagationSpec + want *apis.FieldError + }{{ + name: "missing configmappropagation spec", + cmps: &ConfigMapPropagationSpec{}, + want: func() *apis.FieldError { + fe := apis.ErrMissingField("originalNamespace") + return fe + }(), + }, { + name: "missing original namespace", + cmps: &ConfigMapPropagationSpec{Selector: &validSelector}, + want: func() *apis.FieldError { + fe := apis.ErrMissingField("originalNamespace") + return fe + }(), + }, { + name: "invalid selector matchLabels key", + cmps: &ConfigMapPropagationSpec{ + OriginalNamespace: originalNamespace, + Selector: &metav1.LabelSelector{MatchLabels: map[string]string{"*nvalid": "testing"}}, + }, + want: &apis.FieldError{ + Message: `Invalid selector matchLabels key: *nvalid`, + Paths: []string{"selector"}, + Details: "name part must consist of alphanumeric characters, '-', '_' or '.', and must start and end with an alphanumeric character (e.g. 'MyName', or 'my.name', or '123-abc', regex used for validation is '([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9]')", + }, + }, { + name: "invalid selector matchLabels value", + cmps: &ConfigMapPropagationSpec{ + OriginalNamespace: originalNamespace, + Selector: &metav1.LabelSelector{MatchLabels: map[string]string{"invalid": "test/ing"}}}, + want: &apis.FieldError{ + Message: `Invalid selector matchLabels value: test/ing`, + Paths: []string{"selector"}, + Details: "a valid label must be an empty string or consist of alphanumeric characters, '-', '_' or '.', and must start and end with an alphanumeric character (e.g. 'MyValue', or 'my_value', or '12345', regex used for validation is '(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?')", + }, + }, { + name: "additional selector matchExpressions", + cmps: &ConfigMapPropagationSpec{ + OriginalNamespace: originalNamespace, + Selector: &metav1.LabelSelector{MatchExpressions: []metav1.LabelSelectorRequirement{}}}, + want: &apis.FieldError{ + Message: `MatchExpressions isn't supported yet`, + Paths: []string{"selector"}, + }, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got := test.cmps.Validate(context.Background()) + if diff := cmp.Diff(test.want.Error(), got.Error()); diff != "" { + t.Errorf("%s: Validate ConfigMapPropagationSpec (-want, +got) = %v", test.name, diff) + } + }) + } +} + +func TestConfigMapPropagationImmutableFields(t *testing.T) { + tests := []struct { + name string + current *ConfigMapPropagation + original *ConfigMapPropagation + want *apis.FieldError + }{{ + name: "good (no change)", + current: &ConfigMapPropagation{Spec: ConfigMapPropagationSpec{ + OriginalNamespace: currentNamespace, + }}, + original: &ConfigMapPropagation{Spec: ConfigMapPropagationSpec{ + OriginalNamespace: currentNamespace, + }}, + want: nil, + }, { + name: "new nil is ok", + current: &ConfigMapPropagation{Spec: ConfigMapPropagationSpec{ + OriginalNamespace: currentNamespace, + }}, + original: nil, + want: nil, + }, { + name: "bad (spec change)", + current: &ConfigMapPropagation{Spec: ConfigMapPropagationSpec{ + OriginalNamespace: currentNamespace, + }}, + original: &ConfigMapPropagation{Spec: ConfigMapPropagationSpec{ + OriginalNamespace: originalNamespace, + }}, + want: &apis.FieldError{ + Message: "Immutable fields changed (-old +new)", + Paths: []string{"spec"}, + Details: `{v1alpha1.ConfigMapPropagationSpec}.OriginalNamespace: + -: "original" + +: "current" +`, + }, + }} + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + gotErr := test.current.CheckImmutableFields(context.Background(), test.original) + if diff := cmp.Diff(test.want.Error(), gotErr.Error()); diff != "" { + t.Errorf("CheckImmutableFields (-want, +got) = %v", diff) + } + }) + } +} diff --git a/pkg/apis/configs/v1alpha1/doc.go b/pkg/apis/configs/v1alpha1/doc.go new file mode 100644 index 00000000000..4db3f84709e --- /dev/null +++ b/pkg/apis/configs/v1alpha1/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 v1alpha1 is the v1alpha1 version of the API. +// +k8s:deepcopy-gen=package +// +groupName=configs.internal.knative.dev +package v1alpha1 diff --git a/pkg/apis/configs/v1alpha1/register.go b/pkg/apis/configs/v1alpha1/register.go new file mode 100644 index 00000000000..0d4dcca50f1 --- /dev/null +++ b/pkg/apis/configs/v1alpha1/register.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 v1alpha1 + +import ( + "knative.dev/eventing/pkg/apis/configs" + + 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: configs.GroupName, Version: "v1alpha1"} + +// 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, + &ConfigMapPropagation{}, + &ConfigMapPropagationList{}, + ) + metav1.AddToGroupVersion(scheme, SchemeGroupVersion) + return nil +} diff --git a/pkg/apis/configs/v1alpha1/register_test.go b/pkg/apis/configs/v1alpha1/register_test.go new file mode 100644 index 00000000000..caf0af75ba7 --- /dev/null +++ b/pkg/apis/configs/v1alpha1/register_test.go @@ -0,0 +1,66 @@ +/* +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 v1alpha1 + +import ( + "testing" + + "github.com/google/go-cmp/cmp" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" +) + +// Resource takes an unqualified resource and returns a Group qualified GroupResource +func TestResource(t *testing.T) { + want := schema.GroupResource{ + Group: "configs.internal.knative.dev", + Resource: "foo", + } + + got := Resource("foo") + + if diff := cmp.Diff(want, got); diff != "" { + t.Errorf("unexpected resource (-want, +got) = %v", diff) + } +} + +// Kind takes an unqualified resource and returns a Group qualified GroupKind +func TestKind(t *testing.T) { + want := schema.GroupKind{ + Group: "configs.internal.knative.dev", + Kind: "kind", + } + + got := Kind("kind") + + if diff := cmp.Diff(want, got); diff != "" { + t.Errorf("unexpected resource (-want, +got) = %v", diff) + } +} + +// TestKnownTypes makes sure that expected types get added. +func TestKnownTypes(t *testing.T) { + scheme := runtime.NewScheme() + addKnownTypes(scheme) + types := scheme.KnownTypes(SchemeGroupVersion) + + for _, name := range []string{ + "ConfigMapPropagation", + "ConfigMapPropagationList", + } { + if _, ok := types[name]; !ok { + t.Errorf("Did not find %q as registered type", name) + } + } + +} diff --git a/pkg/apis/configs/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/configs/v1alpha1/zz_generated.deepcopy.go new file mode 100644 index 00000000000..f8dc4793f85 --- /dev/null +++ b/pkg/apis/configs/v1alpha1/zz_generated.deepcopy.go @@ -0,0 +1,146 @@ +// +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 v1alpha1 + +import ( + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ConfigMapPropagation) DeepCopyInto(out *ConfigMapPropagation) { + *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 ConfigMapPropagation. +func (in *ConfigMapPropagation) DeepCopy() *ConfigMapPropagation { + if in == nil { + return nil + } + out := new(ConfigMapPropagation) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *ConfigMapPropagation) 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 *ConfigMapPropagationList) DeepCopyInto(out *ConfigMapPropagationList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]ConfigMapPropagation, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ConfigMapPropagationList. +func (in *ConfigMapPropagationList) DeepCopy() *ConfigMapPropagationList { + if in == nil { + return nil + } + out := new(ConfigMapPropagationList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *ConfigMapPropagationList) 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 *ConfigMapPropagationSpec) DeepCopyInto(out *ConfigMapPropagationSpec) { + *out = *in + if in.Selector != nil { + in, out := &in.Selector, &out.Selector + *out = new(v1.LabelSelector) + (*in).DeepCopyInto(*out) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ConfigMapPropagationSpec. +func (in *ConfigMapPropagationSpec) DeepCopy() *ConfigMapPropagationSpec { + if in == nil { + return nil + } + out := new(ConfigMapPropagationSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ConfigMapPropagationStatus) DeepCopyInto(out *ConfigMapPropagationStatus) { + *out = *in + in.Status.DeepCopyInto(&out.Status) + if in.CopyConfigMaps != nil { + in, out := &in.CopyConfigMaps, &out.CopyConfigMaps + *out = make([]ConfigMapPropagationStatusCopyConfigMap, len(*in)) + copy(*out, *in) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ConfigMapPropagationStatus. +func (in *ConfigMapPropagationStatus) DeepCopy() *ConfigMapPropagationStatus { + if in == nil { + return nil + } + out := new(ConfigMapPropagationStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ConfigMapPropagationStatusCopyConfigMap) DeepCopyInto(out *ConfigMapPropagationStatusCopyConfigMap) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ConfigMapPropagationStatusCopyConfigMap. +func (in *ConfigMapPropagationStatusCopyConfigMap) DeepCopy() *ConfigMapPropagationStatusCopyConfigMap { + if in == nil { + return nil + } + out := new(ConfigMapPropagationStatusCopyConfigMap) + in.DeepCopyInto(out) + return out +} diff --git a/pkg/client/clientset/versioned/clientset.go b/pkg/client/clientset/versioned/clientset.go index f381655f3f0..53ea2c4d6a1 100644 --- a/pkg/client/clientset/versioned/clientset.go +++ b/pkg/client/clientset/versioned/clientset.go @@ -24,6 +24,7 @@ import ( discovery "k8s.io/client-go/discovery" rest "k8s.io/client-go/rest" flowcontrol "k8s.io/client-go/util/flowcontrol" + configsv1alpha1 "knative.dev/eventing/pkg/client/clientset/versioned/typed/configs/v1alpha1" eventingv1alpha1 "knative.dev/eventing/pkg/client/clientset/versioned/typed/eventing/v1alpha1" eventingv1beta1 "knative.dev/eventing/pkg/client/clientset/versioned/typed/eventing/v1beta1" flowsv1alpha1 "knative.dev/eventing/pkg/client/clientset/versioned/typed/flows/v1alpha1" @@ -35,6 +36,7 @@ import ( type Interface interface { Discovery() discovery.DiscoveryInterface + ConfigsV1alpha1() configsv1alpha1.ConfigsV1alpha1Interface EventingV1alpha1() eventingv1alpha1.EventingV1alpha1Interface EventingV1beta1() eventingv1beta1.EventingV1beta1Interface FlowsV1alpha1() flowsv1alpha1.FlowsV1alpha1Interface @@ -48,6 +50,7 @@ type Interface interface { // version included in a Clientset. type Clientset struct { *discovery.DiscoveryClient + configsV1alpha1 *configsv1alpha1.ConfigsV1alpha1Client eventingV1alpha1 *eventingv1alpha1.EventingV1alpha1Client eventingV1beta1 *eventingv1beta1.EventingV1beta1Client flowsV1alpha1 *flowsv1alpha1.FlowsV1alpha1Client @@ -57,6 +60,11 @@ type Clientset struct { sourcesV1alpha1 *sourcesv1alpha1.SourcesV1alpha1Client } +// ConfigsV1alpha1 retrieves the ConfigsV1alpha1Client +func (c *Clientset) ConfigsV1alpha1() configsv1alpha1.ConfigsV1alpha1Interface { + return c.configsV1alpha1 +} + // EventingV1alpha1 retrieves the EventingV1alpha1Client func (c *Clientset) EventingV1alpha1() eventingv1alpha1.EventingV1alpha1Interface { return c.eventingV1alpha1 @@ -113,6 +121,10 @@ func NewForConfig(c *rest.Config) (*Clientset, error) { } var cs Clientset var err error + cs.configsV1alpha1, err = configsv1alpha1.NewForConfig(&configShallowCopy) + if err != nil { + return nil, err + } cs.eventingV1alpha1, err = eventingv1alpha1.NewForConfig(&configShallowCopy) if err != nil { return nil, err @@ -153,6 +165,7 @@ func NewForConfig(c *rest.Config) (*Clientset, error) { // panics if there is an error in the config. func NewForConfigOrDie(c *rest.Config) *Clientset { var cs Clientset + cs.configsV1alpha1 = configsv1alpha1.NewForConfigOrDie(c) cs.eventingV1alpha1 = eventingv1alpha1.NewForConfigOrDie(c) cs.eventingV1beta1 = eventingv1beta1.NewForConfigOrDie(c) cs.flowsV1alpha1 = flowsv1alpha1.NewForConfigOrDie(c) @@ -168,6 +181,7 @@ func NewForConfigOrDie(c *rest.Config) *Clientset { // New creates a new Clientset for the given RESTClient. func New(c rest.Interface) *Clientset { var cs Clientset + cs.configsV1alpha1 = configsv1alpha1.New(c) cs.eventingV1alpha1 = eventingv1alpha1.New(c) cs.eventingV1beta1 = eventingv1beta1.New(c) cs.flowsV1alpha1 = flowsv1alpha1.New(c) diff --git a/pkg/client/clientset/versioned/fake/clientset_generated.go b/pkg/client/clientset/versioned/fake/clientset_generated.go index 7d8ad986992..e3652ab439a 100644 --- a/pkg/client/clientset/versioned/fake/clientset_generated.go +++ b/pkg/client/clientset/versioned/fake/clientset_generated.go @@ -25,6 +25,8 @@ import ( fakediscovery "k8s.io/client-go/discovery/fake" "k8s.io/client-go/testing" 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" eventingv1alpha1 "knative.dev/eventing/pkg/client/clientset/versioned/typed/eventing/v1alpha1" fakeeventingv1alpha1 "knative.dev/eventing/pkg/client/clientset/versioned/typed/eventing/v1alpha1/fake" eventingv1beta1 "knative.dev/eventing/pkg/client/clientset/versioned/typed/eventing/v1beta1" @@ -88,6 +90,11 @@ func (c *Clientset) Tracker() testing.ObjectTracker { var _ clientset.Interface = &Clientset{} +// ConfigsV1alpha1 retrieves the ConfigsV1alpha1Client +func (c *Clientset) ConfigsV1alpha1() configsv1alpha1.ConfigsV1alpha1Interface { + return &fakeconfigsv1alpha1.FakeConfigsV1alpha1{Fake: &c.Fake} +} + // EventingV1alpha1 retrieves the EventingV1alpha1Client func (c *Clientset) EventingV1alpha1() eventingv1alpha1.EventingV1alpha1Interface { return &fakeeventingv1alpha1.FakeEventingV1alpha1{Fake: &c.Fake} diff --git a/pkg/client/clientset/versioned/fake/register.go b/pkg/client/clientset/versioned/fake/register.go index 5473e69a7e4..cdc6cebaf10 100644 --- a/pkg/client/clientset/versioned/fake/register.go +++ b/pkg/client/clientset/versioned/fake/register.go @@ -24,6 +24,7 @@ import ( schema "k8s.io/apimachinery/pkg/runtime/schema" serializer "k8s.io/apimachinery/pkg/runtime/serializer" utilruntime "k8s.io/apimachinery/pkg/util/runtime" + configsv1alpha1 "knative.dev/eventing/pkg/apis/configs/v1alpha1" eventingv1alpha1 "knative.dev/eventing/pkg/apis/eventing/v1alpha1" eventingv1beta1 "knative.dev/eventing/pkg/apis/eventing/v1beta1" flowsv1alpha1 "knative.dev/eventing/pkg/apis/flows/v1alpha1" @@ -37,6 +38,7 @@ var scheme = runtime.NewScheme() var codecs = serializer.NewCodecFactory(scheme) var parameterCodec = runtime.NewParameterCodec(scheme) var localSchemeBuilder = runtime.SchemeBuilder{ + configsv1alpha1.AddToScheme, eventingv1alpha1.AddToScheme, eventingv1beta1.AddToScheme, flowsv1alpha1.AddToScheme, diff --git a/pkg/client/clientset/versioned/scheme/register.go b/pkg/client/clientset/versioned/scheme/register.go index 329e2d70bf6..a301913949a 100644 --- a/pkg/client/clientset/versioned/scheme/register.go +++ b/pkg/client/clientset/versioned/scheme/register.go @@ -24,6 +24,7 @@ import ( schema "k8s.io/apimachinery/pkg/runtime/schema" serializer "k8s.io/apimachinery/pkg/runtime/serializer" utilruntime "k8s.io/apimachinery/pkg/util/runtime" + configsv1alpha1 "knative.dev/eventing/pkg/apis/configs/v1alpha1" eventingv1alpha1 "knative.dev/eventing/pkg/apis/eventing/v1alpha1" eventingv1beta1 "knative.dev/eventing/pkg/apis/eventing/v1beta1" flowsv1alpha1 "knative.dev/eventing/pkg/apis/flows/v1alpha1" @@ -37,6 +38,7 @@ var Scheme = runtime.NewScheme() var Codecs = serializer.NewCodecFactory(Scheme) var ParameterCodec = runtime.NewParameterCodec(Scheme) var localSchemeBuilder = runtime.SchemeBuilder{ + configsv1alpha1.AddToScheme, eventingv1alpha1.AddToScheme, eventingv1beta1.AddToScheme, flowsv1alpha1.AddToScheme, diff --git a/pkg/client/clientset/versioned/typed/configs/v1alpha1/configmappropagation.go b/pkg/client/clientset/versioned/typed/configs/v1alpha1/configmappropagation.go new file mode 100644 index 00000000000..dc075deec55 --- /dev/null +++ b/pkg/client/clientset/versioned/typed/configs/v1alpha1/configmappropagation.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 v1alpha1 + +import ( + "time" + + v1 "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" + v1alpha1 "knative.dev/eventing/pkg/apis/configs/v1alpha1" + scheme "knative.dev/eventing/pkg/client/clientset/versioned/scheme" +) + +// ConfigMapPropagationsGetter has a method to return a ConfigMapPropagationInterface. +// A group's client should implement this interface. +type ConfigMapPropagationsGetter interface { + ConfigMapPropagations(namespace string) ConfigMapPropagationInterface +} + +// ConfigMapPropagationInterface has methods to work with ConfigMapPropagation resources. +type ConfigMapPropagationInterface interface { + Create(*v1alpha1.ConfigMapPropagation) (*v1alpha1.ConfigMapPropagation, error) + Update(*v1alpha1.ConfigMapPropagation) (*v1alpha1.ConfigMapPropagation, error) + UpdateStatus(*v1alpha1.ConfigMapPropagation) (*v1alpha1.ConfigMapPropagation, error) + Delete(name string, options *v1.DeleteOptions) error + DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error + Get(name string, options v1.GetOptions) (*v1alpha1.ConfigMapPropagation, error) + List(opts v1.ListOptions) (*v1alpha1.ConfigMapPropagationList, error) + Watch(opts v1.ListOptions) (watch.Interface, error) + Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1alpha1.ConfigMapPropagation, err error) + ConfigMapPropagationExpansion +} + +// configMapPropagations implements ConfigMapPropagationInterface +type configMapPropagations struct { + client rest.Interface + ns string +} + +// newConfigMapPropagations returns a ConfigMapPropagations +func newConfigMapPropagations(c *ConfigsV1alpha1Client, namespace string) *configMapPropagations { + return &configMapPropagations{ + client: c.RESTClient(), + ns: namespace, + } +} + +// Get takes name of the configMapPropagation, and returns the corresponding configMapPropagation object, and an error if there is any. +func (c *configMapPropagations) Get(name string, options v1.GetOptions) (result *v1alpha1.ConfigMapPropagation, err error) { + result = &v1alpha1.ConfigMapPropagation{} + err = c.client.Get(). + Namespace(c.ns). + Resource("configmappropagations"). + Name(name). + VersionedParams(&options, scheme.ParameterCodec). + Do(). + Into(result) + return +} + +// List takes label and field selectors, and returns the list of ConfigMapPropagations that match those selectors. +func (c *configMapPropagations) List(opts v1.ListOptions) (result *v1alpha1.ConfigMapPropagationList, err error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + result = &v1alpha1.ConfigMapPropagationList{} + err = c.client.Get(). + Namespace(c.ns). + Resource("configmappropagations"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Do(). + Into(result) + return +} + +// Watch returns a watch.Interface that watches the requested configMapPropagations. +func (c *configMapPropagations) Watch(opts v1.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("configmappropagations"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Watch() +} + +// Create takes the representation of a configMapPropagation and creates it. Returns the server's representation of the configMapPropagation, and an error, if there is any. +func (c *configMapPropagations) Create(configMapPropagation *v1alpha1.ConfigMapPropagation) (result *v1alpha1.ConfigMapPropagation, err error) { + result = &v1alpha1.ConfigMapPropagation{} + err = c.client.Post(). + Namespace(c.ns). + Resource("configmappropagations"). + Body(configMapPropagation). + Do(). + Into(result) + return +} + +// Update takes the representation of a configMapPropagation and updates it. Returns the server's representation of the configMapPropagation, and an error, if there is any. +func (c *configMapPropagations) Update(configMapPropagation *v1alpha1.ConfigMapPropagation) (result *v1alpha1.ConfigMapPropagation, err error) { + result = &v1alpha1.ConfigMapPropagation{} + err = c.client.Put(). + Namespace(c.ns). + Resource("configmappropagations"). + Name(configMapPropagation.Name). + Body(configMapPropagation). + 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 *configMapPropagations) UpdateStatus(configMapPropagation *v1alpha1.ConfigMapPropagation) (result *v1alpha1.ConfigMapPropagation, err error) { + result = &v1alpha1.ConfigMapPropagation{} + err = c.client.Put(). + Namespace(c.ns). + Resource("configmappropagations"). + Name(configMapPropagation.Name). + SubResource("status"). + Body(configMapPropagation). + Do(). + Into(result) + return +} + +// Delete takes name of the configMapPropagation and deletes it. Returns an error if one occurs. +func (c *configMapPropagations) Delete(name string, options *v1.DeleteOptions) error { + return c.client.Delete(). + Namespace(c.ns). + Resource("configmappropagations"). + Name(name). + Body(options). + Do(). + Error() +} + +// DeleteCollection deletes a collection of objects. +func (c *configMapPropagations) DeleteCollection(options *v1.DeleteOptions, listOptions v1.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("configmappropagations"). + VersionedParams(&listOptions, scheme.ParameterCodec). + Timeout(timeout). + Body(options). + Do(). + Error() +} + +// Patch applies the patch and returns the patched configMapPropagation. +func (c *configMapPropagations) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1alpha1.ConfigMapPropagation, err error) { + result = &v1alpha1.ConfigMapPropagation{} + err = c.client.Patch(pt). + Namespace(c.ns). + Resource("configmappropagations"). + SubResource(subresources...). + Name(name). + Body(data). + Do(). + Into(result) + return +} diff --git a/pkg/client/clientset/versioned/typed/configs/v1alpha1/configs_client.go b/pkg/client/clientset/versioned/typed/configs/v1alpha1/configs_client.go new file mode 100644 index 00000000000..7efb4a582a2 --- /dev/null +++ b/pkg/client/clientset/versioned/typed/configs/v1alpha1/configs_client.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 client-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + rest "k8s.io/client-go/rest" + v1alpha1 "knative.dev/eventing/pkg/apis/configs/v1alpha1" + "knative.dev/eventing/pkg/client/clientset/versioned/scheme" +) + +type ConfigsV1alpha1Interface interface { + RESTClient() rest.Interface + ConfigMapPropagationsGetter +} + +// ConfigsV1alpha1Client is used to interact with features provided by the configs.internal.knative.dev group. +type ConfigsV1alpha1Client struct { + restClient rest.Interface +} + +func (c *ConfigsV1alpha1Client) ConfigMapPropagations(namespace string) ConfigMapPropagationInterface { + return newConfigMapPropagations(c, namespace) +} + +// NewForConfig creates a new ConfigsV1alpha1Client for the given config. +func NewForConfig(c *rest.Config) (*ConfigsV1alpha1Client, error) { + config := *c + if err := setConfigDefaults(&config); err != nil { + return nil, err + } + client, err := rest.RESTClientFor(&config) + if err != nil { + return nil, err + } + return &ConfigsV1alpha1Client{client}, nil +} + +// NewForConfigOrDie creates a new ConfigsV1alpha1Client for the given config and +// panics if there is an error in the config. +func NewForConfigOrDie(c *rest.Config) *ConfigsV1alpha1Client { + client, err := NewForConfig(c) + if err != nil { + panic(err) + } + return client +} + +// New creates a new ConfigsV1alpha1Client for the given RESTClient. +func New(c rest.Interface) *ConfigsV1alpha1Client { + return &ConfigsV1alpha1Client{c} +} + +func setConfigDefaults(config *rest.Config) error { + gv := v1alpha1.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 *ConfigsV1alpha1Client) RESTClient() rest.Interface { + if c == nil { + return nil + } + return c.restClient +} diff --git a/pkg/client/clientset/versioned/typed/configs/v1alpha1/doc.go b/pkg/client/clientset/versioned/typed/configs/v1alpha1/doc.go new file mode 100644 index 00000000000..41e872fe9a9 --- /dev/null +++ b/pkg/client/clientset/versioned/typed/configs/v1alpha1/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 v1alpha1 diff --git a/pkg/client/clientset/versioned/typed/configs/v1alpha1/fake/doc.go b/pkg/client/clientset/versioned/typed/configs/v1alpha1/fake/doc.go new file mode 100644 index 00000000000..c7f6e65cab8 --- /dev/null +++ b/pkg/client/clientset/versioned/typed/configs/v1alpha1/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/pkg/client/clientset/versioned/typed/configs/v1alpha1/fake/fake_configmappropagation.go b/pkg/client/clientset/versioned/typed/configs/v1alpha1/fake/fake_configmappropagation.go new file mode 100644 index 00000000000..65ce8935d53 --- /dev/null +++ b/pkg/client/clientset/versioned/typed/configs/v1alpha1/fake/fake_configmappropagation.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" + v1alpha1 "knative.dev/eventing/pkg/apis/configs/v1alpha1" +) + +// FakeConfigMapPropagations implements ConfigMapPropagationInterface +type FakeConfigMapPropagations struct { + Fake *FakeConfigsV1alpha1 + ns string +} + +var configmappropagationsResource = schema.GroupVersionResource{Group: "configs.internal.knative.dev", Version: "v1alpha1", Resource: "configmappropagations"} + +var configmappropagationsKind = schema.GroupVersionKind{Group: "configs.internal.knative.dev", Version: "v1alpha1", Kind: "ConfigMapPropagation"} + +// Get takes name of the configMapPropagation, and returns the corresponding configMapPropagation object, and an error if there is any. +func (c *FakeConfigMapPropagations) Get(name string, options v1.GetOptions) (result *v1alpha1.ConfigMapPropagation, err error) { + obj, err := c.Fake. + Invokes(testing.NewGetAction(configmappropagationsResource, c.ns, name), &v1alpha1.ConfigMapPropagation{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.ConfigMapPropagation), err +} + +// List takes label and field selectors, and returns the list of ConfigMapPropagations that match those selectors. +func (c *FakeConfigMapPropagations) List(opts v1.ListOptions) (result *v1alpha1.ConfigMapPropagationList, err error) { + obj, err := c.Fake. + Invokes(testing.NewListAction(configmappropagationsResource, configmappropagationsKind, c.ns, opts), &v1alpha1.ConfigMapPropagationList{}) + + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &v1alpha1.ConfigMapPropagationList{ListMeta: obj.(*v1alpha1.ConfigMapPropagationList).ListMeta} + for _, item := range obj.(*v1alpha1.ConfigMapPropagationList).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 configMapPropagations. +func (c *FakeConfigMapPropagations) Watch(opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewWatchAction(configmappropagationsResource, c.ns, opts)) + +} + +// Create takes the representation of a configMapPropagation and creates it. Returns the server's representation of the configMapPropagation, and an error, if there is any. +func (c *FakeConfigMapPropagations) Create(configMapPropagation *v1alpha1.ConfigMapPropagation) (result *v1alpha1.ConfigMapPropagation, err error) { + obj, err := c.Fake. + Invokes(testing.NewCreateAction(configmappropagationsResource, c.ns, configMapPropagation), &v1alpha1.ConfigMapPropagation{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.ConfigMapPropagation), err +} + +// Update takes the representation of a configMapPropagation and updates it. Returns the server's representation of the configMapPropagation, and an error, if there is any. +func (c *FakeConfigMapPropagations) Update(configMapPropagation *v1alpha1.ConfigMapPropagation) (result *v1alpha1.ConfigMapPropagation, err error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateAction(configmappropagationsResource, c.ns, configMapPropagation), &v1alpha1.ConfigMapPropagation{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.ConfigMapPropagation), 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 *FakeConfigMapPropagations) UpdateStatus(configMapPropagation *v1alpha1.ConfigMapPropagation) (*v1alpha1.ConfigMapPropagation, error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateSubresourceAction(configmappropagationsResource, "status", c.ns, configMapPropagation), &v1alpha1.ConfigMapPropagation{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.ConfigMapPropagation), err +} + +// Delete takes name of the configMapPropagation and deletes it. Returns an error if one occurs. +func (c *FakeConfigMapPropagations) Delete(name string, options *v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewDeleteAction(configmappropagationsResource, c.ns, name), &v1alpha1.ConfigMapPropagation{}) + + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeConfigMapPropagations) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error { + action := testing.NewDeleteCollectionAction(configmappropagationsResource, c.ns, listOptions) + + _, err := c.Fake.Invokes(action, &v1alpha1.ConfigMapPropagationList{}) + return err +} + +// Patch applies the patch and returns the patched configMapPropagation. +func (c *FakeConfigMapPropagations) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1alpha1.ConfigMapPropagation, err error) { + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(configmappropagationsResource, c.ns, name, pt, data, subresources...), &v1alpha1.ConfigMapPropagation{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.ConfigMapPropagation), err +} diff --git a/pkg/client/clientset/versioned/typed/configs/v1alpha1/fake/fake_configs_client.go b/pkg/client/clientset/versioned/typed/configs/v1alpha1/fake/fake_configs_client.go new file mode 100644 index 00000000000..6b97fff7e5a --- /dev/null +++ b/pkg/client/clientset/versioned/typed/configs/v1alpha1/fake/fake_configs_client.go @@ -0,0 +1,40 @@ +/* +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" + v1alpha1 "knative.dev/eventing/pkg/client/clientset/versioned/typed/configs/v1alpha1" +) + +type FakeConfigsV1alpha1 struct { + *testing.Fake +} + +func (c *FakeConfigsV1alpha1) ConfigMapPropagations(namespace string) v1alpha1.ConfigMapPropagationInterface { + return &FakeConfigMapPropagations{c, namespace} +} + +// RESTClient returns a RESTClient that is used to communicate +// with API server by this client implementation. +func (c *FakeConfigsV1alpha1) RESTClient() rest.Interface { + var ret *rest.RESTClient + return ret +} diff --git a/pkg/client/clientset/versioned/typed/configs/v1alpha1/generated_expansion.go b/pkg/client/clientset/versioned/typed/configs/v1alpha1/generated_expansion.go new file mode 100644 index 00000000000..ef016fddbd2 --- /dev/null +++ b/pkg/client/clientset/versioned/typed/configs/v1alpha1/generated_expansion.go @@ -0,0 +1,21 @@ +/* +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 v1alpha1 + +type ConfigMapPropagationExpansion interface{} diff --git a/pkg/client/informers/externalversions/configs/interface.go b/pkg/client/informers/externalversions/configs/interface.go new file mode 100644 index 00000000000..a545b2e0441 --- /dev/null +++ b/pkg/client/informers/externalversions/configs/interface.go @@ -0,0 +1,46 @@ +/* +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 configs + +import ( + v1alpha1 "knative.dev/eventing/pkg/client/informers/externalversions/configs/v1alpha1" + internalinterfaces "knative.dev/eventing/pkg/client/informers/externalversions/internalinterfaces" +) + +// Interface provides access to each of this group's versions. +type Interface interface { + // V1alpha1 provides access to shared informers for resources in V1alpha1. + V1alpha1() v1alpha1.Interface +} + +type group struct { + factory internalinterfaces.SharedInformerFactory + namespace string + tweakListOptions internalinterfaces.TweakListOptionsFunc +} + +// New returns a new Interface. +func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface { + return &group{factory: f, namespace: namespace, tweakListOptions: tweakListOptions} +} + +// V1alpha1 returns a new v1alpha1.Interface. +func (g *group) V1alpha1() v1alpha1.Interface { + return v1alpha1.New(g.factory, g.namespace, g.tweakListOptions) +} diff --git a/pkg/client/informers/externalversions/configs/v1alpha1/configmappropagation.go b/pkg/client/informers/externalversions/configs/v1alpha1/configmappropagation.go new file mode 100644 index 00000000000..c36690cbfe8 --- /dev/null +++ b/pkg/client/informers/externalversions/configs/v1alpha1/configmappropagation.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 v1alpha1 + +import ( + time "time" + + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + watch "k8s.io/apimachinery/pkg/watch" + cache "k8s.io/client-go/tools/cache" + configsv1alpha1 "knative.dev/eventing/pkg/apis/configs/v1alpha1" + versioned "knative.dev/eventing/pkg/client/clientset/versioned" + internalinterfaces "knative.dev/eventing/pkg/client/informers/externalversions/internalinterfaces" + v1alpha1 "knative.dev/eventing/pkg/client/listers/configs/v1alpha1" +) + +// ConfigMapPropagationInformer provides access to a shared informer and lister for +// ConfigMapPropagations. +type ConfigMapPropagationInformer interface { + Informer() cache.SharedIndexInformer + Lister() v1alpha1.ConfigMapPropagationLister +} + +type configMapPropagationInformer struct { + factory internalinterfaces.SharedInformerFactory + tweakListOptions internalinterfaces.TweakListOptionsFunc + namespace string +} + +// NewConfigMapPropagationInformer constructs a new informer for ConfigMapPropagation 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 NewConfigMapPropagationInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { + return NewFilteredConfigMapPropagationInformer(client, namespace, resyncPeriod, indexers, nil) +} + +// NewFilteredConfigMapPropagationInformer constructs a new informer for ConfigMapPropagation 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 NewFilteredConfigMapPropagationInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer { + return cache.NewSharedIndexInformer( + &cache.ListWatch{ + ListFunc: func(options v1.ListOptions) (runtime.Object, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.ConfigsV1alpha1().ConfigMapPropagations(namespace).List(options) + }, + WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.ConfigsV1alpha1().ConfigMapPropagations(namespace).Watch(options) + }, + }, + &configsv1alpha1.ConfigMapPropagation{}, + resyncPeriod, + indexers, + ) +} + +func (f *configMapPropagationInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { + return NewFilteredConfigMapPropagationInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) +} + +func (f *configMapPropagationInformer) Informer() cache.SharedIndexInformer { + return f.factory.InformerFor(&configsv1alpha1.ConfigMapPropagation{}, f.defaultInformer) +} + +func (f *configMapPropagationInformer) Lister() v1alpha1.ConfigMapPropagationLister { + return v1alpha1.NewConfigMapPropagationLister(f.Informer().GetIndexer()) +} diff --git a/pkg/client/informers/externalversions/configs/v1alpha1/interface.go b/pkg/client/informers/externalversions/configs/v1alpha1/interface.go new file mode 100644 index 00000000000..98c0cd06b85 --- /dev/null +++ b/pkg/client/informers/externalversions/configs/v1alpha1/interface.go @@ -0,0 +1,45 @@ +/* +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 v1alpha1 + +import ( + internalinterfaces "knative.dev/eventing/pkg/client/informers/externalversions/internalinterfaces" +) + +// Interface provides access to all the informers in this group version. +type Interface interface { + // ConfigMapPropagations returns a ConfigMapPropagationInformer. + ConfigMapPropagations() ConfigMapPropagationInformer +} + +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} +} + +// ConfigMapPropagations returns a ConfigMapPropagationInformer. +func (v *version) ConfigMapPropagations() ConfigMapPropagationInformer { + return &configMapPropagationInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} +} diff --git a/pkg/client/informers/externalversions/factory.go b/pkg/client/informers/externalversions/factory.go index 57c8c585e82..b4f4c77cf44 100644 --- a/pkg/client/informers/externalversions/factory.go +++ b/pkg/client/informers/externalversions/factory.go @@ -28,6 +28,7 @@ import ( schema "k8s.io/apimachinery/pkg/runtime/schema" cache "k8s.io/client-go/tools/cache" versioned "knative.dev/eventing/pkg/client/clientset/versioned" + configs "knative.dev/eventing/pkg/client/informers/externalversions/configs" eventing "knative.dev/eventing/pkg/client/informers/externalversions/eventing" flows "knative.dev/eventing/pkg/client/informers/externalversions/flows" internalinterfaces "knative.dev/eventing/pkg/client/informers/externalversions/internalinterfaces" @@ -175,12 +176,17 @@ type SharedInformerFactory interface { ForResource(resource schema.GroupVersionResource) (GenericInformer, error) WaitForCacheSync(stopCh <-chan struct{}) map[reflect.Type]bool + Configs() configs.Interface Eventing() eventing.Interface Flows() flows.Interface Messaging() messaging.Interface Sources() sources.Interface } +func (f *sharedInformerFactory) Configs() configs.Interface { + return configs.New(f, f.namespace, f.tweakListOptions) +} + func (f *sharedInformerFactory) Eventing() eventing.Interface { return eventing.New(f, f.namespace, f.tweakListOptions) } diff --git a/pkg/client/informers/externalversions/generic.go b/pkg/client/informers/externalversions/generic.go index a31f8cbf396..d242d8da8d7 100644 --- a/pkg/client/informers/externalversions/generic.go +++ b/pkg/client/informers/externalversions/generic.go @@ -23,7 +23,8 @@ import ( schema "k8s.io/apimachinery/pkg/runtime/schema" cache "k8s.io/client-go/tools/cache" - v1alpha1 "knative.dev/eventing/pkg/apis/eventing/v1alpha1" + v1alpha1 "knative.dev/eventing/pkg/apis/configs/v1alpha1" + eventingv1alpha1 "knative.dev/eventing/pkg/apis/eventing/v1alpha1" v1beta1 "knative.dev/eventing/pkg/apis/eventing/v1beta1" flowsv1alpha1 "knative.dev/eventing/pkg/apis/flows/v1alpha1" flowsv1beta1 "knative.dev/eventing/pkg/apis/flows/v1beta1" @@ -58,12 +59,16 @@ func (f *genericInformer) Lister() cache.GenericLister { // TODO extend this to unknown resources with a client pool func (f *sharedInformerFactory) ForResource(resource schema.GroupVersionResource) (GenericInformer, error) { switch resource { - // Group=eventing.knative.dev, Version=v1alpha1 - case v1alpha1.SchemeGroupVersion.WithResource("brokers"): + // Group=configs.internal.knative.dev, Version=v1alpha1 + case v1alpha1.SchemeGroupVersion.WithResource("configmappropagations"): + return &genericInformer{resource: resource.GroupResource(), informer: f.Configs().V1alpha1().ConfigMapPropagations().Informer()}, nil + + // Group=eventing.knative.dev, Version=v1alpha1 + case eventingv1alpha1.SchemeGroupVersion.WithResource("brokers"): return &genericInformer{resource: resource.GroupResource(), informer: f.Eventing().V1alpha1().Brokers().Informer()}, nil - case v1alpha1.SchemeGroupVersion.WithResource("eventtypes"): + case eventingv1alpha1.SchemeGroupVersion.WithResource("eventtypes"): return &genericInformer{resource: resource.GroupResource(), informer: f.Eventing().V1alpha1().EventTypes().Informer()}, nil - case v1alpha1.SchemeGroupVersion.WithResource("triggers"): + case eventingv1alpha1.SchemeGroupVersion.WithResource("triggers"): return &genericInformer{resource: resource.GroupResource(), informer: f.Eventing().V1alpha1().Triggers().Informer()}, nil // Group=eventing.knative.dev, Version=v1beta1 diff --git a/pkg/client/injection/informers/configs/v1alpha1/configmappropagation/configmappropagation.go b/pkg/client/injection/informers/configs/v1alpha1/configmappropagation/configmappropagation.go new file mode 100644 index 00000000000..585887158b6 --- /dev/null +++ b/pkg/client/injection/informers/configs/v1alpha1/configmappropagation/configmappropagation.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 injection-gen. DO NOT EDIT. + +package configmappropagation + +import ( + "context" + + v1alpha1 "knative.dev/eventing/pkg/client/informers/externalversions/configs/v1alpha1" + factory "knative.dev/eventing/pkg/client/injection/informers/factory" + controller "knative.dev/pkg/controller" + injection "knative.dev/pkg/injection" + logging "knative.dev/pkg/logging" +) + +func init() { + injection.Default.RegisterInformer(withInformer) +} + +// Key is used for associating the Informer inside the context.Context. +type Key struct{} + +func withInformer(ctx context.Context) (context.Context, controller.Informer) { + f := factory.Get(ctx) + inf := f.Configs().V1alpha1().ConfigMapPropagations() + return context.WithValue(ctx, Key{}, inf), inf.Informer() +} + +// Get extracts the typed informer from the context. +func Get(ctx context.Context) v1alpha1.ConfigMapPropagationInformer { + untyped := ctx.Value(Key{}) + if untyped == nil { + logging.FromContext(ctx).Panic( + "Unable to fetch knative.dev/eventing/pkg/client/informers/externalversions/configs/v1alpha1.ConfigMapPropagationInformer from context.") + } + return untyped.(v1alpha1.ConfigMapPropagationInformer) +} diff --git a/pkg/client/injection/informers/configs/v1alpha1/configmappropagation/fake/fake.go b/pkg/client/injection/informers/configs/v1alpha1/configmappropagation/fake/fake.go new file mode 100644 index 00000000000..3d6047ce3b2 --- /dev/null +++ b/pkg/client/injection/informers/configs/v1alpha1/configmappropagation/fake/fake.go @@ -0,0 +1,40 @@ +/* +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 injection-gen. DO NOT EDIT. + +package fake + +import ( + "context" + + configmappropagation "knative.dev/eventing/pkg/client/injection/informers/configs/v1alpha1/configmappropagation" + fake "knative.dev/eventing/pkg/client/injection/informers/factory/fake" + controller "knative.dev/pkg/controller" + injection "knative.dev/pkg/injection" +) + +var Get = configmappropagation.Get + +func init() { + injection.Fake.RegisterInformer(withInformer) +} + +func withInformer(ctx context.Context) (context.Context, controller.Informer) { + f := fake.Get(ctx) + inf := f.Configs().V1alpha1().ConfigMapPropagations() + return context.WithValue(ctx, configmappropagation.Key{}, inf), inf.Informer() +} diff --git a/pkg/client/listers/configs/v1alpha1/configmappropagation.go b/pkg/client/listers/configs/v1alpha1/configmappropagation.go new file mode 100644 index 00000000000..3274646b754 --- /dev/null +++ b/pkg/client/listers/configs/v1alpha1/configmappropagation.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 v1alpha1 + +import ( + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/client-go/tools/cache" + v1alpha1 "knative.dev/eventing/pkg/apis/configs/v1alpha1" +) + +// ConfigMapPropagationLister helps list ConfigMapPropagations. +type ConfigMapPropagationLister interface { + // List lists all ConfigMapPropagations in the indexer. + List(selector labels.Selector) (ret []*v1alpha1.ConfigMapPropagation, err error) + // ConfigMapPropagations returns an object that can list and get ConfigMapPropagations. + ConfigMapPropagations(namespace string) ConfigMapPropagationNamespaceLister + ConfigMapPropagationListerExpansion +} + +// configMapPropagationLister implements the ConfigMapPropagationLister interface. +type configMapPropagationLister struct { + indexer cache.Indexer +} + +// NewConfigMapPropagationLister returns a new ConfigMapPropagationLister. +func NewConfigMapPropagationLister(indexer cache.Indexer) ConfigMapPropagationLister { + return &configMapPropagationLister{indexer: indexer} +} + +// List lists all ConfigMapPropagations in the indexer. +func (s *configMapPropagationLister) List(selector labels.Selector) (ret []*v1alpha1.ConfigMapPropagation, err error) { + err = cache.ListAll(s.indexer, selector, func(m interface{}) { + ret = append(ret, m.(*v1alpha1.ConfigMapPropagation)) + }) + return ret, err +} + +// ConfigMapPropagations returns an object that can list and get ConfigMapPropagations. +func (s *configMapPropagationLister) ConfigMapPropagations(namespace string) ConfigMapPropagationNamespaceLister { + return configMapPropagationNamespaceLister{indexer: s.indexer, namespace: namespace} +} + +// ConfigMapPropagationNamespaceLister helps list and get ConfigMapPropagations. +type ConfigMapPropagationNamespaceLister interface { + // List lists all ConfigMapPropagations in the indexer for a given namespace. + List(selector labels.Selector) (ret []*v1alpha1.ConfigMapPropagation, err error) + // Get retrieves the ConfigMapPropagation from the indexer for a given namespace and name. + Get(name string) (*v1alpha1.ConfigMapPropagation, error) + ConfigMapPropagationNamespaceListerExpansion +} + +// configMapPropagationNamespaceLister implements the ConfigMapPropagationNamespaceLister +// interface. +type configMapPropagationNamespaceLister struct { + indexer cache.Indexer + namespace string +} + +// List lists all ConfigMapPropagations in the indexer for a given namespace. +func (s configMapPropagationNamespaceLister) List(selector labels.Selector) (ret []*v1alpha1.ConfigMapPropagation, err error) { + err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) { + ret = append(ret, m.(*v1alpha1.ConfigMapPropagation)) + }) + return ret, err +} + +// Get retrieves the ConfigMapPropagation from the indexer for a given namespace and name. +func (s configMapPropagationNamespaceLister) Get(name string) (*v1alpha1.ConfigMapPropagation, error) { + obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name) + if err != nil { + return nil, err + } + if !exists { + return nil, errors.NewNotFound(v1alpha1.Resource("configmappropagation"), name) + } + return obj.(*v1alpha1.ConfigMapPropagation), nil +} diff --git a/pkg/client/listers/configs/v1alpha1/expansion_generated.go b/pkg/client/listers/configs/v1alpha1/expansion_generated.go new file mode 100644 index 00000000000..bded4cdb67d --- /dev/null +++ b/pkg/client/listers/configs/v1alpha1/expansion_generated.go @@ -0,0 +1,27 @@ +/* +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 v1alpha1 + +// ConfigMapPropagationListerExpansion allows custom methods to be added to +// ConfigMapPropagationLister. +type ConfigMapPropagationListerExpansion interface{} + +// ConfigMapPropagationNamespaceListerExpansion allows custom methods to be added to +// ConfigMapPropagationNamespaceLister. +type ConfigMapPropagationNamespaceListerExpansion interface{} diff --git a/pkg/reconciler/configmappropagation/configmappropagation.go b/pkg/reconciler/configmappropagation/configmappropagation.go new file mode 100644 index 00000000000..f762092554b --- /dev/null +++ b/pkg/reconciler/configmappropagation/configmappropagation.go @@ -0,0 +1,343 @@ +/* +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 configmappropagation + +import ( + "context" + "fmt" + "k8s.io/apimachinery/pkg/types" + "reflect" + "strings" + "time" + + "go.uber.org/zap" + corev1 "k8s.io/api/core/v1" + apierrs "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/labels" + corev1listers "k8s.io/client-go/listers/core/v1" + "k8s.io/client-go/tools/cache" + + "knative.dev/eventing/pkg/apis/configs/v1alpha1" + configslisters "knative.dev/eventing/pkg/client/listers/configs/v1alpha1" + "knative.dev/eventing/pkg/logging" + "knative.dev/eventing/pkg/reconciler" + "knative.dev/eventing/pkg/reconciler/configmappropagation/resources" + "knative.dev/pkg/controller" + "knative.dev/pkg/tracker" +) + +const ( + // Name of the corev1.Events emitted from the reconciliation process. + configMapPropagationReconcileError = "ConfigMapPropagationReconcileError" + configMapPropagationUpdateStatusFailed = "ConfigMapPropagationStatusFailed" + configMapPropagationReadinessChanged = "ConfigMapPropagationReadinessChanged" + configMapPropagationPropagateSingleConfigMapFailed = "ConfigMapPropagationPropagateSingleConfigMapFailed" + configMapPropagationPropagateSingleConfigMapSucceed = "ConfigMapPropagationPropagateSingleConfigMapSucceed" + + // Name of operation to propagate single configmap. + copyConfigMap = "Copy" + deleteConfigMap = "Delete" + // stopConfigMap indicates a configmap stop propagating. + stopConfigMap = "Stop" +) + +type Reconciler struct { + *reconciler.Base + + // Listers index properties about resources + configMapPropagationLister configslisters.ConfigMapPropagationLister + configMapLister corev1listers.ConfigMapLister + + tracker tracker.Interface +} + +var configMapGVK = corev1.SchemeGroupVersion.WithKind("ConfigMap") + +// Check that our Reconciler implements controller.Reconciler. +var _ controller.Reconciler = (*Reconciler)(nil) + +// Reconcile compares the actual state with the desired, and attempts to +// converge the two. It then updates the Status block of the ConfigMapPropagation resource +// with the current status of the resource. +func (r *Reconciler) Reconcile(ctx context.Context, key string) error { + // Convert the namespace/name string into a distinct namespace and name. + namespace, name, err := cache.SplitMetaNamespaceKey(key) + if err != nil { + logging.FromContext(ctx).Error("invalid resource key") + return nil + } + // Get the ConfigMapPropagation resource with this namespace/name + original, err := r.configMapPropagationLister.ConfigMapPropagations(namespace).Get(name) + if apierrs.IsNotFound(err) { + // The resource may no longer exist, in which case we stop processing. + logging.FromContext(ctx).Info("ConfigMapPropagation key in work queue no longer exists") + return nil + } else if err != nil { + return err + } + + // Don't modify the informers copy. + configMapPropagation := original.DeepCopy() + + // Reconcile this copy of the ConfigMapPropagation and then write back any status + // updates regardless of whether the reconcile error out. + reconcileErr := r.reconcile(ctx, configMapPropagation) + if reconcileErr != nil { + logging.FromContext(ctx).Warn("Error reconciling ConfigMapPropagation", zap.Error(err)) + r.Recorder.Eventf(configMapPropagation, corev1.EventTypeWarning, configMapPropagationReconcileError, + fmt.Sprintf("ConfigMapPropagation reconcile error: %v", reconcileErr)) + } else { + logging.FromContext(ctx).Debug("ConfigMapPropagation reconciled") + } + + // Since the reconciler took a crack at this, make sure it's reflected in the status correctly. + configMapPropagation.Status.ObservedGeneration = original.Generation + + if _, updateStatusErr := r.updateStatus(ctx, configMapPropagation); updateStatusErr != nil { + logging.FromContext(ctx).Warn("Failed to update the ConfigMapPropagation status", zap.Error(updateStatusErr)) + r.Recorder.Eventf(configMapPropagation, corev1.EventTypeWarning, configMapPropagationUpdateStatusFailed, + fmt.Sprintf("Failed to update ConfigMapPropagation's status: %v", updateStatusErr)) + return updateStatusErr + } + // Requeue if the resource is not ready. + return reconcileErr +} + +func (r *Reconciler) reconcile(ctx context.Context, cmp *v1alpha1.ConfigMapPropagation) error { + logging.FromContext(ctx).Debug("Reconciling", zap.Any("ConfigMapPropagation", cmp)) + cmp.Status.InitializeConditions() + cmp.Status.CopyConfigMaps = []v1alpha1.ConfigMapPropagationStatusCopyConfigMap{} + // 1. Create/update ConfigMaps from original namespace to current namespace. + // 2. Track changes of original ConfigMaps as well as copy ConfigMaps. + + // No need to reconcile if the ConfigMapPropagation has been marked for deletion. + if cmp.DeletionTimestamp != nil { + return nil + } + + // Tell tracker to reconcile this ConfigMapPropagation whenever an original ConfigMap changes. + // Note: Temporarily set Selector to match all objects. + // If Selector is set to match specific labels (the required labels from ConfigMapPropagation), + // the tracker can't track changes when an original ConfigMap no longer has required labels. + // One alternative way is to track the name of every qualified original ConfigMap, + // but this requires to track specific Selector as well, in order to notice newly qualified original ConfigMaps. + originalConfigMapObjRef := tracker.Reference{ + Kind: configMapGVK.Kind, + APIVersion: configMapGVK.GroupVersion().String(), + Namespace: cmp.Spec.OriginalNamespace, + Selector: metav1.SetAsLabelSelector(map[string]string{}), + } + if err := r.tracker.TrackReference(originalConfigMapObjRef, cmp); err != nil { + return err + } + + // Tell tracker to reconcile this ConfigMapPropagation whenever the a copy ConfigMap changes. + // Note: Temporarily set Selector to match all objects. + // If Selector is set to match specific labels (the required labels from creation), + // the tracker can't track changes when a copy ConfigMap no longer has required labels. + // One alternative way is to track the name of every qualified copy ConfigMap. + copyConfigMapObjRef := tracker.Reference{ + Kind: configMapGVK.Kind, + APIVersion: configMapGVK.GroupVersion().String(), + Namespace: cmp.Namespace, + Selector: metav1.SetAsLabelSelector(map[string]string{}), + } + if err := r.tracker.TrackReference(copyConfigMapObjRef, cmp); err != nil { + logging.FromContext(ctx).Error("Unable to track changes to ConfigMap", zap.Error(err)) + return err + } + + if err := r.reconcileConfigMap(ctx, cmp); err != nil { + cmp.Status.MarkNotPropagated() + return err + } + + cmp.Status.MarkPropagated() + return nil +} + +func (r *Reconciler) updateStatus(ctx context.Context, desired *v1alpha1.ConfigMapPropagation) (*v1alpha1.ConfigMapPropagation, error) { + configMapPropagation, err := r.configMapPropagationLister.ConfigMapPropagations(desired.Namespace).Get(desired.Name) + if err != nil { + return nil, err + } + + // If there's nothing to update, just return. + if reflect.DeepEqual(configMapPropagation.Status, desired.Status) { + return configMapPropagation, nil + } + + becomesReady := desired.Status.IsReady() && !configMapPropagation.Status.IsReady() + + // Don't modify the informers copy. + existing := configMapPropagation.DeepCopy() + existing.Status = desired.Status + + cmp, err := r.EventingClientSet.ConfigsV1alpha1().ConfigMapPropagations(desired.Namespace).UpdateStatus(existing) + if err == nil && becomesReady { + duration := time.Since(cmp.ObjectMeta.CreationTimestamp.Time) + r.Logger.Infof("ConfigMapPropagation %q became ready after %v", configMapPropagation.Name, duration) + r.Recorder.Event(configMapPropagation, corev1.EventTypeNormal, configMapPropagationReadinessChanged, + fmt.Sprintf("ConfigMapPropagation %q became ready", configMapPropagation.Name)) + if reportErr := r.StatsReporter.ReportReady("ConfigMapPropagation", configMapPropagation.Namespace, configMapPropagation.Name, duration); reportErr != nil { + logging.FromContext(ctx).Sugar().Infof("failed to record ready for ConfigMapPropagation, %v", reportErr) + } + } + return cmp, err +} + +func (r *Reconciler) reconcileConfigMap(ctx context.Context, cmp *v1alpha1.ConfigMapPropagation) error { + // List ConfigMaps in original namespace and create/update copy ConfigMap in current namespace. + var errs error + originalConfigMapList, err := r.configMapLister.ConfigMaps(cmp.Spec.OriginalNamespace).List(resources.ExpectedOriginalSelector(cmp.Spec.Selector)) + if err != nil { + logging.FromContext(ctx).Error("Unable to get the ConfigMap list in original namespace", zap.Error(err)) + return err + } + for _, configMap := range originalConfigMapList { + name := resources.MakeCopyConfigMapName(cmp.Name, configMap.Name) + source := types.NamespacedName{Namespace: cmp.Spec.OriginalNamespace, Name: configMap.Name}.String() + resourceVersion := configMap.ResourceVersion + var expectedStatus v1alpha1.ConfigMapPropagationStatusCopyConfigMap + // Variable "succeed" represents whether a create/update action is successful or not. + if err, succeed := r.createOrUpdateConfigMaps(ctx, cmp, configMap); err != nil { + logging.FromContext(ctx).Warn("Failed to propagate ConfigMap: ", zap.Error(err)) + r.Recorder.Eventf(cmp, corev1.EventTypeWarning, configMapPropagationPropagateSingleConfigMapFailed, + fmt.Sprintf("Failed to propagate ConfigMap %v: %v", configMap.Name, err)) + if errs == nil { + errs = fmt.Errorf("one or more ConfigMap propagation failed") + } + expectedStatus.SetCopyConfigMapStatus(name, source, copyConfigMap, "False", err.Error(), resourceVersion) + } else if !succeed { + // If there is no error, but the create/update action is not successful, + // this indicates the copy configmap's copy label is removed. + logging.FromContext(ctx).Debug("Stop propagating ConfigMap " + configMap.Name) + r.Recorder.Eventf(cmp, corev1.EventTypeNormal, configMapPropagationPropagateSingleConfigMapSucceed, + fmt.Sprintf("Stop propagating ConfigMap: %s", configMap.Name)) + expectedStatus.SetCopyConfigMapStatus(name, source, stopConfigMap, "True", + `copy ConfigMap doesn't have copy label, stop propagating this ConfigMap`, resourceVersion) + } else { + logging.FromContext(ctx).Debug("Propagate ConfigMap " + configMap.Name + " succeed") + r.Recorder.Eventf(cmp, corev1.EventTypeNormal, configMapPropagationPropagateSingleConfigMapSucceed, + fmt.Sprintf("Propagate ConfigMap %v succeed", configMap.Name)) + expectedStatus.SetCopyConfigMapStatus(name, source, copyConfigMap, "True", "", resourceVersion) + } + // Update current copy configmap's status. + cmp.Status.CopyConfigMaps = append(cmp.Status.CopyConfigMaps, expectedStatus) + } + // List ConfigMaps in current namespace and delete copy ConfigMap if the corresponding original ConfigMap no longer exists or no longer has the required label. + copyConfigMapList, err := r.configMapLister.ConfigMaps(cmp.Namespace).List(labels.SelectorFromSet(map[string]string{resources.PropagationLabelKey: resources.PropagationLabelValueCopy})) + if err != nil { + logging.FromContext(ctx).Error("Unable to get the ConfigMap list in current namespace", zap.Error(err)) + return err + } + + for _, copyConfigMap := range copyConfigMapList { + // Select copy ConfigMap which is controlled by current ConfigMapPropagation. + if metav1.IsControlledBy(copyConfigMap, cmp) { + // Get the name of original ConfigMap. + // The name of Copy ConfigMap is followed by -. + originalConfigMapName := strings.TrimPrefix(copyConfigMap.Name, cmp.Name+"-") + source := types.NamespacedName{Namespace: cmp.Spec.OriginalNamespace, Name: originalConfigMapName}.String() + var expectedStatus v1alpha1.ConfigMapPropagationStatusCopyConfigMap + // Variable "succeed" represents whether a delete action is successful or not. + if err, succeed := r.deleteOrKeepConfigMap(ctx, cmp, copyConfigMap, originalConfigMapName, originalConfigMapList); err != nil { + logging.FromContext(ctx).Warn("Failed to propagate ConfigMap: ", zap.Error(err)) + r.Recorder.Eventf(cmp, corev1.EventTypeWarning, configMapPropagationPropagateSingleConfigMapFailed, + fmt.Sprintf("Failed to propagate ConfigMap %v: %v", originalConfigMapName, err)) + if errs == nil { + errs = fmt.Errorf("one or more ConfigMap propagation failed") + } + expectedStatus.SetCopyConfigMapStatus(copyConfigMap.Name, source, deleteConfigMap, "False", err.Error(), "") + } else if succeed { + expectedStatus.SetCopyConfigMapStatus(copyConfigMap.Name, source, deleteConfigMap, "True", "", "") + } + if expectedStatus.Name != "" { + // expectedStatus with same name will be merged and updated. + cmp.Status.CopyConfigMaps = append(cmp.Status.CopyConfigMaps, expectedStatus) + } + } + } + + return errs +} + +// createOrUpdateConfigMaps will return error and bool (represents whether a create/update action is successful or not). +func (r *Reconciler) createOrUpdateConfigMaps(ctx context.Context, cmp *v1alpha1.ConfigMapPropagation, configMap *corev1.ConfigMap) (error, bool) { + expected := resources.MakeConfigMap(resources.ConfigMapArgs{ + Original: configMap, + ConfigMapPropagation: cmp, + }) + current, err := r.configMapLister.ConfigMaps(cmp.Namespace).Get(expected.Name) + if err != nil && !apierrs.IsNotFound(err) { + logging.FromContext(ctx).Error("Unable to get ConfigMap: "+current.Name+" in current namespace", zap.Error(err)) + return fmt.Errorf("error getting ConfigMap in current namespace: %w", err), false + } + + // Only update ConfigMap with knative.dev/config-propagation:copy label. + // If the ConfigMap does not have this label, the controller must not update the ConfigMap. + if current != nil { + label := current.GetLabels() + succeed := true + if label[resources.PropagationLabelKey] != resources.PropagationLabelValueCopy { + // OwnerReference will be removed when the knative.dev/config-propagation:copy label is not set in copy configmap + // so that this copy configmap will not be deleted if cmp is deleted. + expected = current.DeepCopy() + expected.OwnerReferences = nil + // It will return false for the create/update action is not successful, due to removed copy label. + // But it is not an error for ConfigMapPropagation for not propagating successfully. + succeed = false + } + if current, err = r.KubeClientSet.CoreV1().ConfigMaps(expected.Namespace).Update(expected); err != nil { + return fmt.Errorf("error updating ConfigMap in current namespace: %w", err), false + } + return nil, succeed + } + + if current, err = r.KubeClientSet.CoreV1().ConfigMaps(expected.Namespace).Create(expected); err != nil { + return fmt.Errorf("error creating ConfigMap in current namespace: %w", err), false + } + return nil, true +} + +// deleteOrKeepConfigMap will return error and bool (represents whether a delete action is successful or not). +func (r *Reconciler) deleteOrKeepConfigMap(ctx context.Context, cmp *v1alpha1.ConfigMapPropagation, copyConfigMap *corev1.ConfigMap, originalConfigMapName string, originalConfigMapList []*corev1.ConfigMap) (error, bool) { + originalConfigMap, contains := r.contains(originalConfigMapName, originalConfigMapList) + expectedSelector := resources.ExpectedOriginalSelector(cmp.Spec.Selector) + if !contains || !expectedSelector.Matches(labels.Set(originalConfigMap.Labels)) { + // If Original ConfigMap no longer exists or no longer has the required label, delete copy ConfigMap. + logging.FromContext(ctx).Info("Original ConfigMap " + originalConfigMapName + + ` no longer exists/no longer has "knative.dev/eventing/config-propagation:original" label, delete corresponding copy ConfigMap ` + copyConfigMap.Name) + if err := r.KubeClientSet.CoreV1().ConfigMaps(cmp.Namespace).Delete(copyConfigMap.Name, &metav1.DeleteOptions{}); err != nil { + logging.FromContext(ctx).Error("error deleting ConfigMap in current namespace", zap.Error(err)) + return err, false + } + return nil, true + } + return nil, false +} + +// contains returns a configmap object if its name is in a configmaplist. +func (r *Reconciler) contains(name string, list []*corev1.ConfigMap) (*corev1.ConfigMap, bool) { + for _, configMap := range list { + if configMap.Name == name { + return configMap, true + } + } + return nil, false +} diff --git a/pkg/reconciler/configmappropagation/configmappropagation_test.go b/pkg/reconciler/configmappropagation/configmappropagation_test.go new file mode 100644 index 00000000000..1ea31203caf --- /dev/null +++ b/pkg/reconciler/configmappropagation/configmappropagation_test.go @@ -0,0 +1,493 @@ +/* +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 configmappropagation + +import ( + "context" + "testing" + + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/types" + clientgotesting "k8s.io/client-go/testing" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "knative.dev/eventing/pkg/apis/configs/v1alpha1" + "knative.dev/eventing/pkg/client/clientset/versioned/scheme" + "knative.dev/eventing/pkg/reconciler" + "knative.dev/eventing/pkg/reconciler/configmappropagation/resources" + "knative.dev/pkg/configmap" + "knative.dev/pkg/controller" + logtesting "knative.dev/pkg/logging/testing" + "knative.dev/pkg/tracker" + + . "knative.dev/eventing/pkg/reconciler/testing" + . "knative.dev/pkg/reconciler/testing" +) + +const ( + currentNS = "test-current-ns" + configMapPropagationName = "test-cmp" + originalConfigMapName = "test-original-cm" + originalNS = "knative-eventing" + + configMapPropagationGeneration = 7 +) + +var ( + selector = metav1.LabelSelector{ + MatchLabels: map[string]string{"testings": "testing"}, + } + originalSelector = metav1.LabelSelector{ + MatchLabels: map[string]string{ + "testings": "testing", + resources.PropagationLabelKey: resources.PropagationLabelValueOriginal, + }, + } + copySelector = metav1.LabelSelector{ + MatchLabels: map[string]string{ + resources.PropagationLabelKey: resources.PropagationLabelValueCopy, + resources.CopyLabelKey: resources.MakeCopyConfigMapLabel(currentNS, originalConfigMapName), + }, + } + copyConfigMapName = resources.MakeCopyConfigMapName(configMapPropagationName, originalConfigMapName) + originalData = map[string]string{"data": "original"} + copyData = map[string]string{"data": "copy"} +) + +func init() { + // Add types to scheme + _ = v1alpha1.AddToScheme(scheme.Scheme) +} + +func TestAllCase(t *testing.T) { + testKey := currentNS + "/" + configMapPropagationName + table := TableTest{ + { + Name: "bad workqueue key", + // Make sure Reconcile handles bad keys. + Key: "too/many/parts", + }, { + Name: "key not found", + // Make sure Reconcile handles good keys that don't exist. + Key: "foo/not-found", + }, { + Name: "ConfigMapPropagation not found", + Key: testKey, + }, { + Name: "ConfigMapPropagation is being deleted", + Key: testKey, + Objects: []runtime.Object{ + NewConfigMapPropagation(configMapPropagationName, currentNS, + WithInitConfigMapPropagationConditions, + WithConfigMapPropagationDeletionTimestamp, + WithInitConfigMapStatus(), + ), + }, + }, { + Name: "Original ConfigMap no longer has required labels", + Key: testKey, + Objects: []runtime.Object{ + NewConfigMapPropagation(configMapPropagationName, currentNS, + WithInitConfigMapPropagationConditions, + WithConfigMapPropagationSelector(selector), + WithInitConfigMapStatus(), + ), + NewConfigMap(originalConfigMapName, originalNS, + WithConfigMapLabels(metav1.LabelSelector{ + MatchLabels: map[string]string{}, + }), + ), + NewConfigMap(copyConfigMapName, currentNS, + WithConfigMapLabels(copySelector), + WithConfigMapOwnerReference(NewConfigMapPropagation(configMapPropagationName, currentNS, + WithInitConfigMapPropagationConditions, + WithConfigMapPropagationSelector(selector), + )), + ), + }, + WantDeletes: []clientgotesting.DeleteActionImpl{{ + Name: copyConfigMapName, + }}, + WantStatusUpdates: []clientgotesting.UpdateActionImpl{{ + Object: NewConfigMapPropagation(configMapPropagationName, currentNS, + WithInitConfigMapPropagationConditions, + WithConfigMapPropagationSelector(selector), + WithConfigMapPropagationPropagated, + WithInitConfigMapStatus(), + WithCopyConfigMapStatus("test-cmp-test-original-cm", "knative-eventing/test-original-cm", + "Delete", "True", ""), + ), + }}, + WantEvents: []string{ + Eventf(corev1.EventTypeNormal, configMapPropagationReadinessChanged, "ConfigMapPropagation %q became ready", configMapPropagationName), + }, + }, { + Name: "Original ConfigMap no longer exists, delete copy configMap succeeded", + Key: testKey, + Objects: []runtime.Object{ + NewConfigMapPropagation(configMapPropagationName, currentNS, + WithInitConfigMapPropagationConditions, + WithConfigMapPropagationSelector(selector), + WithInitConfigMapStatus(), + ), + NewConfigMap(copyConfigMapName, currentNS, + WithConfigMapLabels(copySelector), + WithConfigMapOwnerReference(NewConfigMapPropagation(configMapPropagationName, currentNS, + WithInitConfigMapPropagationConditions, + WithConfigMapPropagationSelector(selector), + )), + ), + }, + WantDeletes: []clientgotesting.DeleteActionImpl{{ + Name: copyConfigMapName, + }}, + WantStatusUpdates: []clientgotesting.UpdateActionImpl{{ + Object: NewConfigMapPropagation(configMapPropagationName, currentNS, + WithInitConfigMapPropagationConditions, + WithConfigMapPropagationSelector(selector), + WithConfigMapPropagationPropagated, + WithInitConfigMapStatus(), + WithCopyConfigMapStatus("test-cmp-test-original-cm", "knative-eventing/test-original-cm", + "Delete", "True", ""), + ), + }}, + WantEvents: []string{ + Eventf(corev1.EventTypeNormal, configMapPropagationReadinessChanged, "ConfigMapPropagation %q became ready", configMapPropagationName), + }, + }, { + Name: "Original ConfigMap no longer exists, delete copy configMap failed", + Key: testKey, + Objects: []runtime.Object{ + NewConfigMapPropagation(configMapPropagationName, currentNS, + WithInitConfigMapPropagationConditions, + WithConfigMapPropagationSelector(selector), + WithInitConfigMapStatus(), + ), + NewConfigMap(copyConfigMapName, currentNS, + WithConfigMapLabels(copySelector), + WithConfigMapOwnerReference(NewConfigMapPropagation(configMapPropagationName, currentNS, + WithInitConfigMapPropagationConditions, + WithConfigMapPropagationSelector(selector), + )), + ), + }, + WithReactors: []clientgotesting.ReactionFunc{ + InduceFailure("delete", "configmaps"), + }, + WantDeletes: []clientgotesting.DeleteActionImpl{{ + Name: copyConfigMapName, + }}, + WantStatusUpdates: []clientgotesting.UpdateActionImpl{{ + Object: NewConfigMapPropagation(configMapPropagationName, currentNS, + WithInitConfigMapPropagationConditions, + WithConfigMapPropagationSelector(selector), + WithConfigMapPropagationNotPropagated, + WithInitConfigMapStatus(), + WithCopyConfigMapStatus("test-cmp-test-original-cm", "knative-eventing/test-original-cm", + "Delete", "False", "inducing failure for delete configmaps"), + ), + }}, + WantErr: true, + WantEvents: []string{ + Eventf(corev1.EventTypeWarning, configMapPropagationPropagateSingleConfigMapFailed, + "Failed to propagate ConfigMap %v: inducing failure for delete configmaps", originalConfigMapName), + Eventf(corev1.EventTypeWarning, configMapPropagationReconcileError, + "ConfigMapPropagation reconcile error: one or more ConfigMap propagation failed"), + }, + }, { + Name: "Original ConfigMap has changed, update copy ConfigMap failed", + Key: testKey, + Objects: []runtime.Object{ + NewConfigMapPropagation(configMapPropagationName, currentNS, + WithInitConfigMapPropagationConditions, + WithConfigMapPropagationSelector(selector), + WithInitConfigMapStatus(), + ), + NewConfigMap(originalConfigMapName, originalNS, + WithConfigMapLabels(originalSelector), + WithConfigMapData(originalData), + ), + NewConfigMap(copyConfigMapName, currentNS, + WithConfigMapLabels(copySelector), + WithConfigMapOwnerReference(NewConfigMapPropagation(configMapPropagationName, currentNS, + WithInitConfigMapPropagationConditions, + WithConfigMapPropagationSelector(selector), + )), + ), + }, + WantUpdates: []clientgotesting.UpdateActionImpl{{ + Object: NewConfigMap(copyConfigMapName, currentNS, + WithConfigMapLabels(copySelector), + WithConfigMapData(originalData), + WithConfigMapOwnerReference(NewConfigMapPropagation(configMapPropagationName, currentNS, + WithInitConfigMapPropagationConditions, + WithConfigMapPropagationSelector(selector), + )), + ), + }}, + WithReactors: []clientgotesting.ReactionFunc{ + InduceFailure("update", "configmaps"), + }, + WantStatusUpdates: []clientgotesting.UpdateActionImpl{{ + Object: NewConfigMapPropagation(configMapPropagationName, currentNS, + WithInitConfigMapPropagationConditions, + WithConfigMapPropagationSelector(selector), + WithConfigMapPropagationNotPropagated, + WithInitConfigMapStatus(), + WithCopyConfigMapStatus("test-cmp-test-original-cm", "knative-eventing/test-original-cm", + "Copy", "False", "error updating ConfigMap in current namespace: inducing failure for update configmaps"), + ), + }}, + WantErr: true, + WantEvents: []string{ + Eventf(corev1.EventTypeWarning, configMapPropagationPropagateSingleConfigMapFailed, + "Failed to propagate ConfigMap %v: error updating ConfigMap in current namespace: inducing failure for update configmaps", originalConfigMapName), + Eventf(corev1.EventTypeWarning, configMapPropagationReconcileError, + "ConfigMapPropagation reconcile error: one or more ConfigMap propagation failed"), + }, + }, { + Name: "Original ConfigMap has changed, update copy ConfigMap succeeded", + Key: testKey, + Objects: []runtime.Object{ + NewConfigMapPropagation(configMapPropagationName, currentNS, + WithInitConfigMapPropagationConditions, + WithConfigMapPropagationSelector(selector), + WithInitConfigMapStatus(), + ), + NewConfigMap(originalConfigMapName, originalNS, + WithConfigMapLabels(originalSelector), + WithConfigMapData(originalData), + ), + NewConfigMap(copyConfigMapName, currentNS, + WithConfigMapLabels(copySelector), + WithConfigMapOwnerReference(NewConfigMapPropagation(configMapPropagationName, currentNS, + WithInitConfigMapPropagationConditions, + WithConfigMapPropagationSelector(selector), + )), + ), + }, + WantUpdates: []clientgotesting.UpdateActionImpl{{ + Object: NewConfigMap(copyConfigMapName, currentNS, + WithConfigMapLabels(copySelector), + WithConfigMapData(originalData), + WithConfigMapOwnerReference(NewConfigMapPropagation(configMapPropagationName, currentNS, + WithInitConfigMapPropagationConditions, + WithConfigMapPropagationSelector(selector), + )), + ), + }}, + WantStatusUpdates: []clientgotesting.UpdateActionImpl{{ + Object: NewConfigMapPropagation(configMapPropagationName, currentNS, + WithInitConfigMapPropagationConditions, + WithConfigMapPropagationSelector(selector), + WithConfigMapPropagationPropagated, + WithInitConfigMapStatus(), + WithCopyConfigMapStatus("test-cmp-test-original-cm", "knative-eventing/test-original-cm", + "Copy", "True", ""), + ), + }}, + WantEvents: []string{ + Eventf(corev1.EventTypeNormal, configMapPropagationPropagateSingleConfigMapSucceed, "Propagate ConfigMap test-original-cm succeed"), + Eventf(corev1.EventTypeNormal, configMapPropagationReadinessChanged, "ConfigMapPropagation %q became ready", configMapPropagationName), + }, + }, { + Name: "Copy ConfigMap has changed", + Key: testKey, + Objects: []runtime.Object{ + NewConfigMapPropagation(configMapPropagationName, currentNS, + WithInitConfigMapPropagationConditions, + WithConfigMapPropagationSelector(selector), + WithInitConfigMapStatus(), + ), + NewConfigMap(originalConfigMapName, originalNS, + WithConfigMapLabels(originalSelector), + WithConfigMapData(originalData), + ), + NewConfigMap(copyConfigMapName, currentNS, + WithConfigMapLabels(copySelector), + WithConfigMapData(copyData), + WithConfigMapOwnerReference(NewConfigMapPropagation(configMapPropagationName, currentNS, + WithInitConfigMapPropagationConditions, + WithConfigMapPropagationSelector(selector), + )), + ), + }, + WantUpdates: []clientgotesting.UpdateActionImpl{{ + Object: NewConfigMap(copyConfigMapName, currentNS, + WithConfigMapLabels(copySelector), + WithConfigMapData(originalData), + WithConfigMapOwnerReference(NewConfigMapPropagation(configMapPropagationName, currentNS, + WithInitConfigMapPropagationConditions, + WithConfigMapPropagationSelector(selector), + )), + ), + }}, + WantStatusUpdates: []clientgotesting.UpdateActionImpl{{ + Object: NewConfigMapPropagation(configMapPropagationName, currentNS, + WithInitConfigMapPropagationConditions, + WithConfigMapPropagationSelector(selector), + WithConfigMapPropagationPropagated, + WithInitConfigMapStatus(), + WithCopyConfigMapStatus("test-cmp-test-original-cm", "knative-eventing/test-original-cm", + "Copy", "True", ""), + ), + }}, + WantEvents: []string{ + Eventf(corev1.EventTypeNormal, configMapPropagationPropagateSingleConfigMapSucceed, "Propagate ConfigMap test-original-cm succeed"), + Eventf(corev1.EventTypeNormal, configMapPropagationReadinessChanged, "ConfigMapPropagation %q became ready", configMapPropagationName), + }, + }, { + Name: "Copy ConfigMap no longer has required labels", + Key: testKey, + Objects: []runtime.Object{ + NewConfigMapPropagation(configMapPropagationName, currentNS, + WithInitConfigMapPropagationConditions, + WithConfigMapPropagationSelector(selector), + ), + NewConfigMap(originalConfigMapName, originalNS, + WithConfigMapLabels(originalSelector), + ), + NewConfigMap(copyConfigMapName, currentNS, + WithConfigMapLabels(metav1.LabelSelector{ + MatchLabels: map[string]string{}, + }), + WithConfigMapOwnerReference(NewConfigMapPropagation(configMapPropagationName, currentNS, + WithInitConfigMapPropagationConditions, + WithConfigMapPropagationSelector(selector), + )), + ), + }, + WantUpdates: []clientgotesting.UpdateActionImpl{{ + Object: NewConfigMap(copyConfigMapName, currentNS, + WithConfigMapLabels(metav1.LabelSelector{ + MatchLabels: map[string]string{}, + }), + ), + }}, + WantStatusUpdates: []clientgotesting.UpdateActionImpl{{ + Object: NewConfigMapPropagation(configMapPropagationName, currentNS, + WithInitConfigMapPropagationConditions, + WithConfigMapPropagationSelector(selector), + WithConfigMapPropagationPropagated, + WithInitConfigMapStatus(), + WithCopyConfigMapStatus("test-cmp-test-original-cm", "knative-eventing/test-original-cm", + "Stop", "True", `copy ConfigMap doesn't have copy label, stop propagating this ConfigMap`), + ), + }}, + WantErr: false, + WantEvents: []string{ + Eventf(corev1.EventTypeNormal, configMapPropagationPropagateSingleConfigMapSucceed, + `Stop propagating ConfigMap: test-original-cm`), + Eventf(corev1.EventTypeNormal, configMapPropagationReadinessChanged, "ConfigMapPropagation %q became ready", configMapPropagationName), + }, + }, { + Name: "Create new ConfigMap failed", + Key: testKey, + Objects: []runtime.Object{ + NewConfigMapPropagation(configMapPropagationName, currentNS, + WithInitConfigMapPropagationConditions, + WithConfigMapPropagationSelector(selector), + WithInitConfigMapStatus(), + ), + NewConfigMap(originalConfigMapName, originalNS, + WithConfigMapLabels(originalSelector), + ), + }, + WantCreates: []runtime.Object{ + NewConfigMap(copyConfigMapName, currentNS, + WithConfigMapLabels(copySelector), + WithConfigMapOwnerReference(NewConfigMapPropagation(configMapPropagationName, currentNS, + WithInitConfigMapPropagationConditions, + WithConfigMapPropagationSelector(selector), + )), + ), + }, + WithReactors: []clientgotesting.ReactionFunc{ + InduceFailure("create", "configmaps"), + }, + WantStatusUpdates: []clientgotesting.UpdateActionImpl{{ + Object: NewConfigMapPropagation(configMapPropagationName, currentNS, + WithInitConfigMapPropagationConditions, + WithConfigMapPropagationSelector(selector), + WithConfigMapPropagationNotPropagated, + WithInitConfigMapStatus(), + WithCopyConfigMapStatus("test-cmp-test-original-cm", "knative-eventing/test-original-cm", + "Copy", "False", "error creating ConfigMap in current namespace: inducing failure for create configmaps"), + ), + }}, + WantErr: true, + WantEvents: []string{ + Eventf(corev1.EventTypeWarning, configMapPropagationPropagateSingleConfigMapFailed, + "Failed to propagate ConfigMap %v: error creating ConfigMap in current namespace: inducing failure for create configmaps", originalConfigMapName), + Eventf(corev1.EventTypeWarning, configMapPropagationReconcileError, + "ConfigMapPropagation reconcile error: one or more ConfigMap propagation failed"), + }, + }, { + Name: "Successfully reconcile, became ready", + Key: testKey, + Objects: []runtime.Object{ + NewConfigMapPropagation(configMapPropagationName, currentNS, + WithInitConfigMapPropagationConditions, + WithConfigMapPropagationSelector(selector), + WithConfigMapPropagationGeneration(configMapPropagationGeneration), + WithInitConfigMapStatus(), + ), + NewConfigMap(originalConfigMapName, originalNS, + WithConfigMapLabels(originalSelector), + ), + }, + WantCreates: []runtime.Object{ + NewConfigMap(copyConfigMapName, currentNS, + WithConfigMapLabels(copySelector), + WithConfigMapOwnerReference(NewConfigMapPropagation(configMapPropagationName, currentNS, + WithInitConfigMapPropagationConditions, + WithConfigMapPropagationSelector(selector), + )), + ), + }, + WantStatusUpdates: []clientgotesting.UpdateActionImpl{{ + Object: NewConfigMapPropagation(configMapPropagationName, currentNS, + WithInitConfigMapPropagationConditions, + WithConfigMapPropagationSelector(selector), + WithConfigMapPropagationPropagated, + WithConfigMapPropagationGeneration(configMapPropagationGeneration), + WithConfigMapPropagationStatusObservedGeneration(configMapPropagationGeneration), + WithInitConfigMapStatus(), + WithCopyConfigMapStatus("test-cmp-test-original-cm", "knative-eventing/test-original-cm", + "Copy", "True", ""), + ), + }}, + WantEvents: []string{ + Eventf(corev1.EventTypeNormal, configMapPropagationPropagateSingleConfigMapSucceed, "Propagate ConfigMap test-original-cm succeed"), + Eventf(corev1.EventTypeNormal, configMapPropagationReadinessChanged, "ConfigMapPropagation %q became ready", configMapPropagationName), + }, + }, + } + logger := logtesting.TestLogger(t) + table.Test(t, MakeFactory(func(ctx context.Context, listers *Listers, cmw configmap.Watcher) controller.Reconciler { + return &Reconciler{ + Base: reconciler.NewBase(ctx, controllerAgentName, cmw), + configMapPropagationLister: listers.GetConfigMapPropagationLister(), + configMapLister: listers.GetConfigMapLister(), + tracker: tracker.New(func(types.NamespacedName) {}, 0), + } + }, + false, + logger, + )) +} diff --git a/pkg/reconciler/configmappropagation/controller.go b/pkg/reconciler/configmappropagation/controller.go new file mode 100644 index 00000000000..7808253ac45 --- /dev/null +++ b/pkg/reconciler/configmappropagation/controller.go @@ -0,0 +1,71 @@ +/* +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 configmappropagation + +import ( + "context" + + "knative.dev/eventing/pkg/reconciler" + "knative.dev/pkg/configmap" + "knative.dev/pkg/controller" + "knative.dev/pkg/tracker" + + corev1 "k8s.io/api/core/v1" + configmappropagationinformer "knative.dev/eventing/pkg/client/injection/informers/configs/v1alpha1/configmappropagation" + configmapinformer "knative.dev/pkg/client/injection/kube/informers/core/v1/configmap" +) + +const ( + // ReconcilerName is the name of the reconciler. + ReconcilerName = "ConfigMapPropagation" + // controllerAgentName is the string used by this controller to identify + // itself when creating events. + controllerAgentName = "configmappropagation-controller" +) + +// NewController initializes the controller and is called by the generated code +// Registers event handlers to enqueue events +func NewController( + ctx context.Context, + cmw configmap.Watcher, +) *controller.Impl { + + configMapPropagationInformer := configmappropagationinformer.Get(ctx) + configMapInformer := configmapinformer.Get(ctx) + + r := &Reconciler{ + Base: reconciler.NewBase(ctx, controllerAgentName, cmw), + configMapPropagationLister: configMapPropagationInformer.Lister(), + configMapLister: configMapInformer.Lister(), + } + impl := controller.NewImpl(r, r.Logger, ReconcilerName) + + r.Logger.Info("Setting up event handlers") + configMapPropagationInformer.Informer().AddEventHandler(controller.HandleAll(impl.Enqueue)) + + // Tracker is used to notify us that a ConfigMap has changed so that + // we can reconcile. + r.tracker = tracker.New(impl.EnqueueKey, controller.GetTrackerLease(ctx)) + configMapInformer.Informer().AddEventHandler(controller.HandleAll( + controller.EnsureTypeMeta( + r.tracker.OnChanged, + corev1.SchemeGroupVersion.WithKind("ConfigMap"), + ), + )) + + return impl +} diff --git a/pkg/reconciler/configmappropagation/controller_test.go b/pkg/reconciler/configmappropagation/controller_test.go new file mode 100644 index 00000000000..f74d38f89e1 --- /dev/null +++ b/pkg/reconciler/configmappropagation/controller_test.go @@ -0,0 +1,40 @@ +/* +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 configmappropagation + +import ( + "testing" + + "knative.dev/pkg/configmap" + + . "knative.dev/pkg/reconciler/testing" + + // Fake injection informers + _ "knative.dev/eventing/pkg/client/injection/informers/configs/v1alpha1/configmappropagation/fake" + _ "knative.dev/pkg/client/injection/kube/informers/core/v1/configmap/fake" + _ "knative.dev/pkg/injection/clients/dynamicclient/fake" +) + +func TestNew(t *testing.T) { + ctx, _ := SetupFakeContext(t) + + c := NewController(ctx, configmap.NewStaticWatcher()) + + if c == nil { + t.Fatal("Expected NewController to return a non-nil value") + } +} diff --git a/pkg/reconciler/configmappropagation/resources/configmap.go b/pkg/reconciler/configmappropagation/resources/configmap.go new file mode 100644 index 00000000000..0eb47485a9f --- /dev/null +++ b/pkg/reconciler/configmappropagation/resources/configmap.go @@ -0,0 +1,57 @@ +/* +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 resources + +import ( + configsv1alpha1 "knative.dev/eventing/pkg/apis/configs/v1alpha1" + "knative.dev/pkg/kmeta" + + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +type ConfigMapArgs struct { + Original *corev1.ConfigMap + ConfigMapPropagation *configsv1alpha1.ConfigMapPropagation +} + +func MakeConfigMap(args ConfigMapArgs) *corev1.ConfigMap { + return &corev1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + Name: MakeCopyConfigMapName(args.ConfigMapPropagation.Name, args.Original.Name), + Namespace: args.ConfigMapPropagation.Namespace, + Labels: map[string]string{ + PropagationLabelKey: PropagationLabelValueCopy, + CopyLabelKey: MakeCopyConfigMapLabel(args.ConfigMapPropagation.Namespace, args.Original.Name), + }, + OwnerReferences: []metav1.OwnerReference{ + *kmeta.NewControllerRef(args.ConfigMapPropagation), + }, + }, + Data: args.Original.Data, + } +} + +func MakeCopyConfigMapName(configMapPropagationName, configMapName string) string { + return configMapPropagationName + "-" + configMapName +} + +// MakeCopyCOnfigMapLabel uses '-' to separate namespace and configmap name instead of '/', +// for label values only accept '-', '.', '_'. +func MakeCopyConfigMapLabel(configMapPropagationNamespace, configMapName string) string { + return configMapPropagationNamespace + "-" + configMapName +} diff --git a/pkg/reconciler/configmappropagation/resources/configmap_test.go b/pkg/reconciler/configmappropagation/resources/configmap_test.go new file mode 100644 index 00000000000..9cff2a3a72c --- /dev/null +++ b/pkg/reconciler/configmappropagation/resources/configmap_test.go @@ -0,0 +1,77 @@ +/* +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 resources + +import ( + "reflect" + "testing" + + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + configsv1alpha1 "knative.dev/eventing/pkg/apis/configs/v1alpha1" +) + +func TestMakeConfigMap(t *testing.T) { + testCases := map[string]struct { + original *corev1.ConfigMap + configmappropagation *configsv1alpha1.ConfigMapPropagation + }{ + "general configmap": { + original: &corev1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + Name: "original-config-map", + }, + }, + configmappropagation: &configsv1alpha1.ConfigMapPropagation{ + ObjectMeta: metav1.ObjectMeta{ + Name: "cmp", + Namespace: "testing", + }, + }, + }, + } + for n, tc := range testCases { + t.Run(n, func(t *testing.T) { + configmap := MakeConfigMap(ConfigMapArgs{ + tc.original, tc.configmappropagation, + }) + // If name and namespace are correct. + if name := configmap.Name; name != "cmp-original-config-map" { + t.Errorf("want %v, got %v", "cmp-original-config-map", name) + } + + if ns := configmap.Namespace; ns != tc.configmappropagation.Namespace { + t.Errorf("want %v, got %v", tc.configmappropagation.Namespace, ns) + } + + // If OwnerReferences is correct. + if !metav1.IsControlledBy(configmap, tc.configmappropagation) { + t.Errorf("Expected configmap to be controlled by the configmappropagation") + } + + // If labels are correct. + expectedLabels := map[string]string{ + PropagationLabelKey: PropagationLabelValueCopy, + CopyLabelKey: "testing-original-config-map", + } + if labels := configmap.Labels; !reflect.DeepEqual(labels, expectedLabels) { + t.Errorf("want %v, got %q", expectedLabels, labels) + } + }) + } +} diff --git a/pkg/reconciler/configmappropagation/resources/labels.go b/pkg/reconciler/configmappropagation/resources/labels.go new file mode 100644 index 00000000000..4f092750a63 --- /dev/null +++ b/pkg/reconciler/configmappropagation/resources/labels.go @@ -0,0 +1,40 @@ +/* +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 resources + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/labels" +) + +const ( + PropagationLabelKey = "knative.dev/config-propagation" + PropagationLabelValueOriginal = "original" + PropagationLabelValueCopy = "copy" + CopyLabelKey = "knative.dev/config-original" +) + +// ExpectedOriginalSelector with return a selector which matches the input set with an additional label "knative.dev/config-propagation: original" +// This is the expected selector to select original configmaps +func ExpectedOriginalSelector(selector *metav1.LabelSelector) labels.Selector { + expectedOriginalSelector := selector.DeepCopy() + // Add original label if it doesn't exist + if expectedOriginalSelector.MatchLabels[PropagationLabelKey] == "" { + metav1.AddLabelToSelector(expectedOriginalSelector, PropagationLabelKey, PropagationLabelValueOriginal) + } + return labels.SelectorFromSet(expectedOriginalSelector.MatchLabels) +} diff --git a/pkg/reconciler/configmappropagation/resources/labels_test.go b/pkg/reconciler/configmappropagation/resources/labels_test.go new file mode 100644 index 00000000000..0e561c0ee66 --- /dev/null +++ b/pkg/reconciler/configmappropagation/resources/labels_test.go @@ -0,0 +1,78 @@ +/* +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 resources + +import ( + "reflect" + "testing" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/labels" +) + +func TestOriginalLabels(t *testing.T) { + testCases := []struct { + Name string + F func() labels.Selector + Want labels.Selector + }{{ + Name: "empty map", + F: func() labels.Selector { + return ExpectedOriginalSelector(&metav1.LabelSelector{ + MatchLabels: map[string]string{}, + }) + }, + Want: labels.SelectorFromSet(map[string]string{ + PropagationLabelKey: PropagationLabelValueOriginal, + }), + }, { + Name: "map with existing keys", + F: func() labels.Selector { + return ExpectedOriginalSelector(&metav1.LabelSelector{ + MatchLabels: map[string]string{ + "testing": "testing", + }, + }) + }, + Want: labels.SelectorFromSet(map[string]string{ + "testing": "testing", + PropagationLabelKey: PropagationLabelValueOriginal, + }), + }, { + Name: "map with original key", + F: func() labels.Selector { + return ExpectedOriginalSelector(&metav1.LabelSelector{ + MatchLabels: map[string]string{ + "testing": "testing", + PropagationLabelKey: PropagationLabelValueOriginal, + }, + }) + }, + Want: labels.SelectorFromSet(map[string]string{ + "testing": "testing", + PropagationLabelKey: PropagationLabelValueOriginal, + }), + }} + + for _, tc := range testCases { + t.Run(tc.Name, func(t *testing.T) { + if got := tc.F(); !reflect.DeepEqual(got, tc.Want) { + t.Errorf("want %v, got %v", tc.Want, got) + } + }) + } +} diff --git a/pkg/reconciler/inmemorychannel/dispatcher/controller.go b/pkg/reconciler/inmemorychannel/dispatcher/controller.go index 1b54f9b4d88..f762873254c 100644 --- a/pkg/reconciler/inmemorychannel/dispatcher/controller.go +++ b/pkg/reconciler/inmemorychannel/dispatcher/controller.go @@ -29,6 +29,7 @@ import ( "knative.dev/eventing/pkg/tracing" "knative.dev/pkg/configmap" "knative.dev/pkg/controller" + tracingconfig "knative.dev/pkg/tracing/config" ) const ( @@ -54,7 +55,7 @@ func NewController( // Setup trace publishing. iw := cmw.(*configmap.InformedWatcher) - if err := tracing.SetupDynamicPublishing(base.Logger, iw, "imc-dispatcher"); err != nil { + if err := tracing.SetupDynamicPublishing(base.Logger, iw, "imc-dispatcher", tracingconfig.ConfigName); err != nil { base.Logger.Fatalw("Error setting up trace publishing", zap.Error(err)) } diff --git a/pkg/reconciler/namespace/controller.go b/pkg/reconciler/namespace/controller.go index caab0b6781c..036d92ffcee 100644 --- a/pkg/reconciler/namespace/controller.go +++ b/pkg/reconciler/namespace/controller.go @@ -26,6 +26,7 @@ import ( "knative.dev/eventing/pkg/reconciler" + "knative.dev/eventing/pkg/client/injection/informers/configs/v1alpha1/configmappropagation" "knative.dev/eventing/pkg/client/injection/informers/eventing/v1alpha1/broker" "knative.dev/pkg/client/injection/kube/informers/core/v1/namespace" "knative.dev/pkg/client/injection/kube/informers/core/v1/serviceaccount" @@ -56,6 +57,7 @@ func NewController( serviceAccountInformer := serviceaccount.Get(ctx) roleBindingInformer := rolebinding.Get(ctx) brokerInformer := broker.Get(ctx) + configMapPropagationInformer := configmappropagation.Get(ctx) r := &Reconciler{ Base: reconciler.NewBase(ctx, controllerAgentName, cmw), @@ -87,6 +89,9 @@ func NewController( brokerInformer.Informer().AddEventHandler(controller.HandleAll( controller.EnsureTypeMeta(r.tracker.OnChanged, brokerGVK), )) + configMapPropagationInformer.Informer().AddEventHandler(controller.HandleAll( + controller.EnsureTypeMeta(r.tracker.OnChanged, configMapPropagationGVK), + )) return impl } diff --git a/pkg/reconciler/namespace/controller_test.go b/pkg/reconciler/namespace/controller_test.go index 7fa0f0b87fe..31d244f4ab0 100644 --- a/pkg/reconciler/namespace/controller_test.go +++ b/pkg/reconciler/namespace/controller_test.go @@ -23,6 +23,7 @@ import ( . "knative.dev/pkg/reconciler/testing" // Fake injection informers + _ "knative.dev/eventing/pkg/client/injection/informers/configs/v1alpha1/configmappropagation/fake" _ "knative.dev/eventing/pkg/client/injection/informers/eventing/v1alpha1/broker/fake" _ "knative.dev/pkg/client/injection/kube/informers/core/v1/namespace/fake" _ "knative.dev/pkg/client/injection/kube/informers/core/v1/serviceaccount/fake" diff --git a/pkg/reconciler/namespace/namespace.go b/pkg/reconciler/namespace/namespace.go index 72a9ab3241f..ffb9ecb7cf8 100644 --- a/pkg/reconciler/namespace/namespace.go +++ b/pkg/reconciler/namespace/namespace.go @@ -28,6 +28,7 @@ import ( corev1listers "k8s.io/client-go/listers/core/v1" rbacv1listers "k8s.io/client-go/listers/rbac/v1" + configslisters "knative.dev/eventing/pkg/client/listers/configs/v1alpha1" eventinglisters "knative.dev/eventing/pkg/client/listers/eventing/v1alpha1" "go.uber.org/zap" @@ -36,6 +37,7 @@ import ( apierrs "k8s.io/apimachinery/pkg/api/errors" k8serrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + configsv1alpha1 "knative.dev/eventing/pkg/apis/configs/v1alpha1" "knative.dev/eventing/pkg/apis/eventing/v1alpha1" "knative.dev/eventing/pkg/logging" "knative.dev/eventing/pkg/reconciler" @@ -47,17 +49,19 @@ const ( namespaceReconcileFailure = "NamespaceReconcileFailure" // Name of the corev1.Events emitted from the reconciliation process. - brokerCreated = "BrokerCreated" - serviceAccountCreated = "BrokerServiceAccountCreated" - serviceAccountRBACCreated = "BrokerServiceAccountRBACCreated" - secretCopied = "SecretCopied" - secretCopyFailure = "SecretCopyFailure" + configMapPropagationCreated = "ConfigMapPropagationCreated" + brokerCreated = "BrokerCreated" + serviceAccountCreated = "BrokerServiceAccountCreated" + serviceAccountRBACCreated = "BrokerServiceAccountRBACCreated" + secretCopied = "SecretCopied" + secretCopyFailure = "SecretCopyFailure" ) var ( - serviceAccountGVK = corev1.SchemeGroupVersion.WithKind("ServiceAccount") - roleBindingGVK = rbacv1.SchemeGroupVersion.WithKind("RoleBinding") - brokerGVK = v1alpha1.SchemeGroupVersion.WithKind("Broker") + serviceAccountGVK = corev1.SchemeGroupVersion.WithKind("ServiceAccount") + roleBindingGVK = rbacv1.SchemeGroupVersion.WithKind("RoleBinding") + brokerGVK = v1alpha1.SchemeGroupVersion.WithKind("Broker") + configMapPropagationGVK = configsv1alpha1.SchemeGroupVersion.WithKind("ConfigMapPropagation") ) type Reconciler struct { @@ -66,11 +70,12 @@ type Reconciler struct { brokerPullSecretName string // listers index properties about resources - namespaceLister corev1listers.NamespaceLister - serviceAccountLister corev1listers.ServiceAccountLister - roleBindingLister rbacv1listers.RoleBindingLister - brokerLister eventinglisters.BrokerLister - tracker tracker.Interface + namespaceLister corev1listers.NamespaceLister + serviceAccountLister corev1listers.ServiceAccountLister + roleBindingLister rbacv1listers.RoleBindingLister + brokerLister eventinglisters.BrokerLister + configMapPropagationLister configslisters.ConfigMapPropagationLister + tracker tracker.Interface } // Check that our Reconciler implements controller.Reconciler @@ -121,62 +126,80 @@ func (r *Reconciler) reconcile(ctx context.Context, ns *corev1.Namespace) error if ns.DeletionTimestamp != nil { return nil } - if err := r.reconcileServiceAccountAndRoleBindings(ctx, ns, resources.IngressServiceAccountName, resources.IngressRoleBindingName, resources.IngressClusterRoleName, resources.ConfigClusterRoleName); err != nil { - return fmt.Errorf("broker ingress: %v", err) + + cmp, err := r.reconcileConfigMapPropagation(ctx, ns) + if err != nil { + return fmt.Errorf("configMapPropagation: %w", err) + } + + // Tell tracker to reconcile this namespace whenever the ConfigMapPropagation changes. + if err = r.tracker.Track(utils.ObjectRef(cmp, configMapPropagationGVK), ns); err != nil { + return fmt.Errorf("track configMapPropagation: %w", err) } - if err := r.reconcileServiceAccountAndRoleBindings(ctx, ns, resources.FilterServiceAccountName, resources.FilterRoleBindingName, resources.FilterClusterRoleName, resources.ConfigClusterRoleName); err != nil { - return fmt.Errorf("broker filter: %v", err) + if err := r.reconcileServiceAccountAndRoleBindings(ctx, ns, resources.IngressServiceAccountName, resources.IngressRoleBindingName, resources.IngressClusterRoleName); err != nil { + return fmt.Errorf("broker ingress: %w", err) + } + + if err := r.reconcileServiceAccountAndRoleBindings(ctx, ns, resources.FilterServiceAccountName, resources.FilterRoleBindingName, resources.FilterClusterRoleName); err != nil { + return fmt.Errorf("broker filter: %w", err) } b, err := r.reconcileBroker(ctx, ns) if err != nil { - return fmt.Errorf("broker: %v", err) + return fmt.Errorf("broker: %w", err) } // Tell tracker to reconcile this namespace whenever the Broker changes. if err = r.tracker.Track(utils.ObjectRef(b, brokerGVK), ns); err != nil { - return fmt.Errorf("track broker: %v", err) + return fmt.Errorf("track broker: %w", err) } return nil } +// reconcileConfigMapPropagation reconciles the default ConfigMapPropagation for the Namespace 'ns'. +func (r *Reconciler) reconcileConfigMapPropagation(ctx context.Context, ns *corev1.Namespace) (*configsv1alpha1.ConfigMapPropagation, error) { + current, err := r.EventingClientSet.ConfigsV1alpha1().ConfigMapPropagations(ns.Name).Get(resources.DefaultConfigMapPropagationName, metav1.GetOptions{}) + + // If the resource doesn't exist, we'll create it. + if k8serrors.IsNotFound(err) { + cmp := resources.MakeConfigMapPropagation(ns.Name) + cmp, err = r.EventingClientSet.ConfigsV1alpha1().ConfigMapPropagations(ns.Name).Create(cmp) + if err != nil { + return nil, err + } + r.Recorder.Event(ns, corev1.EventTypeNormal, configMapPropagationCreated, + "Default ConfigMapPropagation: "+cmp.Name+" created") + return cmp, nil + } else if err != nil { + return nil, err + } + // Don't update anything that is already present. + return current, nil +} + // reconcileServiceAccountAndRoleBinding reconciles the service account and role binding for // Namespace 'ns'. -func (r *Reconciler) reconcileServiceAccountAndRoleBindings(ctx context.Context, ns *corev1.Namespace, saName, rbName, clusterRoleName, configClusterRoleName string) error { - +func (r *Reconciler) reconcileServiceAccountAndRoleBindings(ctx context.Context, ns *corev1.Namespace, saName, rbName, clusterRoleName string) error { sa, err := r.reconcileBrokerServiceAccount(ctx, ns, resources.MakeServiceAccount(ns.Name, saName)) if err != nil { - return fmt.Errorf("service account '%s': %v", saName, err) + return fmt.Errorf("service account '%s': %w", saName, err) } // Tell tracker to reconcile this namespace whenever the Service Account changes. if err = r.tracker.Track(utils.ObjectRef(sa, serviceAccountGVK), ns); err != nil { - return fmt.Errorf("track service account '%s': %v", sa.Name, err) + return fmt.Errorf("track service account '%s': %w", sa.Name, err) } rb, err := r.reconcileBrokerRBAC(ctx, ns, sa, resources.MakeRoleBinding(rbName, ns.Name, sa, clusterRoleName)) if err != nil { - return fmt.Errorf("role binding '%s': %v", rbName, err) - } - - // Tell tracker to reconcile this namespace whenever the RoleBinding changes. - if err = r.tracker.Track(utils.ObjectRef(rb, roleBindingGVK), ns); err != nil { - return fmt.Errorf("track role binding '%s': %v", rb.Name, err) - } - - // Reconcile the RoleBinding allowing read access to the shared configmaps. - // Note this RoleBinding is created in the system namespace and points to a - // subject in the Broker's namespace. - rb, err = r.reconcileBrokerRBAC(ctx, ns, sa, resources.MakeRoleBinding(resources.ConfigRoleBindingName(sa.Name, ns.Name), system.Namespace(), sa, configClusterRoleName)) - if err != nil { - return fmt.Errorf("role binding '%s': %v", rbName, err) + return fmt.Errorf("role binding '%s': %w", rbName, err) } // Tell tracker to reconcile this namespace whenever the RoleBinding changes. if err = r.tracker.Track(utils.ObjectRef(rb, roleBindingGVK), ns); err != nil { - return fmt.Errorf("track role binding '%s': %v", rb.Name, err) + return fmt.Errorf("track role binding '%s': %w", rb.Name, err) } // If the Broker pull secret has not been specified, then nothing to copy. @@ -194,8 +217,8 @@ func (r *Reconciler) reconcileServiceAccountAndRoleBindings(ctx context.Context, _, err := utils.CopySecret(r.KubeClientSet.CoreV1(), system.Namespace(), r.brokerPullSecretName, ns.Name, sa.Name) if err != nil { r.Recorder.Event(ns, corev1.EventTypeWarning, secretCopyFailure, - fmt.Sprintf("Error copying secret %s/%s => %s/%s : %s", system.Namespace(), r.brokerPullSecretName, ns.Name, sa.Name, err)) - return fmt.Errorf("Error copying secret %s/%s => %s/%s : %s", system.Namespace(), r.brokerPullSecretName, ns.Name, sa.Name, err) + fmt.Sprintf("Error copying secret %s/%s => %s/%s : %v", system.Namespace(), r.brokerPullSecretName, ns.Name, sa.Name, err)) + return fmt.Errorf("Error copying secret %s/%s => %s/%s : %w", system.Namespace(), r.brokerPullSecretName, ns.Name, sa.Name, err) } else { r.Recorder.Event(ns, corev1.EventTypeNormal, secretCopied, fmt.Sprintf("Secret copied into namespace %s/%s => %s/%s", system.Namespace(), r.brokerPullSecretName, ns.Name, sa.Name)) diff --git a/pkg/reconciler/namespace/namespace_test.go b/pkg/reconciler/namespace/namespace_test.go index 1e3f7e8c069..be9c3386b9f 100644 --- a/pkg/reconciler/namespace/namespace_test.go +++ b/pkg/reconciler/namespace/namespace_test.go @@ -22,7 +22,6 @@ import ( "knative.dev/pkg/configmap" "knative.dev/pkg/system" - "knative.dev/pkg/tracker" "k8s.io/apimachinery/pkg/runtime" @@ -74,12 +73,11 @@ func init() { func TestAllCases(t *testing.T) { // Events + cmpEvent := Eventf(corev1.EventTypeNormal, "ConfigMapPropagationCreated", "Default ConfigMapPropagation: eventing created") saIngressEvent := Eventf(corev1.EventTypeNormal, "BrokerServiceAccountCreated", "ServiceAccount 'eventing-broker-ingress' created for the Broker") rbIngressEvent := Eventf(corev1.EventTypeNormal, "BrokerServiceAccountRBACCreated", "RoleBinding 'test-namespace/eventing-broker-ingress' created for the Broker") - rbIngressConfigEvent := Eventf(corev1.EventTypeNormal, "BrokerServiceAccountRBACCreated", "RoleBinding 'knative-testing/eventing-broker-ingress-test-namespace' created for the Broker") saFilterEvent := Eventf(corev1.EventTypeNormal, "BrokerServiceAccountCreated", "ServiceAccount 'eventing-broker-filter' created for the Broker") rbFilterEvent := Eventf(corev1.EventTypeNormal, "BrokerServiceAccountRBACCreated", "RoleBinding 'test-namespace/eventing-broker-filter' created for the Broker") - rbFilterConfigEvent := Eventf(corev1.EventTypeNormal, "BrokerServiceAccountRBACCreated", "RoleBinding 'knative-testing/eventing-broker-filter-test-namespace' created for the Broker") brokerEvent := Eventf(corev1.EventTypeNormal, "BrokerCreated", "Default eventing.knative.dev Broker created.") nsEvent := Eventf(corev1.EventTypeNormal, "NamespaceReconciled", "Namespace reconciled: \"test-namespace\"") nsEventFailure := Eventf(corev1.EventTypeWarning, "NamespaceReconcileFailure", "Failed to reconcile Namespace: broker ingress: Error copying secret knative-testing/broker-image-pull-secret => test-namespace/eventing-broker-ingress : secrets \"broker-image-pull-secret\" not found") @@ -97,10 +95,9 @@ func TestAllCases(t *testing.T) { broker := resources.MakeBroker(testNS) saIngress := resources.MakeServiceAccount(testNS, resources.IngressServiceAccountName) rbIngress := resources.MakeRoleBinding(resources.IngressRoleBindingName, testNS, resources.MakeServiceAccount(testNS, resources.IngressServiceAccountName), resources.IngressClusterRoleName) - rbIngressConfig := resources.MakeRoleBinding(resources.ConfigRoleBindingName(resources.IngressServiceAccountName, testNS), system.Namespace(), resources.MakeServiceAccount(testNS, resources.IngressServiceAccountName), resources.ConfigClusterRoleName) saFilter := resources.MakeServiceAccount(testNS, resources.FilterServiceAccountName) rbFilter := resources.MakeRoleBinding(resources.FilterRoleBindingName, testNS, resources.MakeServiceAccount(testNS, resources.FilterServiceAccountName), resources.FilterClusterRoleName) - rbFilterConfig := resources.MakeRoleBinding(resources.ConfigRoleBindingName(resources.FilterServiceAccountName, testNS), system.Namespace(), resources.MakeServiceAccount(testNS, resources.FilterServiceAccountName), resources.ConfigClusterRoleName) + configMapPropagation := resources.MakeConfigMapPropagation(testNS) table := TableTest{{ Name: "bad workqueue key", @@ -146,27 +143,25 @@ func TestAllCases(t *testing.T) { SkipNamespaceValidation: true, WantErr: false, WantEvents: []string{ + cmpEvent, saIngressEvent, rbIngressEvent, - rbIngressConfigEvent, secretEventIngress, saFilterEvent, rbFilterEvent, - rbFilterConfigEvent, secretEventFilter, brokerEvent, nsEvent, }, WantCreates: []runtime.Object{ + configMapPropagation, broker, secret, saIngress, rbIngress, - rbIngressConfig, secret, saFilter, rbFilter, - rbFilterConfig, secret, }, WantPatches: []clientgotesting.PatchActionImpl{ @@ -187,16 +182,35 @@ func TestAllCases(t *testing.T) { InduceFailure("create", "secrets"), }, WantEvents: []string{ + cmpEvent, saIngressEvent, rbIngressEvent, - rbIngressConfigEvent, secretEventFailure, nsEventFailure, }, WantCreates: []runtime.Object{ + configMapPropagation, saIngress, rbIngress, - rbIngressConfig, + }, + }, { + Name: "Namespace enabled - configmappropagation fails", + Objects: []runtime.Object{ + NewNamespace(testNS, + WithNamespaceLabeled(resources.InjectionEnabledLabels()), + ), + }, + Key: testNS, + SkipNamespaceValidation: true, + WantErr: true, + WithReactors: []clientgotesting.ReactionFunc{ + InduceFailure("create", "configmappropagations"), + }, + WantEvents: []string{ + Eventf(corev1.EventTypeWarning, "NamespaceReconcileFailure", "Failed to reconcile Namespace: configMapPropagation: inducing failure for create configmappropagations"), + }, + WantCreates: []runtime.Object{ + configMapPropagation, }, }, { Name: "Namespace enabled, broker exists", @@ -210,25 +224,23 @@ func TestAllCases(t *testing.T) { SkipNamespaceValidation: true, WantErr: false, WantEvents: []string{ + cmpEvent, saIngressEvent, rbIngressEvent, - rbIngressConfigEvent, secretEventIngress, saFilterEvent, rbFilterEvent, - rbFilterConfigEvent, secretEventFilter, nsEvent, }, WantCreates: []runtime.Object{ + configMapPropagation, secret, saIngress, rbIngress, - rbIngressConfig, secret, saFilter, rbFilter, - rbFilterConfig, secret, }, WantPatches: []clientgotesting.PatchActionImpl{ @@ -263,25 +275,23 @@ func TestAllCases(t *testing.T) { SkipNamespaceValidation: true, WantErr: false, WantEvents: []string{ + cmpEvent, rbIngressEvent, - rbIngressConfigEvent, secretEventIngress, saFilterEvent, rbFilterEvent, - rbFilterConfigEvent, secretEventFilter, brokerEvent, nsEvent, }, WantCreates: []runtime.Object{ + configMapPropagation, broker, secret, rbIngress, - rbIngressConfig, secret, saFilter, rbFilter, - rbFilterConfig, secret, }, WantPatches: []clientgotesting.PatchActionImpl{ @@ -295,29 +305,28 @@ func TestAllCases(t *testing.T) { WithNamespaceLabeled(resources.InjectionEnabledLabels()), ), rbIngress, - rbIngressConfig, }, Key: testNS, SkipNamespaceValidation: true, WantErr: false, WantEvents: []string{ + cmpEvent, saIngressEvent, secretEventIngress, saFilterEvent, rbFilterEvent, - rbFilterConfigEvent, secretEventFilter, brokerEvent, nsEvent, }, WantCreates: []runtime.Object{ + configMapPropagation, broker, secret, saIngress, secret, saFilter, rbFilter, - rbFilterConfig, secret, }, WantPatches: []clientgotesting.PatchActionImpl{ @@ -336,25 +345,23 @@ func TestAllCases(t *testing.T) { SkipNamespaceValidation: true, WantErr: false, WantEvents: []string{ + cmpEvent, saIngressEvent, rbIngressEvent, - rbIngressConfigEvent, secretEventIngress, rbFilterEvent, - rbFilterConfigEvent, secretEventFilter, brokerEvent, nsEvent, }, WantCreates: []runtime.Object{ + configMapPropagation, broker, secret, saIngress, rbIngress, - rbIngressConfig, secret, rbFilter, - rbFilterConfig, secret, }, WantPatches: []clientgotesting.PatchActionImpl{ @@ -368,15 +375,14 @@ func TestAllCases(t *testing.T) { WithNamespaceLabeled(resources.InjectionEnabledLabels()), ), rbFilter, - rbFilterConfig, }, Key: testNS, SkipNamespaceValidation: true, WantErr: false, WantEvents: []string{ + cmpEvent, saIngressEvent, rbIngressEvent, - rbIngressConfigEvent, secretEventIngress, saFilterEvent, secretEventFilter, @@ -384,11 +390,11 @@ func TestAllCases(t *testing.T) { nsEvent, }, WantCreates: []runtime.Object{ + configMapPropagation, broker, secret, saIngress, rbIngress, - rbIngressConfig, secret, saFilter, secret, @@ -407,13 +413,14 @@ func TestAllCases(t *testing.T) { table.Test(t, MakeFactory(func(ctx context.Context, listers *Listers, cmw configmap.Watcher) controller.Reconciler { r := &Reconciler{ - Base: reconciler.NewBase(ctx, controllerAgentName, cmw), - namespaceLister: listers.GetNamespaceLister(), - brokerLister: listers.GetBrokerLister(), - serviceAccountLister: listers.GetServiceAccountLister(), - roleBindingLister: listers.GetRoleBindingLister(), - tracker: tracker.New(func(types.NamespacedName) {}, 0), - brokerPullSecretName: brokerImagePullSecretName, + Base: reconciler.NewBase(ctx, controllerAgentName, cmw), + namespaceLister: listers.GetNamespaceLister(), + brokerLister: listers.GetBrokerLister(), + serviceAccountLister: listers.GetServiceAccountLister(), + roleBindingLister: listers.GetRoleBindingLister(), + configMapPropagationLister: listers.GetConfigMapPropagationLister(), + brokerPullSecretName: brokerImagePullSecretName, + tracker: tracker.New(func(types.NamespacedName) {}, 0), } // only create secret in required tests diff --git a/pkg/reconciler/namespace/resources/configmappropagation.go b/pkg/reconciler/namespace/resources/configmappropagation.go new file mode 100644 index 00000000000..a8bb0031c94 --- /dev/null +++ b/pkg/reconciler/namespace/resources/configmappropagation.go @@ -0,0 +1,37 @@ +/* +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 resources + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "knative.dev/eventing/pkg/apis/configs/v1alpha1" + "knative.dev/pkg/system" +) + +// MakeConfigMapPropagation creates a default ConfigMapPropagation object for Namespace 'namespace'. +func MakeConfigMapPropagation(namespace string) *v1alpha1.ConfigMapPropagation { + return &v1alpha1.ConfigMapPropagation{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: namespace, + Name: DefaultConfigMapPropagationName, + }, + Spec: v1alpha1.ConfigMapPropagationSpec{ + OriginalNamespace: system.Namespace(), + Selector: &metav1.LabelSelector{MatchLabels: ConfigMapPropagationOwnedLabels()}, + }, + } +} diff --git a/pkg/reconciler/namespace/resources/labels.go b/pkg/reconciler/namespace/resources/labels.go index 0bfeade1497..4512b5e2b04 100644 --- a/pkg/reconciler/namespace/resources/labels.go +++ b/pkg/reconciler/namespace/resources/labels.go @@ -22,6 +22,8 @@ const ( InjectionEnabledLabelValue = "enabled" InjectionDisabledLabelValue = "disabled" InjectedResourceLabel = "eventing.knative.dev/namespaceInjected" + CmpDefaultLabelKey = "knative.dev/config-category" + CmpDefaultLabelValue = "eventing" ) // OwnedLabels generates the labels present on injected broker resources. @@ -31,6 +33,13 @@ func OwnedLabels() map[string]string { } } +// ConfigMapPropagationOwnedLabels generates the labels present on injected broker resources. +func ConfigMapPropagationOwnedLabels() map[string]string { + return map[string]string{ + CmpDefaultLabelKey: CmpDefaultLabelValue, + } +} + func InjectionEnabledLabels() map[string]string { return map[string]string{ InjectionLabelKey: InjectionEnabledLabelValue, diff --git a/pkg/reconciler/namespace/resources/names.go b/pkg/reconciler/namespace/resources/names.go index 47e3b71a25d..5f7e36a04ec 100644 --- a/pkg/reconciler/namespace/resources/names.go +++ b/pkg/reconciler/namespace/resources/names.go @@ -16,10 +16,6 @@ limitations under the License. package resources -import ( - "knative.dev/pkg/kmeta" -) - const ( DefaultBrokerName = "default" @@ -31,13 +27,5 @@ const ( IngressRoleBindingName = "eventing-broker-ingress" IngressClusterRoleName = "eventing-broker-ingress" - ConfigClusterRoleName = "eventing-config-reader" + DefaultConfigMapPropagationName = "eventing" ) - -// ConfigRoleBindingName returns a name for a RoleBinding allowing access to the -// shared ConfigMaps from a service account in another namespace. Because these -// are all created in the system namespace, they must be named for their -// subject namespace. -func ConfigRoleBindingName(saName, ns string) string { - return kmeta.ChildName(saName, "-"+ns) -} diff --git a/pkg/reconciler/testing/configmap.go b/pkg/reconciler/testing/configmap.go new file mode 100644 index 00000000000..8f412628a83 --- /dev/null +++ b/pkg/reconciler/testing/configmap.go @@ -0,0 +1,62 @@ +/* +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 testing + +import ( + "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + "knative.dev/eventing/pkg/apis/configs/v1alpha1" + "knative.dev/pkg/kmeta" +) + +// ConfigMapOption enables further configuration of a ConfigMap. +type ConfigMapOption func(*v1.ConfigMap) + +// NewConfigMap creates a new ConfigMap. +func NewConfigMap(name, namespace string, o ...ConfigMapOption) *v1.ConfigMap { + cm := &v1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: namespace, + Name: name, + }, + } + for _, opt := range o { + opt(cm) + } + return cm +} + +func WithConfigMapLabels(labels metav1.LabelSelector) ConfigMapOption { + return func(cm *v1.ConfigMap) { + cm.ObjectMeta.Labels = labels.MatchLabels + } +} + +func WithConfigMapOwnerReference(ConfigMapPropagation *v1alpha1.ConfigMapPropagation) ConfigMapOption { + return func(cm *v1.ConfigMap) { + cm.ObjectMeta.OwnerReferences = []metav1.OwnerReference{ + *kmeta.NewControllerRef(ConfigMapPropagation), + } + } +} + +func WithConfigMapData(data map[string]string) ConfigMapOption { + return func(cm *v1.ConfigMap) { + cm.Data = data + } +} diff --git a/pkg/reconciler/testing/configmappropagation.go b/pkg/reconciler/testing/configmappropagation.go new file mode 100644 index 00000000000..fa72f41cec5 --- /dev/null +++ b/pkg/reconciler/testing/configmappropagation.go @@ -0,0 +1,100 @@ +/* +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 testing + +import ( + "context" + "time" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "knative.dev/eventing/pkg/apis/configs/v1alpha1" +) + +// ConfigMapPropagationOption enables further configuration of a ConfigMapPropagation. +type ConfigMapPropagationOption func(*v1alpha1.ConfigMapPropagation) + +// NewConfigMapPropagation creates a ConfigMapPropagation. +func NewConfigMapPropagation(name, namespace string, o ...ConfigMapPropagationOption) *v1alpha1.ConfigMapPropagation { + cmp := &v1alpha1.ConfigMapPropagation{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: namespace, + Name: name, + }, + } + for _, opt := range o { + opt(cmp) + } + cmp.SetDefaults(context.Background()) + cmp.Spec.OriginalNamespace = "knative-eventing" + return cmp +} + +// WithInitConfigMapPropagationConditions initializes the ConfigMapPropagation's conditions. +func WithInitConfigMapPropagationConditions(cmp *v1alpha1.ConfigMapPropagation) { + cmp.Status.InitializeConditions() +} + +func WithInitConfigMapStatus() ConfigMapPropagationOption { + return func(cmp *v1alpha1.ConfigMapPropagation) { + cmp.Status.CopyConfigMaps = []v1alpha1.ConfigMapPropagationStatusCopyConfigMap{} + } +} + +func WithCopyConfigMapStatus(name, source, operation, ready, reason string) ConfigMapPropagationOption { + return func(cmp *v1alpha1.ConfigMapPropagation) { + cmp.Status.CopyConfigMaps = append(cmp.Status.CopyConfigMaps, v1alpha1.ConfigMapPropagationStatusCopyConfigMap{ + Name: name, + Source: source, + Operation: operation, + Ready: ready, + Reason: reason, + }) + } +} + +func WithConfigMapPropagationDeletionTimestamp(cmp *v1alpha1.ConfigMapPropagation) { + t := metav1.NewTime(time.Unix(1e9, 0)) + cmp.ObjectMeta.SetDeletionTimestamp(&t) +} + +func WithConfigMapPropagationSelector(selector metav1.LabelSelector) ConfigMapPropagationOption { + return func(cmp *v1alpha1.ConfigMapPropagation) { + cmp.Spec.Selector = &selector + } +} + +func WithConfigMapPropagationGeneration(gen int64) ConfigMapPropagationOption { + return func(cmp *v1alpha1.ConfigMapPropagation) { + cmp.Generation = gen + } +} + +func WithConfigMapPropagationStatusObservedGeneration(gen int64) ConfigMapPropagationOption { + return func(cmp *v1alpha1.ConfigMapPropagation) { + cmp.Status.ObservedGeneration = gen + } +} + +// WithConfigMapPropagationPropagated calls .Status.MarkConfigMapPropagationPropagated on the ConfigMapPropagation. +func WithConfigMapPropagationPropagated(cmp *v1alpha1.ConfigMapPropagation) { + cmp.Status.MarkPropagated() +} + +// WithConfigMapPropagationNotPropagated calls .Status.MarkConfigMapPropagationNotPropagated on the ConfigMapPropagation. +func WithConfigMapPropagationNotPropagated(cmp *v1alpha1.ConfigMapPropagation) { + cmp.Status.MarkNotPropagated() +} diff --git a/pkg/reconciler/testing/listers.go b/pkg/reconciler/testing/listers.go index 12c04bd4b3d..ed2e2a6a974 100644 --- a/pkg/reconciler/testing/listers.go +++ b/pkg/reconciler/testing/listers.go @@ -31,12 +31,14 @@ import ( corev1listers "k8s.io/client-go/listers/core/v1" rbacv1listers "k8s.io/client-go/listers/rbac/v1" "k8s.io/client-go/tools/cache" + configsv1alpha1 "knative.dev/eventing/pkg/apis/configs/v1alpha1" eventingv1alpha1 "knative.dev/eventing/pkg/apis/eventing/v1alpha1" flowsv1alpha1 "knative.dev/eventing/pkg/apis/flows/v1alpha1" legacysourcesv1alpha1 "knative.dev/eventing/pkg/apis/legacysources/v1alpha1" messagingv1alpha1 "knative.dev/eventing/pkg/apis/messaging/v1alpha1" sourcesv1alpha1 "knative.dev/eventing/pkg/apis/sources/v1alpha1" fakeeventingclientset "knative.dev/eventing/pkg/client/clientset/versioned/fake" + configslisters "knative.dev/eventing/pkg/client/listers/configs/v1alpha1" eventinglisters "knative.dev/eventing/pkg/client/listers/eventing/v1alpha1" flowslisters "knative.dev/eventing/pkg/client/listers/flows/v1alpha1" messaginglisters "knative.dev/eventing/pkg/client/listers/messaging/v1alpha1" @@ -203,3 +205,7 @@ func (l *Listers) GetConfigMapLister() corev1listers.ConfigMapLister { func (l *Listers) GetCustomResourceDefinitionLister() apiextensionsv1beta1listers.CustomResourceDefinitionLister { return apiextensionsv1beta1listers.NewCustomResourceDefinitionLister(l.indexerFor(&apiextensionsv1beta1.CustomResourceDefinition{})) } + +func (l *Listers) GetConfigMapPropagationLister() configslisters.ConfigMapPropagationLister { + return configslisters.NewConfigMapPropagationLister(l.indexerFor(&configsv1alpha1.ConfigMapPropagation{})) +} diff --git a/pkg/tracing/setup.go b/pkg/tracing/setup.go index 7b806e9d02f..c6a8cd0eb21 100644 --- a/pkg/tracing/setup.go +++ b/pkg/tracing/setup.go @@ -81,14 +81,14 @@ func SetupStaticPublishing(logger *zap.SugaredLogger, serviceName string, cfg *t // just ensures that if generated, they are collected appropriately. This is normally done by using // tracing.HTTPSpanMiddleware as a middleware HTTP handler. The configuration will be dynamically // updated when the ConfigMap is updated. -func SetupDynamicPublishing(logger *zap.SugaredLogger, configMapWatcher *configmap.InformedWatcher, serviceName string) error { +func SetupDynamicPublishing(logger *zap.SugaredLogger, configMapWatcher *configmap.InformedWatcher, serviceName, tracingConfigName string) error { oct, err := setupPublishing(serviceName, logger) if err != nil { return err } tracerUpdater := func(name string, value interface{}) { - if name == tracingconfig.ConfigName { + if name == tracingConfigName { cfg := value.(*tracingconfig.Config) logger.Debugw("Updating tracing config", zap.Any("cfg", cfg)) err = oct.ApplyConfig(cfg) @@ -105,7 +105,7 @@ func SetupDynamicPublishing(logger *zap.SugaredLogger, configMapWatcher *configm logger, []eventingconfigmap.DefaultConstructor{ { - Default: enableZeroSamplingCM(configMapWatcher.Namespace), + Default: enableZeroSamplingCM(configMapWatcher.Namespace, tracingConfigName), Constructor: tracingconfig.NewTracingConfigFromConfigMap, }, }, @@ -114,10 +114,10 @@ func SetupDynamicPublishing(logger *zap.SugaredLogger, configMapWatcher *configm return nil } -func enableZeroSamplingCM(ns string) corev1.ConfigMap { +func enableZeroSamplingCM(ns string, tracingConfigName string) corev1.ConfigMap { return corev1.ConfigMap{ ObjectMeta: metav1.ObjectMeta{ - Name: tracingconfig.ConfigName, + Name: tracingConfigName, Namespace: ns, }, Data: map[string]string{ diff --git a/test/conformance/helpers/broker_tracing_test_helper.go b/test/conformance/helpers/broker_tracing_test_helper.go index a75ea883675..2ab1d04962a 100644 --- a/test/conformance/helpers/broker_tracing_test_helper.go +++ b/test/conformance/helpers/broker_tracing_test_helper.go @@ -79,10 +79,12 @@ func setupBrokerTracing( tc TracingTestCase, ) (tracinghelper.TestSpanTree, string) { const ( - etTransformer = "transformer" - etLogger = "logger" + etTransformer = "transformer" + etLogger = "logger" + defaultCMPName = "eventing" ) // Create the Broker. + client.CreateConfigMapPropagationOrFail(defaultCMPName) client.CreateRBACResourcesForBrokers() broker := client.CreateBrokerOrFail("br", resources.WithChannelTemplateForBroker(channel)) diff --git a/test/lib/creation.go b/test/lib/creation.go index ce6221a50e8..4a6616f76e7 100644 --- a/test/lib/creation.go +++ b/test/lib/creation.go @@ -26,6 +26,7 @@ import ( "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + configsv1alpha1 "knative.dev/eventing/pkg/apis/configs/v1alpha1" "knative.dev/eventing/pkg/apis/eventing/v1alpha1" flowsv1alpha1 "knative.dev/eventing/pkg/apis/flows/v1alpha1" legacysourcesv1alpha1 "knative.dev/eventing/pkg/apis/legacysources/v1alpha1" @@ -34,8 +35,6 @@ import ( "knative.dev/eventing/pkg/utils" "knative.dev/eventing/test/lib/duck" "knative.dev/eventing/test/lib/resources" - - "knative.dev/pkg/test/helpers" ) // TODO(chizhg): break this file into multiple files when it grows too large. @@ -103,6 +102,18 @@ func (client *Client) CreateSubscriptionsOrFail( } } +func (client *Client) CreateConfigMapPropagationOrFail(name string) *configsv1alpha1.ConfigMapPropagation { + namespace := client.Namespace + configMapPropagation := resources.ConfigMapPropagation(name, namespace) + configMapPropagations := client.Eventing.ConfigsV1alpha1().ConfigMapPropagations(namespace) + configMapPropagation, err := configMapPropagations.Create(configMapPropagation) + if err != nil { + client.T.Fatalf("Failed to create configMapPropagation %q: %v", name, err) + } + client.Tracker.AddObj(configMapPropagation) + return configMapPropagation +} + // CreateBrokerOrFail will create a Broker or fail the test if there is an error. func (client *Client) CreateBrokerOrFail(name string, options ...resources.BrokerOption) *v1alpha1.Broker { namespace := client.Namespace @@ -408,20 +419,4 @@ func (client *Client) CreateRBACResourcesForBrokers() { fmt.Sprintf("%s-%s", saFilterName, crFilterName), client.Namespace, ) - // The two RoleBindings are required for access to shared configmaps for logging, - // tracing, and metrics configuration. - client.CreateRoleBindingOrFail( - saIngressName, - ClusterRoleKind, - crConfigReaderName, - fmt.Sprintf("%s-%s-%s", saIngressName, helpers.MakeK8sNamePrefix(client.Namespace), crConfigReaderName), - resources.SystemNamespace, - ) - client.CreateRoleBindingOrFail( - saFilterName, - ClusterRoleKind, - crConfigReaderName, - fmt.Sprintf("%s-%s-%s", saFilterName, helpers.MakeK8sNamePrefix(client.Namespace), crConfigReaderName), - resources.SystemNamespace, - ) } diff --git a/test/lib/resources/eventing.go b/test/lib/resources/eventing.go index a64315ecef1..498c9654f63 100644 --- a/test/lib/resources/eventing.go +++ b/test/lib/resources/eventing.go @@ -28,9 +28,11 @@ import ( duckv1 "knative.dev/pkg/apis/duck/v1" pkgTest "knative.dev/pkg/test" + configsv1alpha1 "knative.dev/eventing/pkg/apis/configs/v1alpha1" eventingduckv1alpha1 "knative.dev/eventing/pkg/apis/duck/v1alpha1" eventingv1alpha1 "knative.dev/eventing/pkg/apis/eventing/v1alpha1" messagingv1alpha1 "knative.dev/eventing/pkg/apis/messaging/v1alpha1" + "knative.dev/eventing/pkg/reconciler/namespace/resources" ) // BrokerOption enables further configuration of a Broker. @@ -127,6 +129,22 @@ func WithDeliveryForBroker(delivery *eventingduckv1alpha1.DeliverySpec) BrokerOp } } +// ConfigMapPropagation returns a ConfigMapPropagation +func ConfigMapPropagation(name, namespace string) *configsv1alpha1.ConfigMapPropagation { + return &configsv1alpha1.ConfigMapPropagation{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: namespace, + Name: name, + }, + Spec: configsv1alpha1.ConfigMapPropagationSpec{ + OriginalNamespace: "knative-eventing", + Selector: &metav1.LabelSelector{ + MatchLabels: resources.ConfigMapPropagationOwnedLabels(), + }, + }, + } +} + // Broker returns a Broker. func Broker(name string, options ...BrokerOption) *eventingv1alpha1.Broker { broker := &eventingv1alpha1.Broker{ diff --git a/test/performance/benchmarks/broker-imc/100-broker-perf-setup.yaml b/test/performance/benchmarks/broker-imc/100-broker-perf-setup.yaml index 7fb68b70f90..568c70e3178 100644 --- a/test/performance/benchmarks/broker-imc/100-broker-perf-setup.yaml +++ b/test/performance/benchmarks/broker-imc/100-broker-perf-setup.yaml @@ -128,35 +128,16 @@ roleRef: --- -apiVersion: rbac.authorization.k8s.io/v1 -kind: RoleBinding +apiVersion: configs.knative.dev/v1alpha1 +kind: ConfigMapPropagation metadata: - name: eventing-config-reader-default-eventing-broker-ingress - namespace: knative-eventing -subjects: - - kind: ServiceAccount - name: eventing-broker-ingress - namespace: perf-eventing -roleRef: - kind: ClusterRole - name: eventing-config-reader - apiGroup: rbac.authorization.k8s.io - ---- - -apiVersion: rbac.authorization.k8s.io/v1 -kind: RoleBinding -metadata: - name: eventing-config-reader-default-eventing-broker-filter - namespace: knative-eventing -subjects: - - kind: ServiceAccount - name: eventing-broker-filter - namespace: perf-eventing -roleRef: - kind: ClusterRole - name: eventing-config-reader - apiGroup: rbac.authorization.k8s.io + name: eventing + namespace: perf-eventing +spec: + originalNamespace: knative-eventing + selector: + matchlabels: + knative.dev/config-category: eventing --- diff --git a/test/performance/benchmarks/broker-imc/continuous/100-broker-imc-setup.yaml b/test/performance/benchmarks/broker-imc/continuous/100-broker-imc-setup.yaml index 7ed5fe24e3b..f7cb1cc1cee 100644 --- a/test/performance/benchmarks/broker-imc/continuous/100-broker-imc-setup.yaml +++ b/test/performance/benchmarks/broker-imc/continuous/100-broker-imc-setup.yaml @@ -121,35 +121,16 @@ roleRef: --- -apiVersion: rbac.authorization.k8s.io/v1 -kind: RoleBinding +apiVersion: configs.knative.dev/v1alpha1 +kind: ConfigMapPropagation metadata: - name: eventing-config-reader-default-eventing-broker-ingress - namespace: knative-eventing -subjects: - - kind: ServiceAccount - name: eventing-broker-ingress - namespace: default -roleRef: - kind: ClusterRole - name: eventing-config-reader - apiGroup: rbac.authorization.k8s.io - ---- - -apiVersion: rbac.authorization.k8s.io/v1 -kind: RoleBinding -metadata: - name: eventing-config-reader-default-eventing-broker-filter - namespace: knative-eventing -subjects: - - kind: ServiceAccount - name: eventing-broker-filter - namespace: default -roleRef: - kind: ClusterRole - name: eventing-config-reader - apiGroup: rbac.authorization.k8s.io + name: eventing + namespace: default +spec: + originalNamespace: knative-eventing + selector: + matchlabels: + knative.dev/config-category: eventing ---