Fix #1286: overwrite resources when --force option is passed to kamel install
diff --git a/pkg/cmd/install.go b/pkg/cmd/install.go
index 8b973b8..b0441dc 100644
--- a/pkg/cmd/install.go
+++ b/pkg/cmd/install.go
@@ -60,6 +60,9 @@
 				return err
 			}
 			if err := options.install(cmd, args); err != nil {
+				if k8serrors.IsAlreadyExists(err) {
+					return errors.Wrap(err, "Camel K seems already installed (use the --force option to overwrite existing resources)")
+				}
 				return err
 			}
 			return nil
@@ -73,6 +76,7 @@
 	cmd.Flags().Bool("skip-cluster-setup", false, "Skip the cluster-setup phase")
 	cmd.Flags().Bool("example", false, "Install example integration")
 	cmd.Flags().Bool("global", false, "Configure the operator to watch all namespaces. No integration platform is created.")
+	cmd.Flags().Bool("force", false, "Force replacement of configuration resources when already present.")
 
 	cmd.Flags().StringP("output", "o", "", "Output format. One of: json|yaml")
 	cmd.Flags().String("organization", "", "A organization on the Docker registry that can be used to publish images")
@@ -137,6 +141,7 @@
 	Global            bool     `mapstructure:"global"`
 	KanikoBuildCache  bool     `mapstructure:"kaniko-build-cache"`
 	Save              bool     `mapstructure:"save"`
+	Force             bool     `mapstructure:"force"`
 	Olm               bool     `mapstructure:"olm"`
 	ClusterType       string   `mapstructure:"cluster-type"`
 	OutputFormat      string   `mapstructure:"output"`
@@ -238,7 +243,7 @@
 				Global:      o.Global,
 				ClusterType: o.ClusterType,
 			}
-			err = install.OperatorOrCollect(o.Context, c, cfg, collection)
+			err = install.OperatorOrCollect(o.Context, c, cfg, collection, o.Force)
 			if err != nil {
 				return err
 			}
@@ -250,7 +255,7 @@
 		if o.registryAuth.IsSet() {
 			regData := o.registryAuth
 			regData.Registry = o.registry.Address
-			generatedSecretName, err = install.RegistrySecretOrCollect(o.Context, c, namespace, regData, collection)
+			generatedSecretName, err = install.RegistrySecretOrCollect(o.Context, c, namespace, regData, collection, o.Force)
 			if err != nil {
 				return err
 			}
@@ -346,14 +351,14 @@
 		// 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)
+			err = install.RuntimeObjectOrCollect(o.Context, c, namespace, collection, o.Force, platform)
 			if err != nil {
 				return err
 			}
 		}
 
 		if o.ExampleSetup {
-			err = install.ExampleOrCollect(o.Context, c, namespace, collection)
+			err = install.ExampleOrCollect(o.Context, c, namespace, collection, o.Force)
 			if err != nil {
 				return err
 			}
diff --git a/pkg/controller/integrationplatform/create.go b/pkg/controller/integrationplatform/create.go
index 7d387a9..e8efeba 100644
--- a/pkg/controller/integrationplatform/create.go
+++ b/pkg/controller/integrationplatform/create.go
@@ -49,7 +49,7 @@
 	for _, k := range deploy.Resources("/") {
 		if strings.HasPrefix(k, "camel-catalog-") {
 			action.L.Infof("Installing camel catalog: %s", k)
-			err := install.Resources(ctx, action.client, platform.Namespace, install.IdentityResourceCustomizer, k)
+			err := install.Resources(ctx, action.client, platform.Namespace, true, install.IdentityResourceCustomizer, k)
 			if err != nil {
 				return nil, err
 			}
@@ -73,7 +73,7 @@
 
 		if len(res) > 0 {
 			action.L.Info("Installing custom platform resources")
-			err := install.Resources(ctx, action.client, platform.Namespace, install.IdentityResourceCustomizer, res...)
+			err := install.Resources(ctx, action.client, platform.Namespace, true, install.IdentityResourceCustomizer, res...)
 			if err != nil {
 				return nil, err
 			}
diff --git a/pkg/install/builder.go b/pkg/install/builder.go
index cd906c0..d9f0d17 100644
--- a/pkg/install/builder.go
+++ b/pkg/install/builder.go
@@ -43,7 +43,7 @@
 }
 
 func installBuilderServiceAccountRolesOpenshift(ctx context.Context, c client.Client, namespace string) error {
-	return ResourcesOrCollect(ctx, c, namespace, nil, IdentityResourceCustomizer,
+	return ResourcesOrCollect(ctx, c, namespace, nil, true, IdentityResourceCustomizer,
 		"builder-service-account.yaml",
 		"builder-role-openshift.yaml",
 		"builder-role-binding.yaml",
@@ -51,7 +51,7 @@
 }
 
 func installBuilderServiceAccountRolesKubernetes(ctx context.Context, c client.Client, namespace string) error {
-	return ResourcesOrCollect(ctx, c, namespace, nil, IdentityResourceCustomizer,
+	return ResourcesOrCollect(ctx, c, namespace, nil, true, IdentityResourceCustomizer,
 		"builder-service-account.yaml",
 		"builder-role-kubernetes.yaml",
 		"builder-role-binding.yaml",
diff --git a/pkg/install/common.go b/pkg/install/common.go
index 79414c2..e1328a1 100644
--- a/pkg/install/common.go
+++ b/pkg/install/common.go
@@ -42,14 +42,14 @@
 }
 
 // Resources installs named resources from the project resource directory
-func Resources(ctx context.Context, c client.Client, namespace string, customizer ResourceCustomizer, names ...string) error {
-	return ResourcesOrCollect(ctx, c, namespace, nil, customizer, names...)
+func Resources(ctx context.Context, c client.Client, namespace string, force bool, customizer ResourceCustomizer, names ...string) error {
+	return ResourcesOrCollect(ctx, c, namespace, nil, force, customizer, names...)
 }
 
 // ResourcesOrCollect --
-func ResourcesOrCollect(ctx context.Context, c client.Client, namespace string, collection *kubernetes.Collection, customizer ResourceCustomizer, names ...string) error {
+func ResourcesOrCollect(ctx context.Context, c client.Client, namespace string, collection *kubernetes.Collection, force bool, customizer ResourceCustomizer, names ...string) error {
 	for _, name := range names {
-		if err := ResourceOrCollect(ctx, c, namespace, collection, customizer, name); err != nil {
+		if err := ResourceOrCollect(ctx, c, namespace, collection, force, customizer, name); err != nil {
 			return err
 		}
 	}
@@ -57,27 +57,27 @@
 }
 
 // Resource installs a single named resource from the project resource directory
-func Resource(ctx context.Context, c client.Client, namespace string, customizer ResourceCustomizer, name string) error {
-	return ResourceOrCollect(ctx, c, namespace, nil, customizer, name)
+func Resource(ctx context.Context, c client.Client, namespace string, force bool, customizer ResourceCustomizer, name string) error {
+	return ResourceOrCollect(ctx, c, namespace, nil, force, customizer, name)
 }
 
 // ResourceOrCollect --
-func ResourceOrCollect(ctx context.Context, c client.Client, namespace string, collection *kubernetes.Collection, customizer ResourceCustomizer, name string) error {
+func ResourceOrCollect(ctx context.Context, c client.Client, namespace string, collection *kubernetes.Collection, force bool, customizer ResourceCustomizer, name string) error {
 	obj, err := kubernetes.LoadResourceFromYaml(c.GetScheme(), deploy.ResourceAsString(name))
 	if err != nil {
 		return err
 	}
 
-	return RuntimeObjectOrCollect(ctx, c, namespace, collection, customizer(obj))
+	return RuntimeObjectOrCollect(ctx, c, namespace, collection, force, customizer(obj))
 }
 
 // RuntimeObject installs a single runtime object
-func RuntimeObject(ctx context.Context, c client.Client, namespace string, obj runtime.Object) error {
-	return RuntimeObjectOrCollect(ctx, c, namespace, nil, obj)
+func RuntimeObject(ctx context.Context, c client.Client, namespace string, force bool, obj runtime.Object) error {
+	return RuntimeObjectOrCollect(ctx, c, namespace, nil, force, obj)
 }
 
 // RuntimeObjectOrCollect --
-func RuntimeObjectOrCollect(ctx context.Context, c client.Client, namespace string, collection *kubernetes.Collection, obj runtime.Object) error {
+func RuntimeObjectOrCollect(ctx context.Context, c client.Client, namespace string, collection *kubernetes.Collection, force bool, obj runtime.Object) error {
 	if collection != nil {
 		// Adding to the collection before setting the namespace
 		collection.Add(obj)
@@ -88,31 +88,29 @@
 		metaObject.SetNamespace(namespace)
 	}
 
-	err := c.Create(ctx, obj)
-	if err != nil && errors.IsAlreadyExists(err) {
-		// Don't recreate Service object
-		if obj.GetObjectKind().GroupVersionKind().Kind == "Service" {
-			return nil
+	if obj.GetObjectKind().GroupVersionKind().Kind == "PersistentVolumeClaim" {
+		if err := c.Create(ctx, obj); err != nil && !errors.IsAlreadyExists(err) {
+			return err
 		}
-		// Don't recreate integration kits, platforms, etc
-		if obj.GetObjectKind().GroupVersionKind().Kind == v1.IntegrationKitKind {
-			return nil
-		}
-		if obj.GetObjectKind().GroupVersionKind().Kind == v1.IntegrationPlatformKind {
-			return nil
-		}
-		if obj.GetObjectKind().GroupVersionKind().Kind == v1.CamelCatalogKind {
-			return nil
-		}
-		if obj.GetObjectKind().GroupVersionKind().Kind == v1.BuildKind {
-			return nil
-		}
-		if obj.GetObjectKind().GroupVersionKind().Kind == "PersistentVolumeClaim" {
-			return nil
-		}
-		return c.Update(ctx, obj)
 	}
-	return err
+
+	if force {
+		if err := kubernetes.ReplaceResource(ctx, c, obj); err != nil {
+			return err
+		}
+		// For some resources, also reset the status
+		if obj.GetObjectKind().GroupVersionKind().Kind == v1.IntegrationKitKind ||
+			obj.GetObjectKind().GroupVersionKind().Kind == v1.BuildKind ||
+			obj.GetObjectKind().GroupVersionKind().Kind == v1.IntegrationPlatformKind {
+			if err := c.Status().Update(ctx, obj); err != nil {
+				return err
+			}
+		}
+		return nil
+	}
+
+	// Just try to create them
+	return c.Create(ctx, obj)
 }
 
 func isOpenShift(c kube.Interface, clusterType string) (bool, error) {
diff --git a/pkg/install/operator.go b/pkg/install/operator.go
index 02a01ca..e61f13f 100644
--- a/pkg/install/operator.go
+++ b/pkg/install/operator.go
@@ -45,12 +45,12 @@
 }
 
 // Operator installs the operator resources in the given namespace
-func Operator(ctx context.Context, c client.Client, cfg OperatorConfiguration) error {
-	return OperatorOrCollect(ctx, c, cfg, nil)
+func Operator(ctx context.Context, c client.Client, cfg OperatorConfiguration, force bool) error {
+	return OperatorOrCollect(ctx, c, cfg, nil, force)
 }
 
 // OperatorOrCollect installs the operator resources or adds them to the collector if present
-func OperatorOrCollect(ctx context.Context, c client.Client, cfg OperatorConfiguration, collection *kubernetes.Collection) error {
+func OperatorOrCollect(ctx context.Context, c client.Client, cfg OperatorConfiguration, collection *kubernetes.Collection, force bool) error {
 	customizer := func(o runtime.Object) runtime.Object {
 		if cfg.CustomImage != "" {
 			if d, ok := o.(*appsv1.Deployment); ok {
@@ -108,11 +108,11 @@
 		return err
 	}
 	if isOpenshift {
-		if err := installOpenshift(ctx, c, cfg.Namespace, customizer, collection); err != nil {
+		if err := installOpenshift(ctx, c, cfg.Namespace, customizer, collection, force); err != nil {
 			return err
 		}
 	} else {
-		if err := installKubernetes(ctx, c, cfg.Namespace, customizer, collection); err != nil {
+		if err := installKubernetes(ctx, c, cfg.Namespace, customizer, collection, force); err != nil {
 			return err
 		}
 	}
@@ -122,13 +122,13 @@
 		return err
 	}
 	if isKnative {
-		return installKnative(ctx, c, cfg.Namespace, customizer, collection)
+		return installKnative(ctx, c, cfg.Namespace, customizer, collection, force)
 	}
 	return nil
 }
 
-func installOpenshift(ctx context.Context, c client.Client, namespace string, customizer ResourceCustomizer, collection *kubernetes.Collection) error {
-	return ResourcesOrCollect(ctx, c, namespace, collection, customizer,
+func installOpenshift(ctx context.Context, c client.Client, namespace string, customizer ResourceCustomizer, collection *kubernetes.Collection, force bool) error {
+	return ResourcesOrCollect(ctx, c, namespace, collection, force, customizer,
 		"operator-service-account.yaml",
 		"operator-role-openshift.yaml",
 		"operator-role-binding.yaml",
@@ -136,8 +136,8 @@
 	)
 }
 
-func installKubernetes(ctx context.Context, c client.Client, namespace string, customizer ResourceCustomizer, collection *kubernetes.Collection) error {
-	return ResourcesOrCollect(ctx, c, namespace, collection, customizer,
+func installKubernetes(ctx context.Context, c client.Client, namespace string, customizer ResourceCustomizer, collection *kubernetes.Collection, force bool) error {
+	return ResourcesOrCollect(ctx, c, namespace, collection, force, customizer,
 		"operator-service-account.yaml",
 		"operator-role-kubernetes.yaml",
 		"operator-role-binding.yaml",
@@ -145,8 +145,8 @@
 	)
 }
 
-func installKnative(ctx context.Context, c client.Client, namespace string, customizer ResourceCustomizer, collection *kubernetes.Collection) error {
-	return ResourcesOrCollect(ctx, c, namespace, collection, customizer,
+func installKnative(ctx context.Context, c client.Client, namespace string, customizer ResourceCustomizer, collection *kubernetes.Collection, force bool) error {
+	return ResourcesOrCollect(ctx, c, namespace, collection, force, customizer,
 		"operator-role-knative.yaml",
 		"operator-role-binding-knative.yaml",
 	)
@@ -195,13 +195,13 @@
 }
 
 // Example --
-func Example(ctx context.Context, c client.Client, namespace string) error {
-	return ExampleOrCollect(ctx, c, namespace, nil)
+func Example(ctx context.Context, c client.Client, namespace string, force bool) error {
+	return ExampleOrCollect(ctx, c, namespace, nil, force)
 }
 
 // ExampleOrCollect --
-func ExampleOrCollect(ctx context.Context, c client.Client, namespace string, collection *kubernetes.Collection) error {
-	return ResourcesOrCollect(ctx, c, namespace, collection, IdentityResourceCustomizer,
+func ExampleOrCollect(ctx context.Context, c client.Client, namespace string, collection *kubernetes.Collection, force bool) error {
+	return ResourcesOrCollect(ctx, c, namespace, collection, force, IdentityResourceCustomizer,
 		"cr-example.yaml",
 	)
 }
diff --git a/pkg/install/secret.go b/pkg/install/secret.go
index 026b520..70a7536 100644
--- a/pkg/install/secret.go
+++ b/pkg/install/secret.go
@@ -30,7 +30,7 @@
 const registrySecretName = "camel-k-registry-secret"
 
 // RegistrySecretOrCollect generates a secret from auth settings and creates it on the cluster (or appends it to the collection)
-func RegistrySecretOrCollect(ctx context.Context, c client.Client, namespace string, auth registry.Auth, collection *kubernetes.Collection) (string, error) {
+func RegistrySecretOrCollect(ctx context.Context, c client.Client, namespace string, auth registry.Auth, collection *kubernetes.Collection, force bool) (string, error) {
 	secretData, err := auth.GenerateDockerConfig()
 	if err != nil {
 		return "", err
@@ -51,7 +51,7 @@
 		},
 	}
 
-	if err := RuntimeObjectOrCollect(ctx, c, namespace, collection, &registrySecret); err != nil {
+	if err := RuntimeObjectOrCollect(ctx, c, namespace, collection, force, &registrySecret); err != nil {
 		return "", err
 	}
 	return registrySecretName, nil