This is an automated email from the ASF dual-hosted git repository.

nferraro pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/camel-k.git


The following commit(s) were added to refs/heads/master by this push:
     new 66660a3  Fix #1675: use kamelets in the operator namespace
66660a3 is described below

commit 66660a33669ac55d08d773b537a0d728467848ae
Author: nicolaferraro <[email protected]>
AuthorDate: Tue Dec 1 15:57:36 2020 +0100

    Fix #1675: use kamelets in the operator namespace
---
 deploy/resources.go                                | 16 ++++++
 .../user-global-kamelet-viewer-role-binding.yaml   | 31 +++++++++++
 deploy/user-global-kamelet-viewer-role.yaml        | 32 +++++++++++
 e2e/common/files/timer-kamelet-usage.groovy        | 19 +++++++
 e2e/common/global_kamelet_test.go                  | 63 ++++++++++++++++++++++
 pkg/cmd/operator/operator.go                       |  6 ++-
 pkg/controller/kameletbinding/initialize.go        |  3 +-
 pkg/install/kamelets.go                            |  8 +++
 pkg/install/optional.go                            | 23 ++++++--
 pkg/kamelet/repository/repository.go               | 15 ++++++
 pkg/trait/kamelets.go                              |  5 +-
 11 files changed, 213 insertions(+), 8 deletions(-)

diff --git a/deploy/resources.go b/deploy/resources.go
index 4767929..a67c4fb 100644
--- a/deploy/resources.go
+++ b/deploy/resources.go
@@ -351,6 +351,20 @@ var assets = func() http.FileSystem {
 
                        compressedContent: 
[]byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xac\x53\xc1\x8e\xdb\x36\x10\xbd\xf3\x2b\x1e\xa4\x4b\x52\xac\xe5\xb6\xa7\x42\x3d\xb9\x9b\xdd\x56\x68\x60\x03\x2b\xa7\x41\x50\xf4\x40\x8b\x63\x69\xb0\x14\xa9\x0e\xa9\x55\xb6\x5f\x5f\x90\xb6\x37\x5e\x14\x3d\x04\x08\x6f\x24\x87\x6f\xde\x9b\xf7\x58\x62\xf5\xed\x96\x2a\xf1\x9e\x3b\x72\x81\x0c\xa2\x47\x1c\x08\x9b\x49\x77\x03\xa1\xf5\xc7\xb8\x68\x21\xdc\xfb\xd9\x19\x1d\xd9\x3b\xbc\xd9\xb4\xf7\x6f\x31\x3b\x43\x02\xef\x08\x5e\x
 [...]
                },
+               "/user-global-kamelet-viewer-role-binding.yaml": 
&vfsgen۰CompressedFileInfo{
+                       name:             
"user-global-kamelet-viewer-role-binding.yaml",
+                       modTime:          time.Time{},
+                       uncompressedSize: 1250,
+
+                       compressedContent: 
[]byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xac\x53\xcd\x6e\xda\x4c\x14\xdd\xcf\x53\x1c\xe1\x4d\x22\x81\xf9\xbe\xae\x2a\x77\x45\x12\x68\xad\x46\x20\x61\xd2\x28\xcb\x8b\x7d\xb1\x6f\xb1\x67\xdc\x99\x71\x1c\xfa\xf4\xd5\x18\xc8\x8f\x2a\xb5\xaa\x94\xd9\x20\x34\x77\xce\xcf\x3d\xc7\x11\x26\xef\x77\x54\x84\x5b\xc9\x59\x3b\x2e\xe0\x0d\x7c\xc5\x98\xb5\x94\x57\x8c\xcc\xec\x7c\x4f\x96\xb1\x30\x9d\x2e\xc8\x8b\xd1\xb8\x98\x65\x8b\x4b\x74\xba\x60\x0b\xa3\x19\xc6\xa2\x31\x96\x
 [...]
+               },
+               "/user-global-kamelet-viewer-role.yaml": 
&vfsgen۰CompressedFileInfo{
+                       name:             
"user-global-kamelet-viewer-role.yaml",
+                       modTime:          time.Time{},
+                       uncompressedSize: 1166,
+
+                       compressedContent: 
[]byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xac\x53\x4f\x6f\xfa\x46\x14\xbc\xef\xa7\x18\xe1\x4b\x22\x81\x69\x7b\xaa\xe8\x89\x26\xd0\x5a\x8d\x40\xc2\xa4\x51\x8e\x8b\xfd\xb0\x9f\x58\xef\xba\x6f\xd7\x38\xf4\xd3\x57\x6b\x4c\x43\xf4\xbb\x66\x2f\xeb\x3f\xe3\x37\x33\x3b\xe3\x04\xb3\xef\x5b\x2a\xc1\x0b\x17\x64\x3d\x95\x08\x0e\xa1\x26\x2c\x5b\x5d\xd4\x84\xdc\x1d\x43\xaf\x85\xb0\x76\x9d\x2d\x75\x60\x67\xf1\xb0\xcc\xd7\x8f\xe8\x6c\x49\x02\x67\x09\x4e\xd0\x38\x21\x95\xa0\x
 [...]
+               },
        }
        fs["/"].(*vfsgen۰DirInfo).entries = []os.FileInfo{
                fs["/addons"].(os.FileInfo),
@@ -390,6 +404,8 @@ var assets = func() http.FileSystem {
                fs["/templates"].(os.FileInfo),
                fs["/traits.yaml"].(os.FileInfo),
                fs["/user-cluster-role.yaml"].(os.FileInfo),
+               
fs["/user-global-kamelet-viewer-role-binding.yaml"].(os.FileInfo),
+               fs["/user-global-kamelet-viewer-role.yaml"].(os.FileInfo),
        }
        fs["/addons"].(*vfsgen۰DirInfo).entries = []os.FileInfo{
                fs["/addons/master"].(os.FileInfo),
diff --git a/deploy/user-global-kamelet-viewer-role-binding.yaml 
b/deploy/user-global-kamelet-viewer-role-binding.yaml
new file mode 100644
index 0000000..62fd38a
--- /dev/null
+++ b/deploy/user-global-kamelet-viewer-role-binding.yaml
@@ -0,0 +1,31 @@
+# ---------------------------------------------------------------------------
+# 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: rbac.authorization.k8s.io/v1
+kind: RoleBinding
+metadata:
+  name: camel-k-kamelet-viewer
+  labels:
+    app: "camel-k"
+roleRef:
+  apiGroup: rbac.authorization.k8s.io
+  kind: Role
+  name: camel-k-kamelet-viewer
+subjects:
+- apiGroup: rbac.authorization.k8s.io
+  kind: Group
+  name: system:authenticated
diff --git a/deploy/user-global-kamelet-viewer-role.yaml 
b/deploy/user-global-kamelet-viewer-role.yaml
new file mode 100644
index 0000000..80bc061
--- /dev/null
+++ b/deploy/user-global-kamelet-viewer-role.yaml
@@ -0,0 +1,32 @@
+# ---------------------------------------------------------------------------
+# 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: rbac.authorization.k8s.io/v1
+kind: Role
+metadata:
+  name: camel-k-kamelet-viewer
+  labels:
+    app: "camel-k"
+rules:
+- apiGroups:
+  - "camel.apache.org"
+  resources:
+  - kamelets
+  verbs:
+  - get
+  - list
+  - watch
diff --git a/e2e/common/files/timer-kamelet-usage.groovy 
b/e2e/common/files/timer-kamelet-usage.groovy
new file mode 100644
index 0000000..11ad5bb
--- /dev/null
+++ b/e2e/common/files/timer-kamelet-usage.groovy
@@ -0,0 +1,19 @@
+/*
+ * 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.
+ */
+
+from('kamelet:my-own-timer-source?message=Hello+world')
+    .to('log:info?showAll=false')
diff --git a/e2e/common/global_kamelet_test.go 
b/e2e/common/global_kamelet_test.go
new file mode 100644
index 0000000..4886820
--- /dev/null
+++ b/e2e/common/global_kamelet_test.go
@@ -0,0 +1,63 @@
+// +build integration
+
+// To enable compilation of this file in Goland, go to "Settings -> Go -> 
Vendoring & Build Tags -> Custom Tags" and add "integration"
+
+/*
+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.
+*/
+
+package common
+
+import (
+       "os"
+       "testing"
+
+       . "github.com/apache/camel-k/e2e/support"
+       "github.com/apache/camel-k/pkg/util/openshift"
+       . "github.com/onsi/gomega"
+       "github.com/stretchr/testify/assert"
+       v1 "k8s.io/api/core/v1"
+)
+
+func TestRunGlobalKamelet(t *testing.T) {
+       forceGlobalTest := os.Getenv("CAMEL_K_FORCE_GLOBAL_TEST") == "true"
+       if !forceGlobalTest {
+               ocp, err := openshift.IsOpenShift(TestClient)
+               assert.Nil(t, err)
+               if ocp {
+                       t.Skip("Prefer not to run on OpenShift to avoid giving 
more permissions to the user running tests")
+                       return
+               }
+       }
+
+       WithNewTestNamespace(t, func(ns string) {
+               Expect(Kamel("install", "-n", ns, 
"--global").Execute()).Should(BeNil())
+
+               Expect(CreateTimerKamelet(ns, 
"my-own-timer-source")()).Should(BeNil())
+
+               // NS2: namespace without operator
+               WithNewTestNamespace(t, func(ns2 string) {
+                       Expect(Kamel("install", "-n", ns2, 
"--skip-operator-setup", "--olm=false").Execute()).Should(BeNil())
+
+                       Expect(Kamel("run", "-n", ns2, 
"files/timer-kamelet-usage.groovy").Execute()).Should(BeNil())
+                       Eventually(IntegrationPodPhase(ns2, 
"timer-kamelet-usage"), TestTimeoutMedium).Should(Equal(v1.PodRunning))
+                       Eventually(IntegrationLogs(ns2, "timer-kamelet-usage"), 
TestTimeoutShort).Should(ContainSubstring("Hello world"))
+                       Expect(Kamel("delete", "--all", "-n", 
ns2).Execute()).Should(BeNil())
+               })
+
+               Expect(Kamel("uninstall", "-n", ns, 
"--skip-cluster-roles=false", 
"--skip-cluster-role-bindings=false").Execute()).Should(BeNil())
+       })
+}
diff --git a/pkg/cmd/operator/operator.go b/pkg/cmd/operator/operator.go
index 2b1cc54..fb4a7c2 100644
--- a/pkg/cmd/operator/operator.go
+++ b/pkg/cmd/operator/operator.go
@@ -65,7 +65,8 @@ func printVersion() {
 }
 
 // Run starts the Camel K operator
-func Run(healthPort, monitoringPort int32) 
{rand.Seed(time.Now().UTC().UnixNano())
+func Run(healthPort, monitoringPort int32) {
+       rand.Seed(time.Now().UTC().UnixNano())
 
        flag.Parse()
 
@@ -151,7 +152,8 @@ func Run(healthPort, monitoringPort int32) 
{rand.Seed(time.Now().UTC().UnixNano(
        // Try to register the OpenShift CLI Download link if possible
        installCtx, installCancel := context.WithTimeout(context.TODO(), 
1*time.Minute)
        defer installCancel()
-       install.OperatorStartupOptionalTools(installCtx, c, namespace, log)
+       operatorNamespace := os.Getenv("NAMESPACE")
+       install.OperatorStartupOptionalTools(installCtx, c, namespace, 
operatorNamespace, log)
 
        // Setup all Controllers
        if err := controller.AddToManager(mgr); err != nil {
diff --git a/pkg/controller/kameletbinding/initialize.go 
b/pkg/controller/kameletbinding/initialize.go
index 7235cd9..66fc329 100644
--- a/pkg/controller/kameletbinding/initialize.go
+++ b/pkg/controller/kameletbinding/initialize.go
@@ -23,6 +23,7 @@ import (
 
        "github.com/apache/camel-k/pkg/apis/camel/v1alpha1"
        "github.com/apache/camel-k/pkg/kamelet/repository"
+       "github.com/apache/camel-k/pkg/platform"
        "github.com/apache/camel-k/pkg/util/kubernetes"
        "github.com/apache/camel-k/pkg/util/patch"
        "github.com/pkg/errors"
@@ -109,7 +110,7 @@ func (action *initializeAction) findIcon(ctx 
context.Context, binding *v1alpha1.
                return "", nil
        }
 
-       repo, err := repository.New(ctx, action.client, binding.Namespace)
+       repo, err := repository.New(ctx, action.client, binding.Namespace, 
platform.GetOperatorNamespace())
        if err != nil {
                return "", err
        }
diff --git a/pkg/install/kamelets.go b/pkg/install/kamelets.go
index 07fb006..7298820 100644
--- a/pkg/install/kamelets.go
+++ b/pkg/install/kamelets.go
@@ -89,3 +89,11 @@ func KameletCatalog(ctx context.Context, c client.Client, 
namespace string) erro
 
        return nil
 }
+
+// KameletViewerRole installs the role that allows any user ro access kamelets 
in the global namespace
+func KameletViewerRole(ctx context.Context, c client.Client, namespace string) 
error {
+       if err := Resource(ctx, c, namespace, true, IdentityResourceCustomizer, 
"user-global-kamelet-viewer-role.yaml"); err != nil {
+               return err
+       }
+       return Resource(ctx, c, namespace, true, IdentityResourceCustomizer, 
"user-global-kamelet-viewer-role-binding.yaml")
+}
diff --git a/pkg/install/optional.go b/pkg/install/optional.go
index 0571844..e7019f4 100644
--- a/pkg/install/optional.go
+++ b/pkg/install/optional.go
@@ -26,7 +26,7 @@ import (
 )
 
 // OperatorStartupOptionalTools tries to install optional tools at operator 
startup and warns if something goes wrong
-func OperatorStartupOptionalTools(ctx context.Context, c client.Client, 
namespace string, log logr.Logger) {
+func OperatorStartupOptionalTools(ctx context.Context, c client.Client, 
namespace string, operatorNamespace string, log logr.Logger) {
 
        // Try to register the OpenShift CLI Download link if possible
        if err := OpenShiftConsoleDownloadLink(ctx, c); err != nil {
@@ -45,12 +45,29 @@ func OperatorStartupOptionalTools(ctx context.Context, c 
client.Client, namespac
                }
        }
 
-       // Try to install Kamelet Catalog automatically if operator is 
namespace scoped
+       // Try to install Kamelet Catalog automatically
+       var kameletNamespace string
+       globalOperator := false
        if namespace != "" && !strings.Contains(namespace, ",") {
-               if err := KameletCatalog(ctx, c, namespace); err != nil {
+               kameletNamespace = namespace
+       } else {
+               kameletNamespace = operatorNamespace
+               globalOperator = true
+       }
+
+       if kameletNamespace != "" {
+               if err := KameletCatalog(ctx, c, kameletNamespace); err != nil {
                        log.Info("Cannot install bundled Kamelet Catalog: 
skipping.")
                        log.V(8).Info("Error while installing bundled Kamelet 
Catalog", "error", err)
                }
+
+               if globalOperator {
+                       // Make sure that Kamelets installed in operator 
namespace can be used by others
+                       if err := KameletViewerRole(ctx, c, kameletNamespace); 
err != nil {
+                               log.Info("Cannot install global Kamelet viewer 
role: skipping.")
+                               log.V(8).Info("Error while installing global 
Kamelet viewer role", "error", err)
+                       }
+               }
        }
 
 }
diff --git a/pkg/kamelet/repository/repository.go 
b/pkg/kamelet/repository/repository.go
index a0f8a1b..721b887 100644
--- a/pkg/kamelet/repository/repository.go
+++ b/pkg/kamelet/repository/repository.go
@@ -53,6 +53,7 @@ type KameletRepository interface {
 // If one namespace defines an IntegrationPlatform (only the first 
IntegrationPlatform in state "Ready" found),
 // then all kamelet repository URIs defined in the IntegrationPlatform are 
included.
 func New(ctx context.Context, client camel.Interface, namespaces ...string) 
(KameletRepository, error) {
+       namespaces = makeDistinctNonEmpty(namespaces)
        platform, err := lookupPlatform(ctx, client, namespaces...)
        if err != nil {
                return nil, err
@@ -64,6 +65,7 @@ func New(ctx context.Context, client camel.Interface, 
namespaces ...string) (Kam
 // Kamelets are first looked up in all the given namespaces, in the order they 
appear,
 // then repositories defined in the platform are looked up.
 func NewForPlatform(ctx context.Context, client camel.Interface, platform 
*v1.IntegrationPlatform, namespaces ...string) (KameletRepository, error) {
+       namespaces = makeDistinctNonEmpty(namespaces)
        repoImpls := make([]KameletRepository, 0)
        for _, namespace := range namespaces {
                // Add first a namespace local repository for each namespace
@@ -176,3 +178,16 @@ func newFromURI(uri string) (KameletRepository, error) {
        }
        return nil, fmt.Errorf("invalid uri: %s", uri)
 }
+
+func makeDistinctNonEmpty(names []string) []string {
+       res := make([]string, 0, len(names))
+       presence := make(map[string]bool, len(names))
+       for _, n := range names {
+               if n == "" || presence[n] {
+                       continue
+               }
+               presence[n] = true
+               res = append(res, n)
+       }
+       return res
+}
diff --git a/pkg/trait/kamelets.go b/pkg/trait/kamelets.go
index 13c5bee..390c754 100644
--- a/pkg/trait/kamelets.go
+++ b/pkg/trait/kamelets.go
@@ -30,6 +30,7 @@ import (
        kameletutils "github.com/apache/camel-k/pkg/kamelet"
        "github.com/apache/camel-k/pkg/kamelet/repository"
        "github.com/apache/camel-k/pkg/metadata"
+       "github.com/apache/camel-k/pkg/platform"
        "github.com/apache/camel-k/pkg/util"
        "github.com/apache/camel-k/pkg/util/digest"
        "github.com/apache/camel-k/pkg/util/flow"
@@ -132,7 +133,7 @@ func (t *kameletsTrait) Apply(e *Environment) error {
 func (t *kameletsTrait) addKamelets(e *Environment) error {
        kameletKeys := t.getKameletKeys()
        if len(kameletKeys) > 0 {
-               repo, err := repository.NewForPlatform(e.C, e.Client, 
e.Platform, e.Integration.Namespace)
+               repo, err := repository.NewForPlatform(e.C, e.Client, 
e.Platform, e.Integration.Namespace, platform.GetOperatorNamespace())
                if err != nil {
                        return err
                }
@@ -170,7 +171,7 @@ func (t *kameletsTrait) addKamelets(e *Environment) error {
 
 func (t *kameletsTrait) configureApplicationProperties(e *Environment) error {
        if len(t.getKameletKeys()) > 0 {
-               repo, err := repository.NewForPlatform(e.C, e.Client, 
e.Platform, e.Integration.Namespace)
+               repo, err := repository.NewForPlatform(e.C, e.Client, 
e.Platform, e.Integration.Namespace, platform.GetOperatorNamespace())
                if err != nil {
                        return err
                }

Reply via email to