From 4847575319f27c00c5d7cc84fd29dfa8ac0da6a4 Mon Sep 17 00:00:00 2001 From: Claudio Miranda Date: Fri, 10 Mar 2023 15:03:49 -0300 Subject: [PATCH] fix(knative): Integration in error state when knative SinkBinding mode=inclusion #4119 https://github.com/apache/camel-k/issues/4119 --- config/rbac/operator-role-knative.yaml | 7 ++++ .../Rest2Channel.java | 26 ++++++++++++++ .../messages-channel.yaml | 21 +++++++++++ .../sinkbinding.feature | 9 +++++ .../knative-sinkbinding-http/yaks-config.yaml | 35 +++++++++++++++++++ pkg/apis/camel/v1/trait/knative.go | 4 +++ pkg/resources/resources.go | 4 +-- pkg/trait/knative.go | 10 ++++++ pkg/util/knative/knative.go | 34 ++++++++++++++++++ 9 files changed, 148 insertions(+), 2 deletions(-) create mode 100644 e2e/yaks/common/knative-sinkbinding-http/Rest2Channel.java create mode 100644 e2e/yaks/common/knative-sinkbinding-http/messages-channel.yaml create mode 100644 e2e/yaks/common/knative-sinkbinding-http/sinkbinding.feature create mode 100644 e2e/yaks/common/knative-sinkbinding-http/yaks-config.yaml diff --git a/config/rbac/operator-role-knative.yaml b/config/rbac/operator-role-knative.yaml index 8ef0f42b6f..3cba80931b 100644 --- a/config/rbac/operator-role-knative.yaml +++ b/config/rbac/operator-role-knative.yaml @@ -71,3 +71,10 @@ rules: - list - patch - update +- apiGroups: + - "" + resources: + - namespaces + verbs: + - get + - patch diff --git a/e2e/yaks/common/knative-sinkbinding-http/Rest2Channel.java b/e2e/yaks/common/knative-sinkbinding-http/Rest2Channel.java new file mode 100644 index 0000000000..5eb905e572 --- /dev/null +++ b/e2e/yaks/common/knative-sinkbinding-http/Rest2Channel.java @@ -0,0 +1,26 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import org.apache.camel.builder.RouteBuilder; + +public class Rest2Channel extends RouteBuilder { + public void configure() throws Exception { + rest("/") + .put("/foo/new") + .to("knative:channel/messages"); + } +} \ No newline at end of file diff --git a/e2e/yaks/common/knative-sinkbinding-http/messages-channel.yaml b/e2e/yaks/common/knative-sinkbinding-http/messages-channel.yaml new file mode 100644 index 0000000000..c67517d929 --- /dev/null +++ b/e2e/yaks/common/knative-sinkbinding-http/messages-channel.yaml @@ -0,0 +1,21 @@ +# --------------------------------------------------------------------------- +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT 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: messaging.knative.dev/v1 +kind: InMemoryChannel +metadata: + name: messages diff --git a/e2e/yaks/common/knative-sinkbinding-http/sinkbinding.feature b/e2e/yaks/common/knative-sinkbinding-http/sinkbinding.feature new file mode 100644 index 0000000000..e5503b57b5 --- /dev/null +++ b/e2e/yaks/common/knative-sinkbinding-http/sinkbinding.feature @@ -0,0 +1,9 @@ +Feature: Camel K can run source HTTP endpoint in sinkbinding mode + + Background: + Given Kubernetes resource polling configuration + | maxAttempts | 1 | + | delayBetweenAttempts | 500 | + + Scenario: Integration knative-service starts with no errors + Given wait for condition=Ready on Kubernetes custom resource integration/rest2channel in integration.camel.apache.org/v1 diff --git a/e2e/yaks/common/knative-sinkbinding-http/yaks-config.yaml b/e2e/yaks/common/knative-sinkbinding-http/yaks-config.yaml new file mode 100644 index 0000000000..e50bd2be4b --- /dev/null +++ b/e2e/yaks/common/knative-sinkbinding-http/yaks-config.yaml @@ -0,0 +1,35 @@ +# --------------------------------------------------------------------------- +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# --------------------------------------------------------------------------- + +config: + namespace: + temporary: true +pre: +- name: installation + run: | + kubectl -n knative-eventing set env deployments eventing-webhook --containers="eventing-webhook" SINK_BINDING_SELECTION_MODE=inclusion + sleep 5s + + kubectl apply -n $YAKS_NAMESPACE -f messages-channel.yaml + + kamel run Rest2Channel.java -w -n $YAKS_NAMESPACE + + kubectl wait integration --all --for=condition=Ready --timeout=10m -n $YAKS_NAMESPACE +post: + - name: print dump + if: env:CI=true && failure() + run: yaks dump --includes app=camel-k diff --git a/pkg/apis/camel/v1/trait/knative.go b/pkg/apis/camel/v1/trait/knative.go index 666953b088..4495c6a487 100644 --- a/pkg/apis/camel/v1/trait/knative.go +++ b/pkg/apis/camel/v1/trait/knative.go @@ -57,4 +57,8 @@ type KnativeTrait struct { SinkBinding *bool `property:"sink-binding" json:"sinkBinding,omitempty"` // Enable automatic discovery of all trait properties. Auto *bool `property:"auto" json:"auto,omitempty"` + // Enables the camel-k-operator to set the "bindings.knative.dev/include=true" label to the namespace + // As Knative requires this label to perform injection of K_SINK URL into the service. + // If this is false, the integration pod may start and fail, read the SinkBinding Knative documentation. (default: true) + NamespaceLabel *bool `property:"namespace-label" json:"namespaceLabel,omitempty"` } diff --git a/pkg/resources/resources.go b/pkg/resources/resources.go index 98e8285a5a..6e51234f3e 100644 --- a/pkg/resources/resources.go +++ b/pkg/resources/resources.go @@ -392,9 +392,9 @@ var assets = func() http.FileSystem { "/rbac/operator-role-knative.yaml": &vfsgen۰CompressedFileInfo{ name: "operator-role-knative.yaml", modTime: time.Time{}, - uncompressedSize: 1677, + uncompressedSize: 1752, - compressedContent: []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xb4\x94\x41\x8f\xdb\x46\x0c\x85\xef\xf3\x2b\x1e\xac\x4b\x02\xac\xb5\x6d\x4f\x85\x7b\x72\x37\xbb\xad\xd1\xc0\x06\x56\x4e\x83\x1c\x29\x89\x96\x08\x4b\x33\x53\xce\xc8\x8a\xfb\xeb\x0b\x8d\xe5\xc6\xc1\x1e\xf6\xb2\xd1\xc5\x1c\xf9\x0d\xf9\x91\x8f\x76\x86\xe5\xdb\x3d\x26\xc3\x47\xa9\xd8\x06\xae\x11\x1d\x62\xcb\x58\x7b\xaa\x5a\x46\xe1\x0e\x71\x24\x65\x3c\xb9\xc1\xd6\x14\xc5\x59\xbc\x5b\x17\x4f\xef\x31\xd8\x9a\x15\xce\x32\x9c\xa2\x77\xca\x26\x43\xe5\x6c\x54\x29\x87\xe8\x14\xdd\x25\x21\xa8\x51\xe6\x9e\x6d\x0c\x39\x50\x30\xa7\xec\xdb\xdd\x7e\xf3\xf0\x88\x83\x74\x8c\x5a\xc2\xe5\x12\xd7\x18\x25\xb6\x26\x43\x6c\x25\x60\x74\x7a\xc4\xc1\x29\xa8\xae\x65\x2a\x4c\x1d\xc4\x1e\x9c\xf6\x17\x0c\xe5\x86\xb4\x16\xdb\xa0\x72\xfe\xac\xd2\xb4\x11\x6e\xb4\xac\xa1\x15\x9f\x9b\x0c\xfb\xa9\x8d\xe2\xe9\x4a\x12\x2e\x69\x53\xcd\xe8\xf0\xc5\x0d\x73\x0f\x37\xed\xce\x53\xb8\xc3\xdf\xac\x61\x2a\xf2\x4b\xfe\x93\xc9\xf0\x6e\x92\x2c\xe6\x2f\x17\xef\x7f\xc3\xd9\x0d\xe8\xe9\x0c\xeb\x22\x86\xc0\x37\x99\xf9\x6b\xc5\x3e\x42\x2c\x2a\xd7\xfb\x4e\xc8\x56\xfc\xad\xad\xff\x2b\xe4\x48\x00\x53\x0e\x57\x46\x12\x0b\x4a\x6d\xc0\x1d\x6e\x65\xa0\x68\x32\x93\x21\x3d\x6d\x8c\x7e\x75\x7f\x3f\x8e\x63\x4e\x09\x37\x77\xda\xdc\x5f\xbb\xbb\xff\xb8\x79\x78\xdc\x16\x8f\xcb\x84\x6c\x32\x7c\xb2\x1d\x87\x00\xe5\x7f\x06\x51\xae\x51\x9e\x41\xde\x77\x52\x51\xd9\x31\x3a\x1a\x27\xe3\x92\x3b\xc9\x74\xb1\x18\x55\xa2\xd8\xe6\x0e\x61\x76\xdd\x64\xdf\xb9\xf3\x6d\x5c\x57\x3c\x09\xdf\x09\x9c\x05\x59\x2c\xd6\x05\x36\xc5\x02\xbf\xaf\x8b\x4d\x71\x67\x32\x7c\xde\xec\xff\xdc\x7d\xda\xe3\xf3\xfa\xf9\x79\xbd\xdd\x6f\x1e\x0b\xec\x9e\xf1\xb0\xdb\x7e\xd8\xec\x37\xbb\x6d\x81\xdd\x13\xd6\xdb\x2f\xf8\x6b\xb3\xfd\x70\x07\x96\xd8\xb2\x82\xbf\x7a\x9d\xf8\x9d\x42\xa6\x41\x72\x3d\x79\x7a\x5d\xa0\x2b\xc0\xb4\x1f\xd3\x39\x78\xae\xe4\x20\x15\x3a\xb2\xcd\x40\x0d\xa3\x71\x27\x56\x3b\xad\x87\x67\xed\x25\x4c\x76\x06\x90\xad\x4d\x86\x4e\x7a\x89\x69\x8b\xc2\xcb\xa6\xa6\x32\x6f\xf9\xdb\x32\x47\xb1\xf5\x0a\xcf\xae\x63\x43\x5e\xe6\xcd\x5a\x41\x4b\xaa\x72\x1a\x62\xeb\x54\xfe\x4d\x30\xf9\xf1\xd7\x90\x8b\xbb\x3f\xfd\x6c\x7a\x8e\x54\x53\xa4\x95\x01\x2c\xf5\xbc\x42\x45\x3d\x77\xcb\xe3\xd2\x79\x56\x8a\x4e\x97\x47\x4b\x51\x4e\x6c\x80\x8e\x4a\xee\xc2\x24\xc5\x64\xf1\x0a\x8b\x59\xbc\x30\x3a\x74\x1c\x56\x66\x09\xf2\xf2\x87\xba\xc1\x27\xd9\x12\x81\xf5\x24\xb6\xc9\xe7\x24\x79\xcd\x27\x03\x28\x07\x37\x68\xc5\xb7\xa2\x8a\x43\x3a\xa8\x1b\x62\x0a\x4f\xac\xe5\x2c\xa8\x94\x29\x72\x0a\x6b\xee\x78\x0e\x1b\x8e\xe9\xb3\x93\x70\x09\x3c\xc5\xaa\x4d\xd1\xe0\xeb\xeb\x85\x31\xbd\x7c\x01\xc6\x27\xb6\xf1\x55\xb2\xa8\xd2\x34\xac\x17\xb2\x52\xdd\xf1\x12\xbf\x01\xda\x0b\xa0\x9e\x43\xa0\xe6\xf5\x59\x0d\x65\xa8\x54\x7c\x5a\xaa\x0b\x41\x4b\xd6\x72\x77\x39\x88\xed\xb9\x77\x7a\xbe\x79\xf9\x23\x60\x67\xa4\x57\x50\xc5\x1e\x4b\xb1\xd3\x5f\xe7\x1b\x71\xfc\x17\x00\x00\xff\xff\xd6\x8b\x9b\xa6\x8d\x06\x00\x00"), + compressedContent: []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xb4\x94\x41\x8f\xdb\x46\x0c\x85\xef\xfa\x15\x0f\xd6\x25\x01\xd6\x72\xdb\x53\xe1\x9e\xdc\xcd\x6e\x6b\x34\xb0\x81\x95\xd3\x20\x47\x4a\xa2\x25\xc2\xd2\xcc\x94\x33\xb2\xe2\xfe\xfa\x42\x23\xb9\x71\xb2\x87\xbd\xec\xea\x62\x8e\xcc\x21\x3f\xf2\x3d\x3b\xc5\xf2\xf5\x9e\x24\xc5\x47\x29\xd9\x78\xae\x10\x2c\x42\xc3\xd8\x38\x2a\x1b\x46\x6e\x8f\x61\x20\x65\x3c\xda\xde\x54\x14\xc4\x1a\xbc\xdb\xe4\x8f\xef\xd1\x9b\x8a\x15\xd6\x30\xac\xa2\xb3\xca\x49\x8a\xd2\x9a\xa0\x52\xf4\xc1\x2a\xda\xa9\x20\xa8\x56\xe6\x8e\x4d\xf0\x19\x90\x33\xc7\xea\xbb\xfd\x61\x7b\xff\x80\xa3\xb4\x8c\x4a\xfc\x74\x89\x2b\x0c\x12\x9a\x24\x45\x68\xc4\x63\xb0\x7a\xc2\xd1\x2a\xa8\xaa\x64\x6c\x4c\x2d\xc4\x1c\xad\x76\x13\x86\x72\x4d\x5a\x89\xa9\x51\x5a\x77\x51\xa9\x9b\x00\x3b\x18\x56\xdf\x88\xcb\x92\x14\x87\x71\x8c\xfc\xf1\x4a\xe2\xa7\xb2\xb1\x67\xb0\xf8\x62\xfb\x79\x86\x9b\x71\xe7\x2d\xdc\xe1\x6f\x56\x3f\x36\xf9\x25\xfb\x29\x49\xf1\x6e\x4c\x59\xcc\x5f\x2e\xde\xff\x86\x8b\xed\xd1\xd1\x05\xc6\x06\xf4\x9e\x6f\x2a\xf3\xd7\x92\x5d\x80\x18\x94\xb6\x73\xad\x90\x29\xf9\xdb\x58\xff\x77\xc8\x10\x01\xc6\x1a\xb6\x08\x24\x06\x14\xc7\x80\x3d\xde\xa6\x81\x42\x92\x26\x29\xe2\xd3\x84\xe0\xd6\xab\xd5\x30\x0c\x19\x45\xdc\xcc\x6a\xbd\xba\x4e\xb7\xfa\xb8\xbd\x7f\xd8\xe5\x0f\xcb\x88\x9c\xa4\xf8\x64\x5a\xf6\x1e\xca\xff\xf4\xa2\x5c\xa1\xb8\x80\x9c\x6b\xa5\xa4\xa2\x65\xb4\x34\x8c\xc2\x45\x75\xa2\xe8\x62\x30\xa8\x04\x31\xf5\x1d\xfc\xac\x7a\x92\x7e\xa7\xce\xb7\x75\x5d\xf1\xc4\x7f\x97\x60\x0d\xc8\x60\xb1\xc9\xb1\xcd\x17\xf8\x7d\x93\x6f\xf3\xbb\x24\xc5\xe7\xed\xe1\xcf\xfd\xa7\x03\x3e\x6f\x9e\x9e\x36\xbb\xc3\xf6\x21\xc7\xfe\x09\xf7\xfb\xdd\x87\xed\x61\xbb\xdf\xe5\xd8\x3f\x62\xb3\xfb\x82\xbf\xb6\xbb\x0f\x77\x60\x09\x0d\x2b\xf8\xab\xd3\x91\xdf\x2a\x64\x5c\x24\x57\xa3\xa6\x57\x03\x5d\x01\x46\x7f\x8c\x67\xef\xb8\x94\xa3\x94\x68\xc9\xd4\x3d\xd5\x8c\xda\x9e\x59\xcd\x68\x0f\xc7\xda\x89\x1f\xe5\xf4\x20\x53\x25\x29\x5a\xe9\x24\x44\x17\xf9\xe7\x43\x8d\x6d\x5e\xf3\xb7\x95\x9c\xc4\x54\x6b\x3c\xd9\x96\x13\x72\x32\x3b\x6b\x0d\x2d\xa8\xcc\xa8\x0f\x8d\x55\xf9\x37\xc2\x64\xa7\x5f\x7d\x26\x76\x75\xfe\x39\xe9\x38\x50\x45\x81\xd6\x09\x60\xa8\xe3\x35\x4a\xea\xb8\x5d\x9e\x96\xd6\xb1\x52\xb0\xba\x3c\x19\x0a\x72\xe6\x04\x68\xa9\xe0\xd6\x8f\xa9\x18\x25\x5e\x63\x31\x27\x2f\x12\xed\x5b\xf6\xeb\x64\x09\x72\xf2\x87\xda\xde\xc5\xb4\x25\x3c\xeb\x59\x4c\x9d\xcd\x45\xb2\x8a\xcf\x09\xa0\xec\x6d\xaf\x25\xdf\x26\x95\xec\xe3\x41\x6d\x1f\x62\x78\x66\x2d\xe6\x84\x52\x99\x02\xc7\xb0\xe2\x96\xe7\xb0\xe6\x10\x3f\x5b\xf1\x53\xe0\x28\x94\x4d\x8c\x7a\x57\x5d\x2f\x0c\xf1\xe5\x33\x30\x3e\xb3\x09\x2f\x92\x05\x95\xba\x66\x9d\xc8\x0a\xb5\xa7\x29\x7e\x05\xb4\x67\x40\x1d\x7b\x4f\xf5\xcb\xbb\xea\x0b\x5f\xaa\xb8\x68\xaa\x89\xa0\x21\x63\xb8\x9d\x0e\x62\x3a\xee\xac\x5e\x6e\x5e\xbe\x05\xec\x8c\xf4\x02\xaa\x98\x53\x21\x66\xfc\xeb\x7c\x2b\x8e\xc5\xe2\x79\xdb\xd1\xc6\xde\x51\xf9\xa3\x89\xae\xe5\xa7\xaa\xff\x05\x00\x00\xff\xff\xa2\x97\xa7\xd4\xd8\x06\x00\x00"), }, "/rbac/operator-role-leases.yaml": &vfsgen۰CompressedFileInfo{ name: "operator-role-leases.yaml", diff --git a/pkg/trait/knative.go b/pkg/trait/knative.go index 935e0d03fa..e53bb4cf79 100644 --- a/pkg/trait/knative.go +++ b/pkg/trait/knative.go @@ -469,6 +469,16 @@ func (t *knativeTrait) configureSinkBinding(e *Environment, env *knativeapi.Came APIVersion: ref.APIVersion, } + if pointer.BoolDeref(t.NamespaceLabel, true) { + // set the namespace label to allow automatic sinkbinding injection + enabled, err := knativeutil.EnableKnativeBindInNamespace(e.Ctx, e.Client, e.Integration.Namespace) + if err != nil { + t.L.Errorf(err, "Error setting label 'bindings.knative.dev/include=true' in namespace: %s", e.Integration.Namespace) + } else if enabled { + t.L.Infof("Label 'bindings.knative.dev/include=true' set in namespace: %s", e.Integration.Namespace) + } + } + // Add the SinkBinding in first position, to make sure it is created // before the reference source, so that the SinkBinding webhook has // all the information to perform injection. diff --git a/pkg/util/knative/knative.go b/pkg/util/knative/knative.go index 9a1d225b58..eae9b1c805 100644 --- a/pkg/util/knative/knative.go +++ b/pkg/util/knative/knative.go @@ -19,6 +19,7 @@ package knative import ( "context" + "encoding/json" "fmt" "net/url" @@ -27,6 +28,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apimachinery/pkg/types" "knative.dev/pkg/apis" ctrl "sigs.k8s.io/controller-runtime/pkg/client" @@ -206,3 +208,35 @@ func getSinkURI(ctx context.Context, c client.Client, sink *corev1.ObjectReferen } return addressURL.String(), nil } + +// EnableKnativeBindInNamespace sets the "bindings.knative.dev/include=true" label to the namespace, only +// if there aren't any of these labels bindings.knative.dev/include bindings.knative.dev/exclude in the namespace +// Returns true if the label was set in the namespace +// https://knative.dev/docs/eventing/custom-event-source/sinkbinding/create-a-sinkbinding +func EnableKnativeBindInNamespace(ctx context.Context, client client.Client, namespace string) (bool, error) { + ns, err := client.CoreV1().Namespaces().Get(ctx, namespace, metav1.GetOptions{}) + if err != nil { + return false, err + } + + // if there are sinkbinding labels in the namespace, camel-k-operator respects it and doesn't proceed + sinkbindingLabelsExists := ns.Labels["bindings.knative.dev/include"] != "" || ns.Labels["bindings.knative.dev/exclude"] != "" + if sinkbindingLabelsExists { + return false, nil + } + + var jsonLabelPatch = map[string]interface{}{ + "metadata": map[string]interface{}{ + "labels": map[string]string{"bindings.knative.dev/include": "true"}, + }, + } + patch, err := json.Marshal(jsonLabelPatch) + if err != nil { + return false, err + } + _, err = client.CoreV1().Namespaces().Patch(ctx, namespace, types.MergePatchType, patch, metav1.PatchOptions{}) + if err != nil { + return false, err + } + return true, nil +}