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, ®istrySecret); err != nil {
+ if err := RuntimeObjectOrCollect(ctx, c, namespace, collection, force, ®istrySecret); err != nil {
return "", err
}
return registrySecretName, nil