You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by as...@apache.org on 2020/02/12 09:48:55 UTC

[camel-k] branch master updated (7b817af -> c0efdcc)

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

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


    from 7b817af  fix #1270: upgrade to Knative 0.12
     new 6b8e113  Fix #1223: add OLM install options
     new 8228f4b  Fix #1223: install and uninstall via OLM
     new 748accd  Fix #1223: checking permissions before install
     new 65a9e7c  Fix #1223: fix lint
     new d43bdac  Fix #1223: add build-time overrides in Makefile
     new c0efdcc  Fix #1223: fix wait for resources

The 6 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 go.mod                                             |   1 +
 go.sum                                             |   3 +
 ...v1alpha1.go => addtoscheme_knative_eventing.go} |   0
 ..._v1alpha1.go => addtoscheme_knative_serving.go} |   0
 ...ive_eventing_v1alpha1.go => addtoscheme_olm.go} |   8 +-
 pkg/client/fastmapper.go                           |   1 +
 pkg/cmd/install.go                                 |  92 +++++-
 pkg/cmd/uninstall.go                               |  65 +++--
 pkg/util/olm/available.go                          |  62 ++++
 pkg/util/olm/operator.go                           | 320 +++++++++++++++++++++
 script/Makefile                                    |  10 +
 11 files changed, 529 insertions(+), 33 deletions(-)
 copy pkg/apis/{addtoscheme_knative_eventing_v1alpha1.go => addtoscheme_knative_eventing.go} (100%)
 rename pkg/apis/{addtoscheme_knative_serving_v1alpha1.go => addtoscheme_knative_serving.go} (100%)
 rename pkg/apis/{addtoscheme_knative_eventing_v1alpha1.go => addtoscheme_olm.go} (74%)
 create mode 100644 pkg/util/olm/available.go
 create mode 100644 pkg/util/olm/operator.go


[camel-k] 02/06: Fix #1223: install and uninstall via OLM

Posted by as...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 8228f4b84b510b224d4b3504eec4e6a2b08b586a
Author: Nicola Ferraro <ni...@gmail.com>
AuthorDate: Mon Feb 10 17:15:26 2020 +0100

    Fix #1223: install and uninstall via OLM
---
 pkg/apis/addtoscheme_olm.go |  2 ++
 pkg/cmd/install.go          | 16 +++++++----
 pkg/cmd/uninstall.go        | 64 ++++++++++++++++++++++++++++++-----------
 pkg/util/olm/available.go   |  6 +++-
 pkg/util/olm/operator.go    | 69 +++++++++++++++++++++++++++++++++++++--------
 5 files changed, 121 insertions(+), 36 deletions(-)

diff --git a/pkg/apis/addtoscheme_olm.go b/pkg/apis/addtoscheme_olm.go
index a69aa84..d891e98 100644
--- a/pkg/apis/addtoscheme_olm.go
+++ b/pkg/apis/addtoscheme_olm.go
@@ -18,10 +18,12 @@ limitations under the License.
 package apis
 
 import (
+	olmv1 "github.com/operator-framework/operator-lifecycle-manager/pkg/api/apis/operators/v1"
 	olmv1alpha1 "github.com/operator-framework/operator-lifecycle-manager/pkg/api/apis/operators/v1alpha1"
 )
 
 func init() {
 	// Register the types with the Scheme so the components can map objects to GroupVersionKinds and back
 	AddToSchemes = append(AddToSchemes, olmv1alpha1.AddToScheme)
+	AddToSchemes = append(AddToSchemes, olmv1.AddToScheme)
 }
diff --git a/pkg/cmd/install.go b/pkg/cmd/install.go
index 8e9c669..292c9d9 100644
--- a/pkg/cmd/install.go
+++ b/pkg/cmd/install.go
@@ -134,7 +134,7 @@ type installCmdOptions struct {
 	Global            bool     `mapstructure:"global"`
 	KanikoBuildCache  bool     `mapstructure:"kaniko-build-cache"`
 	Save              bool     `mapstructure:"save"`
-	Olm               bool    `mapstructure:"olm"`
+	Olm               bool     `mapstructure:"olm"`
 	ClusterType       string   `mapstructure:"cluster-type"`
 	OutputFormat      string   `mapstructure:"output"`
 	RuntimeVersion    string   `mapstructure:"runtime-version"`
@@ -172,18 +172,22 @@ func (o *installCmdOptions) install(cobraCmd *cobra.Command, _ []string) error {
 		if olmClient, err = clientProvider.Get(); err != nil {
 			return err
 		}
-		if installViaOLM, err = olm.IsAvailable(o.Context, olmClient); err != nil {
+		if installViaOLM, err = olm.IsAvailable(o.Context, olmClient, o.Namespace); err != nil {
 			return errors.Wrap(err, "error while checking OLM availability. Run with '--olm=false' to skip this check")
 		}
 
 		if installViaOLM {
-			fmt.Fprintln(cobraCmd.OutOrStdout(), "OLM is available in the cluster");
-			if err = olm.Install(o.Context, olmClient, o.Namespace, o.Global, o.olmOptions, collection); err != nil {
+			fmt.Fprintln(cobraCmd.OutOrStdout(), "OLM is available in the cluster")
+			var installed bool
+			if installed, err = olm.Install(o.Context, olmClient, o.Namespace, o.Global, o.olmOptions, collection); err != nil {
 				return err
 			}
+			if !installed {
+				fmt.Fprintln(cobraCmd.OutOrStdout(), "OLM resources are already available: skipping installation")
+			}
 		}
 
-		if err = install.WaitForAllCRDInstallation(o.Context, clientProvider, 90 * time.Second); err != nil {
+		if err = install.WaitForAllCRDInstallation(o.Context, clientProvider, 90*time.Second); err != nil {
 			return err
 		}
 	}
@@ -202,7 +206,7 @@ func (o *installCmdOptions) install(cobraCmd *cobra.Command, _ []string) error {
 
 	if o.ClusterSetupOnly {
 		if collection == nil {
-			fmt.Fprintln(cobraCmd.OutOrStdout(),"Camel K cluster setup completed successfully")
+			fmt.Fprintln(cobraCmd.OutOrStdout(), "Camel K cluster setup completed successfully")
 		}
 	} else {
 		c, err := o.GetCmdClient()
diff --git a/pkg/cmd/uninstall.go b/pkg/cmd/uninstall.go
index 045b1b8..11462f8 100644
--- a/pkg/cmd/uninstall.go
+++ b/pkg/cmd/uninstall.go
@@ -18,9 +18,10 @@ limitations under the License.
 package cmd
 
 import (
-	"errors"
 	"fmt"
 
+	"github.com/apache/camel-k/pkg/util/olm"
+	"github.com/pkg/errors"
 	"k8s.io/client-go/kubernetes"
 
 	"github.com/apache/camel-k/pkg/client"
@@ -39,7 +40,7 @@ func newCmdUninstall(rootCmdOptions *RootCmdOptions) (*cobra.Command, *uninstall
 		Use:   "uninstall",
 		Short: "Uninstall Camel K from a Kubernetes cluster",
 		Long:  `Uninstalls Camel K from a Kubernetes or OpenShift cluster.`,
-		Run:   options.uninstall,
+		RunE:  options.uninstall,
 	}
 
 	cmd.Flags().BoolVar(&options.skipOperator, "skip-operator", false, "Do not uninstall the Camel-K Operator in the current namespace")
@@ -50,6 +51,11 @@ func newCmdUninstall(rootCmdOptions *RootCmdOptions) (*cobra.Command, *uninstall
 	cmd.Flags().BoolVar(&options.skipIntegrationPlatform, "skip-integration-platform", false, "Do not uninstall the Camel-K Integration Platform in the current namespace")
 	cmd.Flags().BoolVar(&options.skipServiceAccounts, "skip-service-accounts", false, "Do not uninstall the Camel-K Service Accounts in the current namespace")
 	cmd.Flags().BoolVar(&options.skipConfigMaps, "skip-config-maps", false, "Do not uninstall the Camel-K Config Maps in the current namespace")
+	cmd.Flags().BoolVar(&options.global, "global", false, "Indicates that a global installation is going to be uninstalled (affects OLM)")
+	cmd.Flags().BoolVar(&options.olmEnabled, "olm", true, "Try to uninstall via OLM (Operator Lifecycle Manager) if available")
+	cmd.Flags().StringVar(&options.olmOptions.OperatorName, "olm-operator-name", olm.DefaultOperatorName, "Name of the Camel K operator in the OLM source or marketplace")
+	cmd.Flags().StringVar(&options.olmOptions.Package, "olm-package", olm.DefaultPackage, "Name of the Camel K package in the OLM source or marketplace")
+	cmd.Flags().StringVar(&options.olmOptions.GlobalNamespace, "olm-global-namespace", olm.DefaultGlobalNamespace, "A namespace containing an OperatorGroup that defines global scope for the operator (used in combination with the --global flag)")
 
 	// completion support
 	configureBashAnnotationForFlag(
@@ -73,6 +79,10 @@ type uninstallCmdOptions struct {
 	skipIntegrationPlatform bool
 	skipServiceAccounts     bool
 	skipConfigMaps          bool
+	olmEnabled              bool
+	global                  bool
+
+	olmOptions olm.Options
 }
 
 var defaultListOptions = metav1.ListOptions{
@@ -80,33 +90,53 @@ var defaultListOptions = metav1.ListOptions{
 }
 
 // nolint: gocyclo
-func (o *uninstallCmdOptions) uninstall(_ *cobra.Command, _ []string) {
+func (o *uninstallCmdOptions) uninstall(cmd *cobra.Command, _ []string) error {
 	c, err := o.GetCmdClient()
 	if err != nil {
-		return
+		return err
+	}
+
+	uninstallViaOLM := false
+	if o.olmEnabled {
+		var err error
+		if uninstallViaOLM, err = olm.IsAvailable(o.Context, c, o.Namespace); err != nil {
+			return errors.Wrap(err, "error while checking OLM availability. Run with '--olm=false' to skip this check")
+		}
+
+		if uninstallViaOLM {
+			fmt.Fprintln(cmd.OutOrStdout(), "OLM is available in the cluster")
+			if err = olm.Uninstall(o.Context, c, o.Namespace, o.global, o.olmOptions); err != nil {
+				return err
+			}
+			where := fmt.Sprintf("from namespace %s", o.Namespace)
+			if o.global {
+				where = "globally"
+			}
+			fmt.Fprintf(cmd.OutOrStdout(), "Camel-K OLM service removed %s\n", where)
+		}
 	}
 
 	if !o.skipIntegrationPlatform {
 		if err = o.uninstallIntegrationPlatform(); err != nil {
-			fmt.Print(err)
-			return
+			return err
 		}
-		fmt.Printf("Camel-K Integration Platform removed from namespace %s\n", o.Namespace)
+		fmt.Fprintf(cmd.OutOrStdout(), "Camel-K Integration Platform removed from namespace %s\n", o.Namespace)
 	}
 
-	if err = o.uninstallClusterWideResources(c); err != nil {
-		fmt.Print(err)
-		return
-	}
-	fmt.Printf("Camel-K Cluster Wide Resources removed from namespace %s\n", o.Namespace)
+	if !uninstallViaOLM {
+		if err = o.uninstallClusterWideResources(c); err != nil {
+			return err
+		}
+		fmt.Fprintf(cmd.OutOrStdout(), "Camel-K Cluster Wide Resources removed from namespace %s\n", o.Namespace)
 
-	if !o.skipOperator {
-		if err = o.uninstallOperator(c); err != nil {
-			fmt.Print(err)
-			return
+		if !o.skipOperator {
+			if err = o.uninstallOperator(c); err != nil {
+				return err
+			}
+			fmt.Fprintf(cmd.OutOrStdout(), "Camel-K Operator removed from namespace %s\n", o.Namespace)
 		}
-		fmt.Printf("Camel-K Operator removed from namespace %s\n", o.Namespace)
 	}
+	return nil
 }
 
 func (o *uninstallCmdOptions) uninstallOperator(c client.Client) error {
diff --git a/pkg/util/olm/available.go b/pkg/util/olm/available.go
index 2d7636f..3c1d627 100644
--- a/pkg/util/olm/available.go
+++ b/pkg/util/olm/available.go
@@ -20,7 +20,9 @@ package olm
 import (
 	"context"
 
+	"github.com/apache/camel-k/pkg/client"
 	kubernetesutils "github.com/apache/camel-k/pkg/util/kubernetes"
+	olmv1 "github.com/operator-framework/operator-lifecycle-manager/pkg/api/apis/operators/v1"
 	olmv1alpha1 "github.com/operator-framework/operator-lifecycle-manager/pkg/api/apis/operators/v1alpha1"
 	k8serrors "k8s.io/apimachinery/pkg/api/errors"
 	"k8s.io/apimachinery/pkg/runtime/schema"
@@ -30,7 +32,7 @@ import (
 // IsAvailable returns true if we are connected to a cluster with OLM installed
 //
 // This method should not be called from the operator, as it might require permissions that are not available.
-func IsAvailable(ctx context.Context, c kubernetes.Interface) (bool, error) {
+func IsAvailable(ctx context.Context, c client.Client, namespace string) (bool, error) {
 	// check some Knative APIs
 	for _, api := range getOLMGroupVersions() {
 		if installed, err := isAvailable(c, api); err != nil {
@@ -39,6 +41,7 @@ func IsAvailable(ctx context.Context, c kubernetes.Interface) (bool, error) {
 			return true, nil
 		}
 	}
+
 	return false, nil
 }
 
@@ -55,5 +58,6 @@ func isAvailable(c kubernetes.Interface, api schema.GroupVersion) (bool, error)
 func getOLMGroupVersions() []schema.GroupVersion {
 	return []schema.GroupVersion{
 		olmv1alpha1.SchemeGroupVersion,
+		olmv1.SchemeGroupVersion,
 	}
 }
diff --git a/pkg/util/olm/operator.go b/pkg/util/olm/operator.go
index c5bda90..5b23d14 100644
--- a/pkg/util/olm/operator.go
+++ b/pkg/util/olm/operator.go
@@ -19,11 +19,14 @@ package olm
 
 import (
 	"context"
+	"fmt"
 	"strings"
 
 	"github.com/apache/camel-k/pkg/client"
 	"github.com/apache/camel-k/pkg/util/kubernetes"
+	olmv1 "github.com/operator-framework/operator-lifecycle-manager/pkg/api/apis/operators/v1"
 	olmv1alpha1 "github.com/operator-framework/operator-lifecycle-manager/pkg/api/apis/operators/v1alpha1"
+	"github.com/pkg/errors"
 	v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	runtime "sigs.k8s.io/controller-runtime/pkg/client"
 )
@@ -54,13 +57,13 @@ var DefaultGlobalNamespace = "openshift-operators"
 
 // Options contains information about an operator in OLM
 type Options struct {
-	OperatorName        string
-	Package             string
-	Channel             string
-	Source              string
-	SourceNamespace     string
-	StartingCSV         string
-	GlobalNamespace     string
+	OperatorName    string
+	Package         string
+	Channel         string
+	Source          string
+	SourceNamespace string
+	StartingCSV     string
+	GlobalNamespace string
 }
 
 // IsOperatorInstalled tells if a OLM CSV or a Subscription is already installed in the namespace
@@ -83,13 +86,13 @@ func IsOperatorInstalled(ctx context.Context, client client.Client, namespace st
 }
 
 // Install creates a subscription for the OLM package
-func Install(ctx context.Context, client client.Client, namespace string, global bool, options Options, collection *kubernetes.Collection) error {
+func Install(ctx context.Context, client client.Client, namespace string, global bool, options Options, collection *kubernetes.Collection) (bool, error) {
 	options = fillDefaults(options)
 	if installed, err := IsOperatorInstalled(ctx, client, namespace, global, options); err != nil {
-		return err
+		return false, err
 	} else if installed {
 		// Already installed
-		return nil
+		return false, nil
 	}
 
 	targetNamespace := namespace
@@ -113,9 +116,38 @@ func Install(ctx context.Context, client client.Client, namespace string, global
 	}
 	if collection != nil {
 		collection.Add(&sub)
-		return nil
+	} else {
+		if err := client.Create(ctx, &sub); err != nil {
+			return false, err
+		}
+	}
+
+	if !global {
+		group, err := findOperatorGroup(ctx, client, namespace, options)
+		if err != nil {
+			return false, err
+		}
+		if group == nil {
+			group = &olmv1.OperatorGroup{
+				ObjectMeta: v1.ObjectMeta{
+					Namespace:    namespace,
+					GenerateName: fmt.Sprintf("%s-", namespace),
+				},
+				Spec: olmv1.OperatorGroupSpec{
+					TargetNamespaces: []string{namespace},
+				},
+			}
+			if collection != nil {
+				collection.Add(group)
+			} else {
+				if err := client.Create(ctx, group); err != nil {
+					return false, errors.Wrap(err, fmt.Sprintf("namespace %s has no operator group defined and current user is not able to create it. " +
+						"Make sure you have the right roles to install operators from OLM", namespace))
+				}
+			}
+		}
 	}
-	return client.Create(ctx, &sub)
+	return true, nil
 }
 
 // Uninstall removes CSV and subscription from the namespace
@@ -175,6 +207,19 @@ func findCSV(ctx context.Context, client client.Client, namespace string, option
 	return nil, nil
 }
 
+func findOperatorGroup(ctx context.Context, client client.Client, namespace string, options Options) (*olmv1.OperatorGroup, error) {
+	opGroupList := olmv1.OperatorGroupList{}
+	if err := client.List(ctx, &opGroupList, runtime.InNamespace(namespace)); err != nil {
+		return nil, err
+	}
+
+	if len(opGroupList.Items) > 0 {
+		return &opGroupList.Items[0], nil
+	}
+
+	return nil, nil
+}
+
 func fillDefaults(o Options) Options {
 	if o.OperatorName == "" {
 		o.OperatorName = DefaultOperatorName


[camel-k] 04/06: Fix #1223: fix lint

Posted by as...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 65a9e7cd39a3455ed254383106010879af98b3e9
Author: Nicola Ferraro <ni...@gmail.com>
AuthorDate: Mon Feb 10 18:02:46 2020 +0100

    Fix #1223: fix lint
---
 pkg/cmd/install.go        | 10 ++++++----
 pkg/cmd/uninstall.go      |  5 +++--
 pkg/util/olm/available.go |  5 ++---
 pkg/util/olm/operator.go  | 17 ++++++++---------
 4 files changed, 19 insertions(+), 18 deletions(-)

diff --git a/pkg/cmd/install.go b/pkg/cmd/install.go
index eee8a8f..42c5128 100644
--- a/pkg/cmd/install.go
+++ b/pkg/cmd/install.go
@@ -102,8 +102,10 @@ func newCmdInstall(rootCmdOptions *RootCmdOptions) (*cobra.Command, *installCmdO
 	cmd.Flags().String("olm-channel", olm.DefaultChannel, "Name of the Camel K channel in the OLM source or marketplace")
 	cmd.Flags().String("olm-source", olm.DefaultSource, "Name of the OLM source providing the Camel K package (defaults to the standard Operator Hub source)")
 	cmd.Flags().String("olm-source-namespace", olm.DefaultSourceNamespace, "Namespace where the OLM source is available")
-	cmd.Flags().String("olm-starting-csv", olm.DefaultStartingCSV, "Allow to install a specific version from the operator source instead of latest available from the channel")
-	cmd.Flags().String("olm-global-namespace", olm.DefaultGlobalNamespace, "A namespace containing an OperatorGroup that defines global scope for the operator (used in combination with the --global flag)")
+	cmd.Flags().String("olm-starting-csv", olm.DefaultStartingCSV, "Allow to install a specific version from the operator source instead of latest available "+
+		"from the channel")
+	cmd.Flags().String("olm-global-namespace", olm.DefaultGlobalNamespace, "A namespace containing an OperatorGroup that defines global scope for the "+
+		"operator (used in combination with the --global flag)")
 
 	// maven settings
 	cmd.Flags().String("local-repository", "", "Location of the local maven repository")
@@ -174,7 +176,7 @@ func (o *installCmdOptions) install(cobraCmd *cobra.Command, _ []string) error {
 			return err
 		}
 		var olmAvailable bool
-		if olmAvailable, err = olm.IsAvailable(o.Context, olmClient, o.Namespace); err != nil {
+		if olmAvailable, err = olm.IsAPIAvailable(o.Context, olmClient, o.Namespace); err != nil {
 			return errors.Wrap(err, "error while checking OLM availability. Run with '--olm=false' to skip this check")
 		}
 
@@ -183,7 +185,7 @@ func (o *installCmdOptions) install(cobraCmd *cobra.Command, _ []string) error {
 				return errors.Wrap(err, "error while checking permissions to install operator via OLM. Run with '--olm=false' to skip this check")
 			}
 			if !installViaOLM {
-				fmt.Fprintln(cobraCmd.OutOrStdout(), "OLM is available but current user has not enough permissions to create the operator. " +
+				fmt.Fprintln(cobraCmd.OutOrStdout(), "OLM is available but current user has not enough permissions to create the operator. "+
 					"You can either ask your administrator to provide permissions (preferred) or run the install command with the `--olm=false` flag.")
 				os.Exit(1)
 			}
diff --git a/pkg/cmd/uninstall.go b/pkg/cmd/uninstall.go
index 11462f8..ab264b4 100644
--- a/pkg/cmd/uninstall.go
+++ b/pkg/cmd/uninstall.go
@@ -55,7 +55,8 @@ func newCmdUninstall(rootCmdOptions *RootCmdOptions) (*cobra.Command, *uninstall
 	cmd.Flags().BoolVar(&options.olmEnabled, "olm", true, "Try to uninstall via OLM (Operator Lifecycle Manager) if available")
 	cmd.Flags().StringVar(&options.olmOptions.OperatorName, "olm-operator-name", olm.DefaultOperatorName, "Name of the Camel K operator in the OLM source or marketplace")
 	cmd.Flags().StringVar(&options.olmOptions.Package, "olm-package", olm.DefaultPackage, "Name of the Camel K package in the OLM source or marketplace")
-	cmd.Flags().StringVar(&options.olmOptions.GlobalNamespace, "olm-global-namespace", olm.DefaultGlobalNamespace, "A namespace containing an OperatorGroup that defines global scope for the operator (used in combination with the --global flag)")
+	cmd.Flags().StringVar(&options.olmOptions.GlobalNamespace, "olm-global-namespace", olm.DefaultGlobalNamespace, "A namespace containing an OperatorGroup that defines "+
+		"global scope for the operator (used in combination with the --global flag)")
 
 	// completion support
 	configureBashAnnotationForFlag(
@@ -99,7 +100,7 @@ func (o *uninstallCmdOptions) uninstall(cmd *cobra.Command, _ []string) error {
 	uninstallViaOLM := false
 	if o.olmEnabled {
 		var err error
-		if uninstallViaOLM, err = olm.IsAvailable(o.Context, c, o.Namespace); err != nil {
+		if uninstallViaOLM, err = olm.IsAPIAvailable(o.Context, c, o.Namespace); err != nil {
 			return errors.Wrap(err, "error while checking OLM availability. Run with '--olm=false' to skip this check")
 		}
 
diff --git a/pkg/util/olm/available.go b/pkg/util/olm/available.go
index 3c1d627..eb4b7da 100644
--- a/pkg/util/olm/available.go
+++ b/pkg/util/olm/available.go
@@ -20,7 +20,6 @@ package olm
 import (
 	"context"
 
-	"github.com/apache/camel-k/pkg/client"
 	kubernetesutils "github.com/apache/camel-k/pkg/util/kubernetes"
 	olmv1 "github.com/operator-framework/operator-lifecycle-manager/pkg/api/apis/operators/v1"
 	olmv1alpha1 "github.com/operator-framework/operator-lifecycle-manager/pkg/api/apis/operators/v1alpha1"
@@ -29,10 +28,10 @@ import (
 	"k8s.io/client-go/kubernetes"
 )
 
-// IsAvailable returns true if we are connected to a cluster with OLM installed
+// IsAPIAvailable returns true if we are connected to a cluster with OLM installed
 //
 // This method should not be called from the operator, as it might require permissions that are not available.
-func IsAvailable(ctx context.Context, c client.Client, namespace string) (bool, error) {
+func IsAPIAvailable(ctx context.Context, c kubernetes.Interface, namespace string) (bool, error) {
 	// check some Knative APIs
 	for _, api := range getOLMGroupVersions() {
 		if installed, err := isAvailable(c, api); err != nil {
diff --git a/pkg/util/olm/operator.go b/pkg/util/olm/operator.go
index 73a84e4..a85c414 100644
--- a/pkg/util/olm/operator.go
+++ b/pkg/util/olm/operator.go
@@ -135,6 +135,7 @@ func HasPermissionToInstall(ctx context.Context, client client.Client, namespace
 	return true, nil
 }
 
+// nolint:unparam
 func checkPermission(client client.Client, group, resource, namespace, name, verb string) (bool, error) {
 	sarReview := &authorizationv1.SelfSubjectAccessReview{
 		Spec: authorizationv1.SelfSubjectAccessReviewSpec{
@@ -191,10 +192,8 @@ func Install(ctx context.Context, client client.Client, namespace string, global
 	}
 	if collection != nil {
 		collection.Add(&sub)
-	} else {
-		if err := client.Create(ctx, &sub); err != nil {
-			return false, err
-		}
+	} else if err := client.Create(ctx, &sub); err != nil {
+		return false, err
 	}
 
 	if !global {
@@ -214,11 +213,10 @@ func Install(ctx context.Context, client client.Client, namespace string, global
 			}
 			if collection != nil {
 				collection.Add(group)
-			} else {
-				if err := client.Create(ctx, group); err != nil {
-					return false, errors.Wrap(err, fmt.Sprintf("namespace %s has no operator group defined and current user is not able to create it. "+
-						"Make sure you have the right roles to install operators from OLM", namespace))
-				}
+			} else if err := client.Create(ctx, group); err != nil {
+				return false, errors.Wrap(err, fmt.Sprintf("namespace %s has no operator group defined and "+
+					"current user is not able to create it. "+
+					"Make sure you have the right roles to install operators from OLM", namespace))
 			}
 		}
 	}
@@ -282,6 +280,7 @@ func findCSV(ctx context.Context, client client.Client, namespace string, option
 	return nil, nil
 }
 
+// nolint:unparam
 func findOperatorGroup(ctx context.Context, client client.Client, namespace string, options Options) (*olmv1.OperatorGroup, error) {
 	opGroupList := olmv1.OperatorGroupList{}
 	if err := client.List(ctx, &opGroupList, runtime.InNamespace(namespace)); err != nil {


[camel-k] 05/06: Fix #1223: add build-time overrides in Makefile

Posted by as...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit d43bdacbda264fbce0a287f5c4e7d49d84bdebf3
Author: Nicola Ferraro <ni...@gmail.com>
AuthorDate: Mon Feb 10 18:18:20 2020 +0100

    Fix #1223: add build-time overrides in Makefile
---
 script/Makefile | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/script/Makefile b/script/Makefile
index df560c4..ff8e7d9 100644
--- a/script/Makefile
+++ b/script/Makefile
@@ -36,6 +36,16 @@ STAGING_RUNTIME_REPO := https://repository.apache.org/content/repositories/orgap
 # or "download" them from Apache Snapshots and Maven Central
 PACKAGE_ARTIFACTS_STRATEGY := copy
 
+# OLM (Operator Lifecycle Manager and Operator Hub): uncomment to override operator settings at build time
+#GOLDFLAGS += -X github.com/apache/camel-k/pkg/util/olm.DefaultOperatorName=camel-k-operator
+#GOLDFLAGS += -X github.com/apache/camel-k/pkg/util/olm.DefaultPackage=camel-k
+#GOLDFLAGS += -X github.com/apache/camel-k/pkg/util/olm.DefaultChannel=alpha
+#GOLDFLAGS += -X github.com/apache/camel-k/pkg/util/olm.DefaultSource=community-operators
+#GOLDFLAGS += -X github.com/apache/camel-k/pkg/util/olm.DefaultSourceNamespace=openshift-marketplace
+#GOLDFLAGS += -X github.com/apache/camel-k/pkg/util/olm.DefaultStartingCSV=
+#GOLDFLAGS += -X github.com/apache/camel-k/pkg/util/olm.DefaultGlobalNamespace=openshift-operators
+
+# Build
 GOLDFLAGS += -X github.com/apache/camel-k/pkg/cmd/operator.GitCommit=$(GIT_COMMIT)
 GOFLAGS = -ldflags "$(GOLDFLAGS)" -trimpath
 


[camel-k] 03/06: Fix #1223: checking permissions before install

Posted by as...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 748accde000393d3d33e0d40f0ea7e11e4ff65ec
Author: Nicola Ferraro <ni...@gmail.com>
AuthorDate: Mon Feb 10 17:53:56 2020 +0100

    Fix #1223: checking permissions before install
---
 pkg/cmd/install.go       | 15 +++++++++-
 pkg/util/olm/operator.go | 77 +++++++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 90 insertions(+), 2 deletions(-)

diff --git a/pkg/cmd/install.go b/pkg/cmd/install.go
index 292c9d9..eee8a8f 100644
--- a/pkg/cmd/install.go
+++ b/pkg/cmd/install.go
@@ -19,6 +19,7 @@ package cmd
 
 import (
 	"fmt"
+	"os"
 	"regexp"
 	"strings"
 	"time"
@@ -172,10 +173,22 @@ func (o *installCmdOptions) install(cobraCmd *cobra.Command, _ []string) error {
 		if olmClient, err = clientProvider.Get(); err != nil {
 			return err
 		}
-		if installViaOLM, err = olm.IsAvailable(o.Context, olmClient, o.Namespace); err != nil {
+		var olmAvailable bool
+		if olmAvailable, err = olm.IsAvailable(o.Context, olmClient, o.Namespace); err != nil {
 			return errors.Wrap(err, "error while checking OLM availability. Run with '--olm=false' to skip this check")
 		}
 
+		if olmAvailable {
+			if installViaOLM, err = olm.HasPermissionToInstall(o.Context, olmClient, o.Namespace, o.Global, o.olmOptions); err != nil {
+				return errors.Wrap(err, "error while checking permissions to install operator via OLM. Run with '--olm=false' to skip this check")
+			}
+			if !installViaOLM {
+				fmt.Fprintln(cobraCmd.OutOrStdout(), "OLM is available but current user has not enough permissions to create the operator. " +
+					"You can either ask your administrator to provide permissions (preferred) or run the install command with the `--olm=false` flag.")
+				os.Exit(1)
+			}
+		}
+
 		if installViaOLM {
 			fmt.Fprintln(cobraCmd.OutOrStdout(), "OLM is available in the cluster")
 			var installed bool
diff --git a/pkg/util/olm/operator.go b/pkg/util/olm/operator.go
index 5b23d14..73a84e4 100644
--- a/pkg/util/olm/operator.go
+++ b/pkg/util/olm/operator.go
@@ -27,6 +27,8 @@ import (
 	olmv1 "github.com/operator-framework/operator-lifecycle-manager/pkg/api/apis/operators/v1"
 	olmv1alpha1 "github.com/operator-framework/operator-lifecycle-manager/pkg/api/apis/operators/v1alpha1"
 	"github.com/pkg/errors"
+	authorizationv1 "k8s.io/api/authorization/v1"
+	k8serrors "k8s.io/apimachinery/pkg/api/errors"
 	v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	runtime "sigs.k8s.io/controller-runtime/pkg/client"
 )
@@ -85,6 +87,79 @@ func IsOperatorInstalled(ctx context.Context, client client.Client, namespace st
 	return false, nil
 }
 
+// HasPermissionToInstall checks if the current user/serviceaccount has the right permissions to install camel k via OLM
+func HasPermissionToInstall(ctx context.Context, client client.Client, namespace string, global bool, options Options) (bool, error) {
+	if ok, err := checkPermission(client, olmv1alpha1.GroupName, "clusterserviceversions", namespace, options.Package, "list"); err != nil {
+		return false, err
+	} else if !ok {
+		return false, nil
+	}
+
+	targetNamespace := namespace
+	if global {
+		targetNamespace = options.GlobalNamespace
+	}
+
+	if ok, err := checkPermission(client, olmv1alpha1.GroupName, "subscriptions", targetNamespace, options.Package, "create"); err != nil {
+		return false, err
+	} else if !ok {
+		return false, nil
+	}
+
+	if installed, err := IsOperatorInstalled(ctx, client, namespace, global, options); err != nil {
+		return false, err
+	} else if installed {
+		return true, nil
+	}
+
+	if !global {
+		if ok, err := checkPermission(client, olmv1.GroupName, "operatorgroups", namespace, options.Package, "list"); err != nil {
+			return false, err
+		} else if !ok {
+			return false, nil
+		}
+
+		group, err := findOperatorGroup(ctx, client, namespace, options)
+		if err != nil {
+			return false, err
+		}
+		if group == nil {
+			if ok, err := checkPermission(client, olmv1.GroupName, "operatorgroups", namespace, options.Package, "create"); err != nil {
+				return false, err
+			} else if !ok {
+				return false, nil
+			}
+		}
+
+	}
+	return true, nil
+}
+
+func checkPermission(client client.Client, group, resource, namespace, name, verb string) (bool, error) {
+	sarReview := &authorizationv1.SelfSubjectAccessReview{
+		Spec: authorizationv1.SelfSubjectAccessReviewSpec{
+			ResourceAttributes: &authorizationv1.ResourceAttributes{
+				Group:     group,
+				Resource:  resource,
+				Namespace: namespace,
+				Name:      name,
+				Verb:      verb,
+			},
+		},
+	}
+
+	sar, err := client.AuthorizationV1().SelfSubjectAccessReviews().Create(sarReview)
+	if err != nil {
+		if k8serrors.IsForbidden(err) {
+			return false, nil
+		}
+		return false, err
+	} else if !sar.Status.Allowed {
+		return false, nil
+	}
+	return true, nil
+}
+
 // Install creates a subscription for the OLM package
 func Install(ctx context.Context, client client.Client, namespace string, global bool, options Options, collection *kubernetes.Collection) (bool, error) {
 	options = fillDefaults(options)
@@ -141,7 +216,7 @@ func Install(ctx context.Context, client client.Client, namespace string, global
 				collection.Add(group)
 			} else {
 				if err := client.Create(ctx, group); err != nil {
-					return false, errors.Wrap(err, fmt.Sprintf("namespace %s has no operator group defined and current user is not able to create it. " +
+					return false, errors.Wrap(err, fmt.Sprintf("namespace %s has no operator group defined and current user is not able to create it. "+
 						"Make sure you have the right roles to install operators from OLM", namespace))
 				}
 			}


[camel-k] 06/06: Fix #1223: fix wait for resources

Posted by as...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit c0efdcccf51c84a2f2b7c80c3362da2178444a19
Author: Nicola Ferraro <ni...@gmail.com>
AuthorDate: Mon Feb 10 23:27:00 2020 +0100

    Fix #1223: fix wait for resources
---
 pkg/cmd/install.go | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/pkg/cmd/install.go b/pkg/cmd/install.go
index 42c5128..8b973b8 100644
--- a/pkg/cmd/install.go
+++ b/pkg/cmd/install.go
@@ -200,10 +200,10 @@ func (o *installCmdOptions) install(cobraCmd *cobra.Command, _ []string) error {
 			if !installed {
 				fmt.Fprintln(cobraCmd.OutOrStdout(), "OLM resources are already available: skipping installation")
 			}
-		}
 
-		if err = install.WaitForAllCRDInstallation(o.Context, clientProvider, 90*time.Second); err != nil {
-			return err
+			if err = install.WaitForAllCRDInstallation(o.Context, clientProvider, 90*time.Second); err != nil {
+				return err
+			}
 		}
 	}
 


[camel-k] 01/06: Fix #1223: add OLM install options

Posted by as...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 6b8e113c4ce5a4cd7d6d91551033b12b0f375f6e
Author: Nicola Ferraro <ni...@gmail.com>
AuthorDate: Sat Feb 8 00:47:35 2020 +0100

    Fix #1223: add OLM install options
---
 go.mod                                             |   1 +
 go.sum                                             |   3 +
 ...v1alpha1.go => addtoscheme_knative_eventing.go} |   0
 ..._v1alpha1.go => addtoscheme_knative_serving.go} |   0
 ...tive_serving_v1alpha1.go => addtoscheme_olm.go} |   4 +-
 pkg/client/fastmapper.go                           |   1 +
 pkg/cmd/install.go                                 |  73 ++++++--
 pkg/util/olm/available.go                          |  59 ++++++
 pkg/util/olm/operator.go                           | 201 +++++++++++++++++++++
 9 files changed, 328 insertions(+), 14 deletions(-)

diff --git a/go.mod b/go.mod
index 9d88d7a..52f4532 100644
--- a/go.mod
+++ b/go.mod
@@ -22,6 +22,7 @@ require (
 	github.com/mitchellh/mapstructure v1.1.2
 	github.com/onsi/gomega v1.7.0
 	github.com/openshift/api v3.9.1-0.20190927182313-d4a64ec2cbd8+incompatible
+	github.com/operator-framework/operator-lifecycle-manager v0.0.0-20191115003340-16619cd27fa5
 	github.com/operator-framework/operator-sdk v0.15.0
 	github.com/pkg/errors v0.8.1
 	github.com/radovskyb/watcher v1.0.6
diff --git a/go.sum b/go.sum
index 5a419be..a3675c8 100644
--- a/go.sum
+++ b/go.sum
@@ -103,6 +103,7 @@ github.com/bifurcation/mint v0.0.0-20180715133206-93c51c6ce115/go.mod h1:zVt7zX3
 github.com/bitly/go-hostpool v0.0.0-20171023180738-a3a6125de932/go.mod h1:NOuUCSz6Q9T7+igc/hlvDOUdtWKryOrtFyIVABv/p7k=
 github.com/bitly/go-simplejson v0.5.0/go.mod h1:cXHtHw4XUPsvGaxgjIAn8PhEWG9NfngEKAMDJEczWVA=
 github.com/blang/semver v3.5.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
+github.com/blang/semver v3.5.1+incompatible h1:cQNTCjp13qL8KC3Nbxr/y2Bqb63oX6wdnnjpJbkM4JQ=
 github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
 github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4=
 github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps=
@@ -588,7 +589,9 @@ github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFSt
 github.com/openzipkin/zipkin-go v0.1.6 h1:yXiysv1CSK7Q5yjGy1710zZGnsbMUIjluWBxtLXHPBo=
 github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw=
 github.com/operator-framework/api v0.0.0-20200120235816-80fd2f1a09c9/go.mod h1:S5IdlJvmKkF84K2tBvsrqJbI2FVy03P88R75snpRxJo=
+github.com/operator-framework/operator-lifecycle-manager v0.0.0-20191115003340-16619cd27fa5 h1:rjaihxY50c5C+kbQIK4s36R8zxByATYrgRbua4eiG6o=
 github.com/operator-framework/operator-lifecycle-manager v0.0.0-20191115003340-16619cd27fa5/go.mod h1:zL34MNy92LPutBH5gQK+gGhtgTUlZZX03I2G12vWHF4=
+github.com/operator-framework/operator-lifecycle-manager v3.11.0+incompatible h1:Po8C8RVLRWq7pNQ5pKonM9CXpC/osoBWbmsuf+HJnSI=
 github.com/operator-framework/operator-registry v1.5.1/go.mod h1:agrQlkWOo1q8U1SAaLSS2WQ+Z9vswNT2M2HFib9iuLY=
 github.com/operator-framework/operator-registry v1.5.3/go.mod h1:agrQlkWOo1q8U1SAaLSS2WQ+Z9vswNT2M2HFib9iuLY=
 github.com/operator-framework/operator-registry v1.5.7-0.20200121213444-d8e2ec52c19a/go.mod h1:ekexcV4O8YMxdQuPb+Xco7MHfVmRIq7Jvj5e6NU7dHI=
diff --git a/pkg/apis/addtoscheme_knative_eventing_v1alpha1.go b/pkg/apis/addtoscheme_knative_eventing.go
similarity index 100%
rename from pkg/apis/addtoscheme_knative_eventing_v1alpha1.go
rename to pkg/apis/addtoscheme_knative_eventing.go
diff --git a/pkg/apis/addtoscheme_knative_serving_v1alpha1.go b/pkg/apis/addtoscheme_knative_serving.go
similarity index 100%
copy from pkg/apis/addtoscheme_knative_serving_v1alpha1.go
copy to pkg/apis/addtoscheme_knative_serving.go
diff --git a/pkg/apis/addtoscheme_knative_serving_v1alpha1.go b/pkg/apis/addtoscheme_olm.go
similarity index 84%
rename from pkg/apis/addtoscheme_knative_serving_v1alpha1.go
rename to pkg/apis/addtoscheme_olm.go
index f270608..a69aa84 100644
--- a/pkg/apis/addtoscheme_knative_serving_v1alpha1.go
+++ b/pkg/apis/addtoscheme_olm.go
@@ -18,10 +18,10 @@ limitations under the License.
 package apis
 
 import (
-	serving "knative.dev/serving/pkg/apis/serving/v1"
+	olmv1alpha1 "github.com/operator-framework/operator-lifecycle-manager/pkg/api/apis/operators/v1alpha1"
 )
 
 func init() {
 	// Register the types with the Scheme so the components can map objects to GroupVersionKinds and back
-	AddToSchemes = append(AddToSchemes, serving.AddToScheme)
+	AddToSchemes = append(AddToSchemes, olmv1alpha1.AddToScheme)
 }
diff --git a/pkg/client/fastmapper.go b/pkg/client/fastmapper.go
index 346603d..82b33b8 100644
--- a/pkg/client/fastmapper.go
+++ b/pkg/client/fastmapper.go
@@ -38,6 +38,7 @@ var FastMapperAllowedAPIGroups = map[string]bool{
 	"camel.apache.org":          true,
 	"rbac.authorization.k8s.io": true,
 	"console.openshift.io":      true, // OpenShift console resources
+	"operators.coreos.com":      true, // Operator SDK OLM
 }
 
 // newFastDiscoveryRESTMapper comes from https://github.com/kubernetes-sigs/controller-runtime/pull/592.
diff --git a/pkg/cmd/install.go b/pkg/cmd/install.go
index f9a3481..8e9c669 100644
--- a/pkg/cmd/install.go
+++ b/pkg/cmd/install.go
@@ -23,6 +23,7 @@ import (
 	"strings"
 	"time"
 
+	"github.com/apache/camel-k/pkg/util/olm"
 	"github.com/apache/camel-k/pkg/util/registry"
 	"go.uber.org/multierr"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -93,6 +94,16 @@ func newCmdInstall(rootCmdOptions *RootCmdOptions) (*cobra.Command, *installCmdO
 	cmd.Flags().String("http-proxy-secret", "", "Configure the source of the secret holding HTTP proxy server details "+
 		"(HTTP_PROXY|HTTPS_PROXY|NO_PROXY)")
 
+	// olm
+	cmd.Flags().Bool("olm", true, "Try to install everything via OLM (Operator Lifecycle Manager) if available")
+	cmd.Flags().String("olm-operator-name", olm.DefaultOperatorName, "Name of the Camel K operator in the OLM source or marketplace")
+	cmd.Flags().String("olm-package", olm.DefaultPackage, "Name of the Camel K package in the OLM source or marketplace")
+	cmd.Flags().String("olm-channel", olm.DefaultChannel, "Name of the Camel K channel in the OLM source or marketplace")
+	cmd.Flags().String("olm-source", olm.DefaultSource, "Name of the OLM source providing the Camel K package (defaults to the standard Operator Hub source)")
+	cmd.Flags().String("olm-source-namespace", olm.DefaultSourceNamespace, "Namespace where the OLM source is available")
+	cmd.Flags().String("olm-starting-csv", olm.DefaultStartingCSV, "Allow to install a specific version from the operator source instead of latest available from the channel")
+	cmd.Flags().String("olm-global-namespace", olm.DefaultGlobalNamespace, "A namespace containing an OperatorGroup that defines global scope for the operator (used in combination with the --global flag)")
+
 	// maven settings
 	cmd.Flags().String("local-repository", "", "Location of the local maven repository")
 	cmd.Flags().String("maven-settings", "", "Configure the source of the maven settings (configmap|secret:name[/key])")
@@ -123,6 +134,7 @@ type installCmdOptions struct {
 	Global            bool     `mapstructure:"global"`
 	KanikoBuildCache  bool     `mapstructure:"kaniko-build-cache"`
 	Save              bool     `mapstructure:"save"`
+	Olm               bool    `mapstructure:"olm"`
 	ClusterType       string   `mapstructure:"cluster-type"`
 	OutputFormat      string   `mapstructure:"output"`
 	RuntimeVersion    string   `mapstructure:"runtime-version"`
@@ -140,6 +152,7 @@ type installCmdOptions struct {
 
 	registry     v1.IntegrationPlatformRegistrySpec
 	registryAuth registry.Auth
+	olmOptions   olm.Options
 }
 
 // nolint: gocyclo
@@ -149,13 +162,36 @@ func (o *installCmdOptions) install(cobraCmd *cobra.Command, _ []string) error {
 		collection = kubernetes.NewCollection()
 	}
 
-	if !o.SkipClusterSetup {
-		// Let's use a client provider during cluster installation, to eliminate the problem of CRD object caching
-		clientProvider := client.Provider{Get: o.NewCmdClient}
+	// Let's use a client provider during cluster installation, to eliminate the problem of CRD object caching
+	clientProvider := client.Provider{Get: o.NewCmdClient}
+
+	installViaOLM := false
+	if o.Olm {
+		var err error
+		var olmClient client.Client
+		if olmClient, err = clientProvider.Get(); err != nil {
+			return err
+		}
+		if installViaOLM, err = olm.IsAvailable(o.Context, olmClient); err != nil {
+			return errors.Wrap(err, "error while checking OLM availability. Run with '--olm=false' to skip this check")
+		}
 
+		if installViaOLM {
+			fmt.Fprintln(cobraCmd.OutOrStdout(), "OLM is available in the cluster");
+			if err = olm.Install(o.Context, olmClient, o.Namespace, o.Global, o.olmOptions, collection); err != nil {
+				return err
+			}
+		}
+
+		if err = install.WaitForAllCRDInstallation(o.Context, clientProvider, 90 * time.Second); err != nil {
+			return err
+		}
+	}
+
+	if !o.SkipClusterSetup && !installViaOLM {
 		err := install.SetupClusterWideResourcesOrCollect(o.Context, clientProvider, collection)
 		if err != nil && k8serrors.IsForbidden(err) {
-			fmt.Println("Current user is not authorized to create cluster-wide objects like custom resource definitions or cluster roles: ", err)
+			fmt.Fprintln(cobraCmd.OutOrStdout(), "Current user is not authorized to create cluster-wide objects like custom resource definitions or cluster roles: ", err)
 
 			meg := `please login as cluster-admin and execute "kamel install --cluster-setup" to install cluster-wide resources (one-time operation)`
 			return errors.New(meg)
@@ -166,7 +202,7 @@ func (o *installCmdOptions) install(cobraCmd *cobra.Command, _ []string) error {
 
 	if o.ClusterSetupOnly {
 		if collection == nil {
-			fmt.Println("Camel K cluster setup completed successfully")
+			fmt.Fprintln(cobraCmd.OutOrStdout(),"Camel K cluster setup completed successfully")
 		}
 	} else {
 		c, err := o.GetCmdClient()
@@ -176,7 +212,7 @@ func (o *installCmdOptions) install(cobraCmd *cobra.Command, _ []string) error {
 
 		namespace := o.Namespace
 
-		if !o.SkipOperatorSetup {
+		if !o.SkipOperatorSetup && !installViaOLM {
 			cfg := install.OperatorConfiguration{
 				CustomImage: o.OperatorImage,
 				Namespace:   namespace,
@@ -187,8 +223,8 @@ func (o *installCmdOptions) install(cobraCmd *cobra.Command, _ []string) error {
 			if err != nil {
 				return err
 			}
-		} else {
-			fmt.Println("Camel K operator installation skipped")
+		} else if o.SkipOperatorSetup {
+			fmt.Fprintln(cobraCmd.OutOrStdout(), "Camel K operator installation skipped")
 		}
 
 		generatedSecretName := ""
@@ -288,8 +324,9 @@ func (o *installCmdOptions) install(cobraCmd *cobra.Command, _ []string) error {
 		platform.Spec.Resources.Kits = o.Kits
 
 		// Do not create an integration platform in global mode as platforms are expected
-		// to be created in other namespaces
-		if !o.Global {
+		// to be created in other namespaces.
+		// In OLM mode, the operator is installed in an external namespace, so it's ok to install the platform locally.
+		if !o.Global || installViaOLM {
 			err = install.RuntimeObjectOrCollect(o.Context, c, namespace, collection, platform)
 			if err != nil {
 				return err
@@ -311,10 +348,14 @@ func (o *installCmdOptions) install(cobraCmd *cobra.Command, _ []string) error {
 				}
 			}
 
+			strategy := ""
+			if installViaOLM {
+				strategy = "via OLM subscription"
+			}
 			if o.Global {
-				fmt.Println("Camel K installed in namespace", namespace, "(global mode)")
+				fmt.Println("Camel K installed in namespace", namespace, strategy, "(global mode)")
 			} else {
-				fmt.Println("Camel K installed in namespace", namespace)
+				fmt.Println("Camel K installed in namespace", namespace, strategy)
 			}
 		}
 	}
@@ -389,6 +430,14 @@ func (o *installCmdOptions) decode(cmd *cobra.Command, _ []string) error {
 	o.registryAuth.Password = viper.GetString(path + ".registry-auth-password")
 	o.registryAuth.Server = viper.GetString(path + ".registry-auth-server")
 
+	o.olmOptions.OperatorName = viper.GetString(path + ".olm-operator-name")
+	o.olmOptions.Package = viper.GetString(path + ".olm-package")
+	o.olmOptions.Channel = viper.GetString(path + ".olm-channel")
+	o.olmOptions.Source = viper.GetString(path + ".olm-source")
+	o.olmOptions.SourceNamespace = viper.GetString(path + ".olm-source-namespace")
+	o.olmOptions.StartingCSV = viper.GetString(path + ".olm-starting-csv")
+	o.olmOptions.GlobalNamespace = viper.GetString(path + ".olm-global-namespace")
+
 	return nil
 }
 
diff --git a/pkg/util/olm/available.go b/pkg/util/olm/available.go
new file mode 100644
index 0000000..2d7636f
--- /dev/null
+++ b/pkg/util/olm/available.go
@@ -0,0 +1,59 @@
+/*
+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 olm
+
+import (
+	"context"
+
+	kubernetesutils "github.com/apache/camel-k/pkg/util/kubernetes"
+	olmv1alpha1 "github.com/operator-framework/operator-lifecycle-manager/pkg/api/apis/operators/v1alpha1"
+	k8serrors "k8s.io/apimachinery/pkg/api/errors"
+	"k8s.io/apimachinery/pkg/runtime/schema"
+	"k8s.io/client-go/kubernetes"
+)
+
+// IsAvailable returns true if we are connected to a cluster with OLM installed
+//
+// This method should not be called from the operator, as it might require permissions that are not available.
+func IsAvailable(ctx context.Context, c kubernetes.Interface) (bool, error) {
+	// check some Knative APIs
+	for _, api := range getOLMGroupVersions() {
+		if installed, err := isAvailable(c, api); err != nil {
+			return false, err
+		} else if installed {
+			return true, nil
+		}
+	}
+	return false, nil
+}
+
+func isAvailable(c kubernetes.Interface, api schema.GroupVersion) (bool, error) {
+	_, err := c.Discovery().ServerResourcesForGroupVersion(api.String())
+	if err != nil && (k8serrors.IsNotFound(err) || kubernetesutils.IsUnknownAPIError(err)) {
+		return false, nil
+	} else if err != nil {
+		return false, err
+	}
+	return true, nil
+}
+
+func getOLMGroupVersions() []schema.GroupVersion {
+	return []schema.GroupVersion{
+		olmv1alpha1.SchemeGroupVersion,
+	}
+}
diff --git a/pkg/util/olm/operator.go b/pkg/util/olm/operator.go
new file mode 100644
index 0000000..c5bda90
--- /dev/null
+++ b/pkg/util/olm/operator.go
@@ -0,0 +1,201 @@
+/*
+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 olm
+
+import (
+	"context"
+	"strings"
+
+	"github.com/apache/camel-k/pkg/client"
+	"github.com/apache/camel-k/pkg/util/kubernetes"
+	olmv1alpha1 "github.com/operator-framework/operator-lifecycle-manager/pkg/api/apis/operators/v1alpha1"
+	v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+	runtime "sigs.k8s.io/controller-runtime/pkg/client"
+)
+
+// The following properties can be overridden at build time via ldflags
+
+// DefaultOperatorName is the Camel K operator name in OLM
+var DefaultOperatorName = "camel-k-operator"
+
+// DefaultPackage is the Camel K package in OLM
+var DefaultPackage = "camel-k"
+
+// DefaultChannel is the distribution channel in Operator Hub
+var DefaultChannel = "alpha"
+
+// DefaultSource is the name of the operator source where the operator is published
+var DefaultSource = "community-operators"
+
+// DefaultSourceNamespace is the namespace of the operator source
+var DefaultSourceNamespace = "openshift-marketplace"
+
+// DefaultStartingCSV contains the specific version to install
+var DefaultStartingCSV = ""
+
+// DefaultGlobalNamespace indicates a namespace containing an OperatorGroup that enables the operator to watch all namespaces.
+// It will be used in global installation mode.
+var DefaultGlobalNamespace = "openshift-operators"
+
+// Options contains information about an operator in OLM
+type Options struct {
+	OperatorName        string
+	Package             string
+	Channel             string
+	Source              string
+	SourceNamespace     string
+	StartingCSV         string
+	GlobalNamespace     string
+}
+
+// IsOperatorInstalled tells if a OLM CSV or a Subscription is already installed in the namespace
+func IsOperatorInstalled(ctx context.Context, client client.Client, namespace string, global bool, options Options) (bool, error) {
+	options = fillDefaults(options)
+	// CSV is present in current namespace for both local and global installation modes
+	if csv, err := findCSV(ctx, client, namespace, options); err != nil {
+		return false, err
+	} else if csv != nil {
+		return true, nil
+	}
+	// A subscription may indicate an in-progress installation
+	if sub, err := findSubscription(ctx, client, namespace, global, options); err != nil {
+		return false, err
+	} else if sub != nil {
+		return true, nil
+	}
+
+	return false, nil
+}
+
+// Install creates a subscription for the OLM package
+func Install(ctx context.Context, client client.Client, namespace string, global bool, options Options, collection *kubernetes.Collection) error {
+	options = fillDefaults(options)
+	if installed, err := IsOperatorInstalled(ctx, client, namespace, global, options); err != nil {
+		return err
+	} else if installed {
+		// Already installed
+		return nil
+	}
+
+	targetNamespace := namespace
+	if global {
+		targetNamespace = options.GlobalNamespace
+	}
+
+	sub := olmv1alpha1.Subscription{
+		ObjectMeta: v1.ObjectMeta{
+			Name:      options.Package,
+			Namespace: targetNamespace,
+		},
+		Spec: &olmv1alpha1.SubscriptionSpec{
+			CatalogSource:          options.Source,
+			CatalogSourceNamespace: options.SourceNamespace,
+			Package:                options.Package,
+			Channel:                options.Channel,
+			StartingCSV:            options.StartingCSV,
+			InstallPlanApproval:    olmv1alpha1.ApprovalAutomatic,
+		},
+	}
+	if collection != nil {
+		collection.Add(&sub)
+		return nil
+	}
+	return client.Create(ctx, &sub)
+}
+
+// Uninstall removes CSV and subscription from the namespace
+func Uninstall(ctx context.Context, client client.Client, namespace string, global bool, options Options) error {
+	sub, err := findSubscription(ctx, client, namespace, global, options)
+	if err != nil {
+		return err
+	}
+	if sub != nil {
+		if err := client.Delete(ctx, sub); err != nil {
+			return err
+		}
+	}
+
+	csv, err := findCSV(ctx, client, namespace, options)
+	if err != nil {
+		return err
+	}
+	if csv != nil {
+		if err := client.Delete(ctx, csv); err != nil {
+			return err
+		}
+	}
+	return nil
+}
+
+func findSubscription(ctx context.Context, client client.Client, namespace string, global bool, options Options) (*olmv1alpha1.Subscription, error) {
+	subNamespace := namespace
+	if global {
+		// In case of global installation, global subscription must be removed
+		subNamespace = options.GlobalNamespace
+	}
+	subscriptionList := olmv1alpha1.SubscriptionList{}
+	if err := client.List(ctx, &subscriptionList, runtime.InNamespace(subNamespace)); err != nil {
+		return nil, err
+	}
+
+	for _, item := range subscriptionList.Items {
+		if item.Spec.Package == options.Package {
+			return &item, nil
+		}
+	}
+	return nil, nil
+}
+
+func findCSV(ctx context.Context, client client.Client, namespace string, options Options) (*olmv1alpha1.ClusterServiceVersion, error) {
+	csvList := olmv1alpha1.ClusterServiceVersionList{}
+	if err := client.List(ctx, &csvList, runtime.InNamespace(namespace)); err != nil {
+		return nil, err
+	}
+
+	for _, item := range csvList.Items {
+		if strings.HasPrefix(item.Name, options.OperatorName) {
+			return &item, nil
+		}
+	}
+	return nil, nil
+}
+
+func fillDefaults(o Options) Options {
+	if o.OperatorName == "" {
+		o.OperatorName = DefaultOperatorName
+	}
+	if o.Package == "" {
+		o.Package = DefaultPackage
+	}
+	if o.Channel == "" {
+		o.Channel = DefaultChannel
+	}
+	if o.Source == "" {
+		o.Source = DefaultSource
+	}
+	if o.SourceNamespace == "" {
+		o.SourceNamespace = DefaultSourceNamespace
+	}
+	if o.StartingCSV == "" {
+		o.StartingCSV = DefaultStartingCSV
+	}
+	if o.GlobalNamespace == "" {
+		o.GlobalNamespace = DefaultGlobalNamespace
+	}
+	return o
+}