Skip to content

Commit

Permalink
Fix apache#1286: overwrite resources when --force option is passed to…
Browse files Browse the repository at this point in the history
… kamel install
  • Loading branch information
nicolaferraro committed Feb 21, 2020
1 parent 9a7c4f7 commit 5492589
Show file tree
Hide file tree
Showing 6 changed files with 61 additions and 58 deletions.
13 changes: 9 additions & 4 deletions pkg/cmd/install.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,9 @@ func newCmdInstall(rootCmdOptions *RootCmdOptions) (*cobra.Command, *installCmdO
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
Expand All @@ -73,6 +76,7 @@ func newCmdInstall(rootCmdOptions *RootCmdOptions) (*cobra.Command, *installCmdO
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")
Expand Down Expand Up @@ -137,6 +141,7 @@ type installCmdOptions struct {
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"`
Expand Down Expand Up @@ -238,7 +243,7 @@ func (o *installCmdOptions) install(cobraCmd *cobra.Command, _ []string) error {
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
}
Expand All @@ -250,7 +255,7 @@ func (o *installCmdOptions) install(cobraCmd *cobra.Command, _ []string) error {
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
}
Expand Down Expand Up @@ -346,14 +351,14 @@ func (o *installCmdOptions) install(cobraCmd *cobra.Command, _ []string) error {
// 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
}
Expand Down
4 changes: 2 additions & 2 deletions pkg/controller/integrationplatform/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ func (action *createAction) Handle(ctx context.Context, platform *v1.Integration
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
}
Expand All @@ -73,7 +73,7 @@ func (action *createAction) Handle(ctx context.Context, platform *v1.Integration

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
}
Expand Down
4 changes: 2 additions & 2 deletions pkg/install/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,15 +43,15 @@ func BuilderServiceAccountRoles(ctx context.Context, c client.Client, namespace
}

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",
)
}

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",
Expand Down
62 changes: 30 additions & 32 deletions pkg/install/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,42 +42,42 @@ var IdentityResourceCustomizer = func(object runtime.Object) runtime.Object {
}

// 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
}
}
return nil
}

// 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)
Expand All @@ -88,31 +88,29 @@ func RuntimeObjectOrCollect(ctx context.Context, c client.Client, namespace stri
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
}
// 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 == "PersistentVolumeClaim" {
if err := c.Create(ctx, obj); err != nil && !errors.IsAlreadyExists(err) {
return err
}
if obj.GetObjectKind().GroupVersionKind().Kind == v1.BuildKind {
return nil
}

if force {
if err := kubernetes.ReplaceResource(ctx, c, obj); err != nil {
return err
}
if obj.GetObjectKind().GroupVersionKind().Kind == "PersistentVolumeClaim" {
return nil
// 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 c.Update(ctx, obj)
return nil
}
return err

// Just try to create them
return c.Create(ctx, obj)
}

func isOpenShift(c kube.Interface, clusterType string) (bool, error) {
Expand Down
32 changes: 16 additions & 16 deletions pkg/install/operator.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,12 +45,12 @@ type OperatorConfiguration struct {
}

// 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 {
Expand Down Expand Up @@ -108,11 +108,11 @@ func OperatorOrCollect(ctx context.Context, c client.Client, cfg OperatorConfigu
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
}
}
Expand All @@ -122,31 +122,31 @@ func OperatorOrCollect(ctx context.Context, c client.Client, cfg OperatorConfigu
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",
"operator-deployment.yaml",
)
}

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",
"operator-deployment.yaml",
)
}

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",
)
Expand Down Expand Up @@ -195,13 +195,13 @@ func PlatformOrCollect(ctx context.Context, c client.Client, clusterType string,
}

// 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",
)
}
4 changes: 2 additions & 2 deletions pkg/install/secret.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ import (
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
Expand All @@ -51,7 +51,7 @@ func RegistrySecretOrCollect(ctx context.Context, c client.Client, namespace str
},
}

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
Expand Down

0 comments on commit 5492589

Please sign in to comment.