diff --git a/pkg/cmd/rebuild.go b/pkg/cmd/rebuild.go index 35f59677c6..9cd7983b4b 100644 --- a/pkg/cmd/rebuild.go +++ b/pkg/cmd/rebuild.go @@ -22,11 +22,15 @@ import ( "github.com/pkg/errors" "github.com/spf13/cobra" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/apimachinery/pkg/selection" k8sclient "sigs.k8s.io/controller-runtime/pkg/client" v1 "github.com/apache/camel-k/v2/pkg/apis/camel/v1" + "github.com/apache/camel-k/v2/pkg/apis/camel/v1alpha1" "github.com/apache/camel-k/v2/pkg/client" + "github.com/apache/camel-k/v2/pkg/util/kubernetes" ) func newCmdRebuild(rootCmdOptions *RootCmdOptions) (*cobra.Command, *rebuildCmdOptions) { @@ -68,11 +72,80 @@ func (o *rebuildCmdOptions) validate(args []string) error { } func (o *rebuildCmdOptions) run(cmd *cobra.Command, args []string) error { + errKlbs := o.rebuildKameletBindingType(cmd, args) + errIts := o.rebuildIntegrationType(cmd, args) + + if errIts != nil && errKlbs != nil { + return errors.Wrap(errIts, errKlbs.Error()) + } + + return nil +} + +func (o *rebuildCmdOptions) rebuildKameletBindingType(cmd *cobra.Command, args []string) error { c, err := o.GetCmdClient() if err != nil { return err } + var kameletBindings []v1alpha1.KameletBinding + if o.RebuildAll { + if kameletBindings, err = o.listAllKameletBindings(c); err != nil { + return err + } + } else if len(args) > 0 { + if kameletBindings, err = o.getKameletBindings(c, args); err != nil { + return err + } + } + + if err = o.rebuildKameletBindings(c, kameletBindings); err != nil { + return err + } + + fmt.Fprintln(cmd.OutOrStdout(), len(kameletBindings), "kamelet bindings have been rebuilt") + return nil +} + +func (o *rebuildCmdOptions) listAllKameletBindings(c client.Client) ([]v1alpha1.KameletBinding, error) { + list := v1alpha1.NewKameletBindingList() + if err := c.List(o.Context, &list, k8sclient.InNamespace(o.Namespace)); err != nil { + return nil, errors.Wrap(err, fmt.Sprintf("could not retrieve kamelet bindings from namespace %s", o.Namespace)) + } + return list.Items, nil +} +func (o *rebuildCmdOptions) getKameletBindings(c client.Client, names []string) ([]v1alpha1.KameletBinding, error) { + klbs := make([]v1alpha1.KameletBinding, 0, len(names)) + for _, n := range names { + klb := v1alpha1.NewKameletBinding(o.Namespace, n) + key := k8sclient.ObjectKey{ + Name: n, + Namespace: o.Namespace, + } + if err := c.Get(o.Context, key, &klb); err != nil { + return nil, errors.Wrap(err, fmt.Sprintf("could not find kamelet binding %s in namespace %s", klb.Name, o.Namespace)) + } + klbs = append(klbs, klb) + } + return klbs, nil +} + +func (o *rebuildCmdOptions) rebuildKameletBindings(c k8sclient.StatusClient, kameletbindings []v1alpha1.KameletBinding) error { + for _, i := range kameletbindings { + klb := i + klb.Status = v1alpha1.KameletBindingStatus{} + if err := c.Status().Update(o.Context, &klb); err != nil { + return errors.Wrap(err, fmt.Sprintf("could not rebuild kamelet binding %s in namespace %s", klb.Name, o.Namespace)) + } + } + return nil +} + +func (o *rebuildCmdOptions) rebuildIntegrationType(cmd *cobra.Command, args []string) error { + c, err := o.GetCmdClient() + if err != nil { + return err + } var integrations []v1.Integration if o.RebuildAll { if integrations, err = o.listAllIntegrations(c); err != nil { @@ -94,7 +167,19 @@ func (o *rebuildCmdOptions) run(cmd *cobra.Command, args []string) error { func (o *rebuildCmdOptions) listAllIntegrations(c client.Client) ([]v1.Integration, error) { list := v1.NewIntegrationList() - if err := c.List(o.Context, &list, k8sclient.InNamespace(o.Namespace)); err != nil { + // Integrations controlled by KameletBindings are not included + excludeItsFromKlbs, err := labels.NewRequirement(kubernetes.CamelCreatorLabelKind, selection.NotEquals, []string{ + "KameletBinding", + }) + if err != nil { + return list.Items, err + } + if err := c.List(o.Context, &list, + k8sclient.InNamespace(o.Namespace), + k8sclient.MatchingLabelsSelector{ + Selector: labels.NewSelector().Add(*excludeItsFromKlbs), + }, + ); err != nil { return nil, errors.Wrap(err, fmt.Sprintf("could not retrieve integrations from namespace %s", o.Namespace)) } return list.Items, nil @@ -111,7 +196,10 @@ func (o *rebuildCmdOptions) getIntegrations(c client.Client, names []string) ([] if err := c.Get(o.Context, key, &it); err != nil { return nil, errors.Wrap(err, fmt.Sprintf("could not find integration %s in namespace %s", it.Name, o.Namespace)) } - ints = append(ints, it) + // Integrations controlled by KameletBindings are not included + if it.Labels[kubernetes.CamelCreatorLabelKind] != "KameletBinding" { + ints = append(ints, it) + } } return ints, nil } diff --git a/pkg/cmd/rebuild_test.go b/pkg/cmd/rebuild_test.go index 021c1cf6ba..936a5d2add 100644 --- a/pkg/cmd/rebuild_test.go +++ b/pkg/cmd/rebuild_test.go @@ -20,18 +20,22 @@ package cmd import ( "testing" + "github.com/apache/camel-k/v2/pkg/util/kubernetes" "github.com/apache/camel-k/v2/pkg/util/test" "github.com/spf13/cobra" "github.com/stretchr/testify/assert" + "k8s.io/apimachinery/pkg/runtime" ) const cmdRebuild = "rebuild" // nolint: unparam -func initializeRebuildCmdOptions(t *testing.T) (*rebuildCmdOptions, *cobra.Command, RootCmdOptions) { +func initializeRebuildOptions(t *testing.T, initObjs ...runtime.Object) (*rebuildCmdOptions, *cobra.Command, RootCmdOptions) { t.Helper() - - options, rootCmd := kamelTestPreAddCommandInit() + fakeClient, err := test.NewFakeClient(initObjs...) + assert.Nil(t, err) + options, rootCmd := kamelTestPreAddCommandInitWithClient(fakeClient) + options.Namespace = "default" rebuildCmdOptions := addTestRebuildCmd(*options, rootCmd) kamelTestPostAddCommandInit(t, rootCmd) @@ -39,28 +43,82 @@ func initializeRebuildCmdOptions(t *testing.T) (*rebuildCmdOptions, *cobra.Comma } func addTestRebuildCmd(options RootCmdOptions, rootCmd *cobra.Command) *rebuildCmdOptions { - // add a testing version of rebuild Command rebuildCmd, rebuildOptions := newCmdRebuild(&options) - rebuildCmd.RunE = func(c *cobra.Command, args []string) error { - return nil - } - rebuildCmd.PostRunE = func(c *cobra.Command, args []string) error { - return nil - } rebuildCmd.Args = test.ArbitraryArgs rootCmd.AddCommand(rebuildCmd) return rebuildOptions } func TestRebuildNonExistingFlag(t *testing.T) { - _, rootCmd, _ := initializeRebuildCmdOptions(t) + _, rootCmd, _ := initializeRebuildOptions(t) _, err := test.ExecuteCommand(rootCmd, cmdRebuild, "--nonExistingFlag") assert.NotNil(t, err) } func TestRebuildAllFlag(t *testing.T) { - rebuildCmdOptions, rootCmd, _ := initializeRebuildCmdOptions(t) + rebuildCmdOptions, rootCmd, _ := initializeRebuildOptions(t) _, err := test.ExecuteCommand(rootCmd, cmdRebuild, "--all") assert.Nil(t, err) assert.Equal(t, true, rebuildCmdOptions.RebuildAll) } + +func TestRebuildAllKameletBindingsAndIntegrations(t *testing.T) { + defaultIntegration := nominalIntegration("my-it-test") + defaultKB := nominalKameletBinding("my-kb-test") + itGeneratedByKlb := nominalIntegration("my-kb-test") + itGeneratedByKlb.Labels = map[string]string{ + kubernetes.CamelCreatorLabelKind: "KameletBinding", + } + + _, rebuildCmd, _ := initializeRebuildOptions(t, &defaultIntegration, &defaultKB, &itGeneratedByKlb) + output, err := test.ExecuteCommand(rebuildCmd, cmdRebuild, "--all") + assert.Nil(t, err) + assert.Contains(t, output, "1 kamelet bindings have been rebuilt") + assert.Contains(t, output, "1 integrations have been rebuilt") +} + +func TestRebuildNone(t *testing.T) { + defaultIntegration := nominalIntegration("my-it-test") + defaultKB := nominalKameletBinding("my-kb-test") + itGeneratedByKlb := nominalIntegration("my-kb-test") + itGeneratedByKlb.Labels = map[string]string{ + kubernetes.CamelCreatorLabelKind: "KameletBinding", + } + + _, rebuildCmd, _ := initializeRebuildOptions(t, &defaultIntegration, &defaultKB, &itGeneratedByKlb) + output, err := test.ExecuteCommand(rebuildCmd, cmdRebuild, "my-missing") + assert.NotNil(t, err) + assert.NotContains(t, output, "have been rebuilt") + assert.Contains(t, output, "could not find kamelet binding my-missing in namespace default") + assert.Contains(t, output, "could not find integration my-missing in namespace default") +} + +func TestRebuildKameletBindingOnly(t *testing.T) { + defaultIntegration := nominalIntegration("my-it-test") + defaultKB := nominalKameletBinding("my-kb-test") + itGeneratedByKlb := nominalIntegration("my-kb-test") + itGeneratedByKlb.Labels = map[string]string{ + kubernetes.CamelCreatorLabelKind: "KameletBinding", + } + + _, rebuildCmd, _ := initializeRebuildOptions(t, &defaultIntegration, &defaultKB, &itGeneratedByKlb) + output, err := test.ExecuteCommand(rebuildCmd, cmdRebuild, "my-kb-test") + assert.Nil(t, err) + assert.Contains(t, output, "1 kamelet bindings have been rebuilt") + assert.NotContains(t, output, "1 integrations have been rebuilt") +} + +func TestRebuildIntegrationOnly(t *testing.T) { + defaultIntegration := nominalIntegration("my-it-test") + defaultKB := nominalKameletBinding("my-kb-test") + itGeneratedByKlb := nominalIntegration("my-kb-test") + itGeneratedByKlb.Labels = map[string]string{ + kubernetes.CamelCreatorLabelKind: "KameletBinding", + } + + _, rebuildCmd, _ := initializeRebuildOptions(t, &defaultIntegration, &defaultKB, &itGeneratedByKlb) + output, err := test.ExecuteCommand(rebuildCmd, cmdRebuild, "my-it-test") + assert.Nil(t, err) + assert.NotContains(t, output, "1 kamelet bindings have been rebuilt") + assert.Contains(t, output, "1 integrations have been rebuilt") +}