This is an automated email from the ASF dual-hosted git repository. pcongiusti pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/camel-k.git
The following commit(s) were added to refs/heads/main by this push: new 67e017ac7 chore(api): remove IntegrationProfile deprecation notice 67e017ac7 is described below commit 67e017ac754284856b3ed5c7a4a08e17593364a0 Author: Pasquale Congiusti <pasquale.congiu...@gmail.com> AuthorDate: Mon Mar 17 18:00:58 2025 +0100 chore(api): remove IntegrationProfile deprecation notice Refactoring also to make this CR static as it makes no sense to run any reconciliation over the profile. Closes #6091 --- docs/modules/ROOT/partials/apis/camel-k-crds.adoc | 3 +- e2e/advanced/integration_profile_test.go | 13 +- e2e/support/test_support.go | 10 - helm/camel-k/crds/camel-k-crds.yaml | 3 +- pkg/apis/camel/v1/integrationprofile_types.go | 4 +- .../camel/v1/integrationprofile_types_support.go | 99 ---------- pkg/controller/add_integrationprofile.go | 26 --- .../integration/integration_controller.go | 49 ----- pkg/controller/integration/kits.go | 6 +- pkg/controller/integrationprofile/action.go | 54 ----- pkg/controller/integrationprofile/initialize.go | 64 ------ .../integrationprofile_controller.go | 217 --------------------- pkg/controller/integrationprofile/log.go | 23 --- pkg/controller/integrationprofile/monitor.go | 47 ----- pkg/event/manager.go | 17 -- pkg/platform/profile.go | 83 +------- pkg/platform/profile_test.go | 203 ------------------- .../camel.apache.org_integrationprofiles.yaml | 3 +- pkg/trait/camel.go | 4 +- pkg/trait/quarkus.go | 2 +- pkg/trait/trait.go | 2 +- pkg/trait/trait_configure.go | 2 +- pkg/trait/util.go | 23 ++- pkg/trait/util_test.go | 38 +++- 24 files changed, 71 insertions(+), 924 deletions(-) diff --git a/docs/modules/ROOT/partials/apis/camel-k-crds.adoc b/docs/modules/ROOT/partials/apis/camel-k-crds.adoc index ebfd2c584..4e3d99a41 100644 --- a/docs/modules/ROOT/partials/apis/camel-k-crds.adoc +++ b/docs/modules/ROOT/partials/apis/camel-k-crds.adoc @@ -226,7 +226,6 @@ Refer to the Kubernetes API documentation for the fields of the `metadata` field IntegrationProfile is the resource used to apply user defined settings to the Camel K operator behavior. It defines the behavior of all Custom Resources (`IntegrationKit`, `Integration`, `Kamelet`) in the given namespace. -Deprecated: may be removed in future releases. Make use of IntegrationPlatform instead. [cols="2,2a",options="header"] |=== @@ -260,7 +259,7 @@ Refer to the Kubernetes API documentation for the fields of the `metadata` field | - +Deprecated: no longer in use. |=== diff --git a/e2e/advanced/integration_profile_test.go b/e2e/advanced/integration_profile_test.go index c479113e4..d8c83bad6 100644 --- a/e2e/advanced/integration_profile_test.go +++ b/e2e/advanced/integration_profile_test.go @@ -51,7 +51,6 @@ func TestIntegrationProfile(t *testing.T) { } g.Expect(CreateIntegrationProfile(t, ctx, &integrationProfile)).To(Succeed()) - g.Eventually(SelectedIntegrationProfilePhase(t, ctx, ns, "ipr-global"), TestTimeoutMedium).Should(Equal(v1.IntegrationProfilePhaseReady)) WithNewTestNamespace(t, func(ctx context.Context, g *WithT, ns1 string) { integrationProfile := v1.NewIntegrationProfile(ns1, "ipr-local") @@ -60,7 +59,6 @@ func TestIntegrationProfile(t *testing.T) { LimitCPU: "0.2", } g.Expect(CreateIntegrationProfile(t, ctx, &integrationProfile)).To(Succeed()) - g.Eventually(SelectedIntegrationProfilePhase(t, ctx, ns1, "ipr-local"), TestTimeoutMedium).Should(Equal(v1.IntegrationProfilePhaseReady)) t.Run("Run integration with global integration profile", func(t *testing.T) { g.Expect(KamelRunWithID(t, ctx, operatorID, ns1, "--name", "limited", "--integration-profile", "ipr-global", "files/yaml.yaml").Execute()).To(Succeed()) @@ -122,12 +120,11 @@ func TestIntegrationProfileInfluencesKit(t *testing.T) { } g.Expect(CreateIntegrationProfile(t, ctx, &integrationProfile)).To(Succeed()) - g.Eventually(SelectedIntegrationProfilePhase(t, ctx, ns, "ipr-global"), TestTimeoutMedium).Should(Equal(v1.IntegrationProfilePhaseReady)) g.Expect(KamelRunWithID(t, ctx, operatorID, ns, "--name", "normal", "files/yaml.yaml").Execute()).To(Succeed()) + g.Eventually(IntegrationConditionStatus(t, ctx, ns, "normal", v1.IntegrationConditionReady), TestTimeoutMedium).Should(Equal(corev1.ConditionTrue)) g.Eventually(IntegrationPod(t, ctx, ns, "normal"), TestTimeoutMedium).Should(Not(BeNil())) - g.Eventually(IntegrationPodPhase(t, ctx, ns, "normal"), TestTimeoutLong).Should(Equal(corev1.PodRunning)) - g.Eventually(IntegrationConditionStatus(t, ctx, ns, "normal", v1.IntegrationConditionReady), TestTimeoutShort).Should(Equal(corev1.ConditionTrue)) + g.Eventually(IntegrationPodPhase(t, ctx, ns, "normal"), TestTimeoutMedium).Should(Equal(corev1.PodRunning)) g.Eventually(IntegrationLogs(t, ctx, ns, "normal"), TestTimeoutShort).Should(ContainSubstring("Magicstring!")) // Verify that a new kit has been built based on the default base image integrationKitName := IntegrationKit(t, ctx, ns, "normal")() @@ -136,9 +133,9 @@ func TestIntegrationProfileInfluencesKit(t *testing.T) { g.Expect(KamelRunWithID(t, ctx, operatorID, ns, "--name", "simple", "--integration-profile", "ipr-global", "files/yaml.yaml").Execute()).To(Succeed()) + g.Eventually(IntegrationConditionStatus(t, ctx, ns, "simple", v1.IntegrationConditionReady), TestTimeoutMedium).Should(Equal(corev1.ConditionTrue)) g.Eventually(IntegrationPod(t, ctx, ns, "simple"), TestTimeoutMedium).Should(Not(BeNil())) - g.Eventually(IntegrationPodPhase(t, ctx, ns, "simple"), TestTimeoutLong).Should(Equal(corev1.PodRunning)) - g.Eventually(IntegrationConditionStatus(t, ctx, ns, "simple", v1.IntegrationConditionReady), TestTimeoutShort).Should(Equal(corev1.ConditionTrue)) + g.Eventually(IntegrationPodPhase(t, ctx, ns, "simple"), TestTimeoutMedium).Should(Equal(corev1.PodRunning)) g.Eventually(IntegrationLogs(t, ctx, ns, "simple"), TestTimeoutShort).Should(ContainSubstring("Magicstring!")) // Verify that a new kit has been built based on the previous kit @@ -166,8 +163,6 @@ func TestPropagateIntegrationProfileChanges(t *testing.T) { } g.Expect(CreateIntegrationProfile(t, ctx, &integrationProfile)).To(Succeed()) - g.Eventually(SelectedIntegrationProfilePhase(t, ctx, ns, "debug-profile"), TestTimeoutMedium).Should(Equal(v1.IntegrationProfilePhaseReady)) - g.Expect(KamelRunWithID(t, ctx, operatorID, ns, "--name", "simple", "--integration-profile", "debug-profile", "files/yaml.yaml").Execute()).To(Succeed()) g.Eventually(IntegrationPod(t, ctx, ns, "simple"), TestTimeoutMedium).Should(Not(BeNil())) diff --git a/e2e/support/test_support.go b/e2e/support/test_support.go index f457e3e62..08cae0de3 100644 --- a/e2e/support/test_support.go +++ b/e2e/support/test_support.go @@ -2160,16 +2160,6 @@ func SelectedPlatformPhase(t *testing.T, ctx context.Context, ns string, name st } } -func SelectedIntegrationProfilePhase(t *testing.T, ctx context.Context, ns string, name string) func() v1.IntegrationProfilePhase { - return func() v1.IntegrationProfilePhase { - pc := IntegrationProfileByName(t, ctx, ns, name)() - if pc == nil { - return "" - } - return pc.Status.Phase - } -} - func PlatformHas(t *testing.T, ctx context.Context, ns string, predicate func(pl *v1.IntegrationPlatform) bool) func() bool { return func() bool { pl := Platform(t, ctx, ns)() diff --git a/helm/camel-k/crds/camel-k-crds.yaml b/helm/camel-k/crds/camel-k-crds.yaml index c018394c8..594542e04 100644 --- a/helm/camel-k/crds/camel-k-crds.yaml +++ b/helm/camel-k/crds/camel-k-crds.yaml @@ -7702,7 +7702,6 @@ spec: description: |- IntegrationProfile is the resource used to apply user defined settings to the Camel K operator behavior. It defines the behavior of all Custom Resources (`IntegrationKit`, `Integration`, `Kamelet`) in the given namespace. - Deprecated: may be removed in future releases. Make use of IntegrationPlatform instead. properties: apiVersion: description: |- @@ -9764,7 +9763,7 @@ spec: type: object type: object status: - description: IntegrationProfileStatus defines the observed state of IntegrationProfile. + description: 'Deprecated: no longer in use.' properties: build: description: specify how to build the Integration/IntegrationKits diff --git a/pkg/apis/camel/v1/integrationprofile_types.go b/pkg/apis/camel/v1/integrationprofile_types.go index dc379d73f..70c5bc14b 100644 --- a/pkg/apis/camel/v1/integrationprofile_types.go +++ b/pkg/apis/camel/v1/integrationprofile_types.go @@ -56,12 +56,12 @@ type IntegrationProfileStatus struct { // IntegrationProfile is the resource used to apply user defined settings to the Camel K operator behavior. // It defines the behavior of all Custom Resources (`IntegrationKit`, `Integration`, `Kamelet`) in the given namespace. -// Deprecated: may be removed in future releases. Make use of IntegrationPlatform instead. type IntegrationProfile struct { metav1.TypeMeta `json:",inline"` metav1.ObjectMeta `json:"metadata,omitempty"` - Spec IntegrationProfileSpec `json:"spec,omitempty"` + Spec IntegrationProfileSpec `json:"spec,omitempty"` + // Deprecated: no longer in use. Status IntegrationProfileStatus `json:"status,omitempty"` } diff --git a/pkg/apis/camel/v1/integrationprofile_types_support.go b/pkg/apis/camel/v1/integrationprofile_types_support.go index 9ea29fb27..da9302b9b 100644 --- a/pkg/apis/camel/v1/integrationprofile_types_support.go +++ b/pkg/apis/camel/v1/integrationprofile_types_support.go @@ -41,96 +41,6 @@ func (in *IntegrationProfile) SetOperatorID(operatorID string) { SetAnnotation(&in.ObjectMeta, OperatorIDAnnotation, operatorID) } -// GetActualValue can be used to extract information the platform spec or its derived config in the status. -func (in *IntegrationProfile) GetActualValue(extractor func(spec IntegrationProfileSpec) string) string { - res := extractor(in.Status.IntegrationProfileSpec) - if res == "" { - res = extractor(in.Spec) - } - return res -} - -// ResyncStatusFullConfig copies the spec configuration into the status field. -func (in *IntegrationProfile) ResyncStatusFullConfig() { - cl := in.Spec.DeepCopy() - in.Status.IntegrationProfileSpec = *cl -} - -// GetCondition returns the condition with the provided type. -func (in *IntegrationProfileStatus) GetCondition(condType IntegrationProfileConditionType) *IntegrationProfileCondition { - for i := range in.Conditions { - c := in.Conditions[i] - if c.Type == condType { - return &c - } - } - return nil -} - -// SetCondition sets the condition with the given status, reason, and message. -func (in *IntegrationProfileStatus) SetCondition(condType IntegrationProfileConditionType, status corev1.ConditionStatus, reason string, message string) { - in.SetConditions(IntegrationProfileCondition{ - Type: condType, - Status: status, - LastUpdateTime: metav1.Now(), - LastTransitionTime: metav1.Now(), - Reason: reason, - Message: message, - }) -} - -// SetErrorCondition sets the condition with the given reason and error message. -func (in *IntegrationProfileStatus) SetErrorCondition(condType IntegrationProfileConditionType, reason string, err error) { - in.SetConditions(IntegrationProfileCondition{ - Type: condType, - Status: corev1.ConditionFalse, - LastUpdateTime: metav1.Now(), - LastTransitionTime: metav1.Now(), - Reason: reason, - Message: err.Error(), - }) -} - -// SetConditions updates the resource to include the provided conditions. -// -// If a condition that we are about to add already exists and has the same status and -// reason then we are not going to update. -func (in *IntegrationProfileStatus) SetConditions(conditions ...IntegrationProfileCondition) { - for _, condition := range conditions { - if condition.LastUpdateTime.IsZero() { - condition.LastUpdateTime = metav1.Now() - } - if condition.LastTransitionTime.IsZero() { - condition.LastTransitionTime = metav1.Now() - } - - currentCond := in.GetCondition(condition.Type) - - if currentCond != nil && currentCond.Status == condition.Status && currentCond.Reason == condition.Reason { - return - } - // Do not update lastTransitionTime if the status of the condition doesn't change. - if currentCond != nil && currentCond.Status == condition.Status { - condition.LastTransitionTime = currentCond.LastTransitionTime - } - - in.RemoveCondition(condition.Type) - in.Conditions = append(in.Conditions, condition) - } -} - -// RemoveCondition removes the resource condition with the provided type. -func (in *IntegrationProfileStatus) RemoveCondition(condType IntegrationProfileConditionType) { - newConditions := in.Conditions[:0] - for _, c := range in.Conditions { - if c.Type != condType { - newConditions = append(newConditions, c) - } - } - - in.Conditions = newConditions -} - // GetTimeout returns the specified duration or a default one. func (b *IntegrationProfileBuildSpec) GetTimeout() metav1.Duration { if b.Timeout == nil { @@ -141,15 +51,6 @@ func (b *IntegrationProfileBuildSpec) GetTimeout() metav1.Duration { var _ ResourceCondition = &IntegrationProfileCondition{} -// GetConditions --. -func (in *IntegrationProfileStatus) GetConditions() []ResourceCondition { - res := make([]ResourceCondition, 0, len(in.Conditions)) - for _, c := range in.Conditions { - res = append(res, &c) - } - return res -} - // GetType --. func (c *IntegrationProfileCondition) GetType() string { return string(c.Type) diff --git a/pkg/controller/add_integrationprofile.go b/pkg/controller/add_integrationprofile.go deleted file mode 100644 index 469cf40ac..000000000 --- a/pkg/controller/add_integrationprofile.go +++ /dev/null @@ -1,26 +0,0 @@ -/* -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 controller - -import ( - "github.com/apache/camel-k/v2/pkg/controller/integrationprofile" -) - -func init() { - addToManager = append(addToManager, integrationprofile.Add) -} diff --git a/pkg/controller/integration/integration_controller.go b/pkg/controller/integration/integration_controller.go index 8e58a7c02..b5db985fe 100644 --- a/pkg/controller/integration/integration_controller.go +++ b/pkg/controller/integration/integration_controller.go @@ -238,45 +238,6 @@ func enqueueRequestsFromConfigFunc(ctx context.Context, c client.Client, res ctr return requests } -func integrationProfileEnqueueRequestsFromMapFunc(ctx context.Context, c client.Client, profile *v1.IntegrationProfile) []reconcile.Request { - var requests []reconcile.Request - - if profile.Status.Phase != v1.IntegrationProfilePhaseReady { - return requests - } - - list := &v1.IntegrationList{} - - // Do global search in case of global operator - var opts []ctrl.ListOption - - if !platform.IsCurrentOperatorGlobal() { - opts = append(opts, ctrl.InNamespace(profile.Namespace)) - } - - if err := c.List(ctx, list, opts...); err != nil { - log.Error(err, "Failed to list integrations") - return requests - } - - for i := range list.Items { - integration := list.Items[i] - if integration.Status.Phase == v1.IntegrationPhaseRunning && v1.GetIntegrationProfileAnnotation(&integration) == profile.Name { - if profileNamespace := v1.GetIntegrationProfileNamespaceAnnotation(&integration); profileNamespace == "" || profileNamespace == profile.Namespace { - log.Infof("IntegrationProfile %s changed, notify integration: %s", profile.Name, integration.Name) - requests = append(requests, reconcile.Request{ - NamespacedName: types.NamespacedName{ - Namespace: integration.Namespace, - Name: integration.Name, - }, - }) - } - } - } - - return requests -} - func integrationPlatformEnqueueRequestsFromMapFunc(ctx context.Context, c client.Client, p *v1.IntegrationPlatform) []reconcile.Request { var requests []reconcile.Request @@ -375,16 +336,6 @@ func watchIntegrationResources(c client.Client, b *builder.Builder) { } return integrationPlatformEnqueueRequestsFromMapFunc(ctx, c, p) })). - // Watch for IntegrationProfile and enqueue requests for any integrations that references the profile - Watches(&v1.IntegrationProfile{}, - handler.EnqueueRequestsFromMapFunc(func(ctx context.Context, a ctrl.Object) []reconcile.Request { - profile, ok := a.(*v1.IntegrationProfile) - if !ok { - log.Error(fmt.Errorf("type assertion failed: %v", a), "Failed to retrieve IntegrationProfile") - return []reconcile.Request{} - } - return integrationProfileEnqueueRequestsFromMapFunc(ctx, c, profile) - })). // Watch for Configmaps or Secret used in the Integrations for updates Watches(&corev1.ConfigMap{}, handler.EnqueueRequestsFromMapFunc(func(ctx context.Context, a ctrl.Object) []reconcile.Request { diff --git a/pkg/controller/integration/kits.go b/pkg/controller/integration/kits.go index df0bdf9f5..6e3df4789 100644 --- a/pkg/controller/integration/kits.go +++ b/pkg/controller/integration/kits.go @@ -117,11 +117,13 @@ func integrationMatches(ctx context.Context, c client.Client, integration *v1.In if err != nil && !k8serrors.IsNotFound(err) { return false, err } - if _, err := platform.ApplyIntegrationProfile(ctx, c, pl, integration); err != nil { + + itp, err := platform.ApplyIntegrationProfile(ctx, c, integration) + if err != nil { return false, err } - itc, err := trait.NewSpecTraitsOptionsForIntegrationAndPlatform(c, integration, pl) + itc, err := trait.NewSpecTraitsOptionsForIntegrationAndPlatform(c, integration, itp, pl) if err != nil { return false, err } diff --git a/pkg/controller/integrationprofile/action.go b/pkg/controller/integrationprofile/action.go deleted file mode 100644 index 5bd470964..000000000 --- a/pkg/controller/integrationprofile/action.go +++ /dev/null @@ -1,54 +0,0 @@ -/* -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 integrationprofile - -import ( - "context" - - v1 "github.com/apache/camel-k/v2/pkg/apis/camel/v1" - "github.com/apache/camel-k/v2/pkg/client" - "github.com/apache/camel-k/v2/pkg/util/log" -) - -// Action --. -type Action interface { - client.Injectable - log.Injectable - - // a user friendly name for the action - Name() string - - // returns true if the action can handle the integration profile - CanHandle(profile *v1.IntegrationProfile) bool - - // executes the handling function - Handle(ctx context.Context, profile *v1.IntegrationProfile) (*v1.IntegrationProfile, error) -} - -type baseAction struct { - client client.Client - L log.Logger -} - -func (action *baseAction) InjectClient(client client.Client) { - action.client = client -} - -func (action *baseAction) InjectLogger(log log.Logger) { - action.L = log -} diff --git a/pkg/controller/integrationprofile/initialize.go b/pkg/controller/integrationprofile/initialize.go deleted file mode 100644 index ccd2850b8..000000000 --- a/pkg/controller/integrationprofile/initialize.go +++ /dev/null @@ -1,64 +0,0 @@ -/* -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 integrationprofile - -import ( - "context" - - corev1 "k8s.io/api/core/v1" - - v1 "github.com/apache/camel-k/v2/pkg/apis/camel/v1" -) - -// NewInitializeAction returns the action that initializes the integration profile when not provided by the user. -func NewInitializeAction() Action { - return &initializeAction{} -} - -type initializeAction struct { - baseAction -} - -func (action *initializeAction) Name() string { - return "initialize" -} - -func (action *initializeAction) CanHandle(profile *v1.IntegrationProfile) bool { - return profile.Status.Phase == v1.IntegrationProfilePhaseNone -} - -func (action *initializeAction) Handle(ctx context.Context, profile *v1.IntegrationProfile) (*v1.IntegrationProfile, error) { - action.L.Info("Initializing IntegrationProfile") - profile.ResyncStatusFullConfig() - - profile.Status.SetCondition( - v1.IntegrationProfileConditionTypeCreated, - corev1.ConditionTrue, - v1.IntegrationProfileConditionCreatedReason, - "integration profile created") - - profile.Status.SetCondition( - "DeprecationNotice", - corev1.ConditionTrue, - "DeprecationNoticeWarning", - "Usage of IntegrationProfile is deprecated. Make use of IntegrationPlatform instead.") - - profile.Status.Phase = v1.IntegrationProfilePhaseReady - - return profile, nil -} diff --git a/pkg/controller/integrationprofile/integrationprofile_controller.go b/pkg/controller/integrationprofile/integrationprofile_controller.go deleted file mode 100644 index b87806689..000000000 --- a/pkg/controller/integrationprofile/integrationprofile_controller.go +++ /dev/null @@ -1,217 +0,0 @@ -/* -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 integrationprofile - -import ( - "context" - "time" - - k8serrors "k8s.io/apimachinery/pkg/api/errors" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/runtime/schema" - "k8s.io/client-go/tools/record" - - ctrl "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/controller" - "sigs.k8s.io/controller-runtime/pkg/event" - "sigs.k8s.io/controller-runtime/pkg/handler" - "sigs.k8s.io/controller-runtime/pkg/manager" - "sigs.k8s.io/controller-runtime/pkg/reconcile" - "sigs.k8s.io/controller-runtime/pkg/source" - - v1 "github.com/apache/camel-k/v2/pkg/apis/camel/v1" - "github.com/apache/camel-k/v2/pkg/client" - camelevent "github.com/apache/camel-k/v2/pkg/event" - "github.com/apache/camel-k/v2/pkg/platform" - "github.com/apache/camel-k/v2/pkg/util/monitoring" -) - -const ( - requeueAfterDuration = 5 * time.Second -) - -// Add creates a new IntegrationProfile Controller and adds it to the Manager. The Manager will set fields -// on the Controller and Start it when the Manager is Started. -func Add(ctx context.Context, mgr manager.Manager, c client.Client) error { - return add(mgr, newReconciler(mgr, c)) -} - -func newReconciler(mgr manager.Manager, c client.Client) reconcile.Reconciler { - return monitoring.NewInstrumentedReconciler( - &reconcileIntegrationProfile{ - client: c, - reader: mgr.GetAPIReader(), - scheme: mgr.GetScheme(), - recorder: mgr.GetEventRecorderFor("camel-k-integration-profile-controller"), - }, - schema.GroupVersionKind{ - Group: v1.SchemeGroupVersion.Group, - Version: v1.SchemeGroupVersion.Version, - Kind: v1.IntegrationProfileKind, - }, - ) -} - -func add(mgr manager.Manager, r reconcile.Reconciler) error { - c, err := controller.New("integrationprofile-controller", mgr, controller.Options{Reconciler: r}) - if err != nil { - return err - } - - // Watch for changes to primary resource IntegrationProfile - err = c.Watch( - source.Kind(mgr.GetCache(), - &v1.IntegrationProfile{}, - &handler.TypedEnqueueRequestForObject[*v1.IntegrationProfile]{}, - platform.FilteringFuncs[*v1.IntegrationProfile]{ - UpdateFunc: func(e event.TypedUpdateEvent[*v1.IntegrationProfile]) bool { - // Ignore updates to the integration profile status in which case metadata.Generation - // does not change, or except when the integration profile phase changes as it's used - // to transition from one phase to another - return e.ObjectOld.Generation != e.ObjectNew.Generation || - e.ObjectOld.Status.Phase != e.ObjectNew.Status.Phase - }, - DeleteFunc: func(e event.TypedDeleteEvent[*v1.IntegrationProfile]) bool { - // Evaluates to false if the object has been confirmed deleted - return !e.DeleteStateUnknown - }, - }, - ), - ) - if err != nil { - return err - } - - return nil -} - -var _ reconcile.Reconciler = &reconcileIntegrationProfile{} - -// reconcileIntegrationProfile reconciles a IntegrationProfile object. -type reconcileIntegrationProfile struct { - // This client, initialized using mgr.Client() above, is a split client - // that reads objects from the cache and writes to the API server - client client.Client - // Non-caching client - reader ctrl.Reader - scheme *runtime.Scheme - recorder record.EventRecorder -} - -// Reconcile reads that state of the cluster for a IntegrationProfile object and makes changes based -// on the state read and what is in the IntegrationProfile.Spec -// Note: -// The Controller will requeue the Request to be processed again if the returned error is non-nil or -// Result.Requeue is true, otherwise upon completion it will remove the work from the queue. -func (r *reconcileIntegrationProfile) Reconcile(ctx context.Context, request reconcile.Request) (reconcile.Result, error) { - rlog := Log.WithValues("request-namespace", request.Namespace, "request-name", request.Name) - rlog.Debug("Reconciling IntegrationProfile") - - // Make sure the operator is allowed to act on namespace - if ok, err := platform.IsOperatorAllowedOnNamespace(ctx, r.client, request.Namespace); err != nil { - return reconcile.Result{}, err - } else if !ok { - rlog.Info("Ignoring request because namespace is locked") - return reconcile.Result{}, nil - } - - // Fetch the IntegrationProfile instance - var instance v1.IntegrationProfile - - if err := r.client.Get(ctx, request.NamespacedName, &instance); err != nil { - if k8serrors.IsNotFound(err) { - // Request object not found, could have been deleted after reconcile request. - // Owned objects are automatically garbage collected. For additional cleanup - // logic use finalizers. - - // Return and don't requeue - return reconcile.Result{}, nil - } - // Error reading the object - requeue the request. - return reconcile.Result{}, err - } - - // Only process resources assigned to the operator - if !platform.IsOperatorHandlerConsideringLock(ctx, r.client, request.Namespace, &instance) { - rlog.Info("Ignoring request because resource is not assigned to current operator") - return reconcile.Result{}, nil - } - - actions := []Action{ - NewInitializeAction(), - NewMonitorAction(), - } - - var targetPhase v1.IntegrationProfilePhase - var err error - - target := instance.DeepCopy() - targetLog := rlog.ForIntegrationProfile(target) - - for _, a := range actions { - a.InjectClient(r.client) - a.InjectLogger(targetLog) - - if !a.CanHandle(target) { - continue - } - - targetLog.Infof("Invoking action %s", a.Name()) - - phaseFrom := target.Status.Phase - - target, err = a.Handle(ctx, target) - if err != nil { - camelevent.NotifyIntegrationProfileError(ctx, r.client, r.recorder, &instance, target, err) - return reconcile.Result{}, err - } - - if target != nil { - target.Status.ObservedGeneration = instance.Generation - - if err := r.client.Status().Patch(ctx, target, ctrl.MergeFrom(&instance)); err != nil { - camelevent.NotifyIntegrationProfileError(ctx, r.client, r.recorder, &instance, target, err) - return reconcile.Result{}, err - } - - targetPhase = target.Status.Phase - - if targetPhase != phaseFrom { - targetLog.Info( - "State transition", - "phase-from", phaseFrom, - "phase-to", target.Status.Phase, - ) - } - } - - // handle one action at time so the resource - // is always at its latest state - camelevent.NotifyIntegrationProfileUpdated(ctx, r.client, r.recorder, &instance, target) - break - } - - if targetPhase == v1.IntegrationProfilePhaseReady { - return reconcile.Result{}, nil - } - - // Requeue - return reconcile.Result{ - RequeueAfter: requeueAfterDuration, - }, nil -} diff --git a/pkg/controller/integrationprofile/log.go b/pkg/controller/integrationprofile/log.go deleted file mode 100644 index c377ad906..000000000 --- a/pkg/controller/integrationprofile/log.go +++ /dev/null @@ -1,23 +0,0 @@ -/* -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 integrationprofile - -import "github.com/apache/camel-k/v2/pkg/util/log" - -// Log --. -var Log = log.Log.WithName("controller").WithName("integrationprofile") diff --git a/pkg/controller/integrationprofile/monitor.go b/pkg/controller/integrationprofile/monitor.go deleted file mode 100644 index f980c9ffb..000000000 --- a/pkg/controller/integrationprofile/monitor.go +++ /dev/null @@ -1,47 +0,0 @@ -/* -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 integrationprofile - -import ( - "context" - - v1 "github.com/apache/camel-k/v2/pkg/apis/camel/v1" -) - -// NewMonitorAction returns an action that monitors the integration profile after it's fully initialized. -func NewMonitorAction() Action { - return &monitorAction{} -} - -type monitorAction struct { - baseAction -} - -func (action *monitorAction) Name() string { - return "monitor" -} - -func (action *monitorAction) CanHandle(profile *v1.IntegrationProfile) bool { - return profile.Status.Phase == v1.IntegrationProfilePhaseReady -} - -func (action *monitorAction) Handle(ctx context.Context, profile *v1.IntegrationProfile) (*v1.IntegrationProfile, error) { - // Refresh applied profile - profile.ResyncStatusFullConfig() - return profile, nil -} diff --git a/pkg/event/manager.go b/pkg/event/manager.go index 435f13b62..2cfa9202f 100644 --- a/pkg/event/manager.go +++ b/pkg/event/manager.go @@ -174,23 +174,6 @@ func NotifyIntegrationPlatformError(ctx context.Context, c client.Client, record recorder.Eventf(p, corev1.EventTypeWarning, ReasonIntegrationPlatformError, "Cannot reconcile Integration Platform %s: %v", p.Name, err) } -// NotifyIntegrationProfileUpdated automatically generates events when a integration profile changes. -func NotifyIntegrationProfileUpdated(ctx context.Context, c client.Client, recorder record.EventRecorder, old, newResource *v1.IntegrationProfile) { - if newResource == nil { - return - } - oldPhase := "" - var oldConditions []v1.ResourceCondition - if old != nil { - oldPhase = string(old.Status.Phase) - oldConditions = old.Status.GetConditions() - } - if newResource.Status.Phase != v1.IntegrationProfilePhaseNone { - notifyIfConditionUpdated(recorder, newResource, oldConditions, newResource.Status.GetConditions(), "Integration Profile", newResource.Name, ReasonIntegrationProfileConditionChanged) - } - notifyIfPhaseUpdated(ctx, c, recorder, newResource, oldPhase, string(newResource.Status.Phase), "Integration Profile", newResource.Name, ReasonIntegrationProfilePhaseUpdated, "") -} - // NotifyIntegrationProfileError automatically generates error events when the integration Platform reconcile cycle phase has an error. func NotifyIntegrationProfileError(ctx context.Context, c client.Client, recorder record.EventRecorder, old, newResource *v1.IntegrationProfile, err error) { p := old diff --git a/pkg/platform/profile.go b/pkg/platform/profile.go index 8f9459a95..b2d5fd9c9 100644 --- a/pkg/platform/profile.go +++ b/pkg/platform/profile.go @@ -21,98 +21,19 @@ import ( "context" v1 "github.com/apache/camel-k/v2/pkg/apis/camel/v1" - "github.com/apache/camel-k/v2/pkg/util" "github.com/apache/camel-k/v2/pkg/util/kubernetes" - "github.com/apache/camel-k/v2/pkg/util/log" k8serrors "k8s.io/apimachinery/pkg/api/errors" k8sclient "sigs.k8s.io/controller-runtime/pkg/client" ) -// ApplyIntegrationProfile resolves integration profile from given object and applies the profile settings to the given integration platform. -func ApplyIntegrationProfile(ctx context.Context, c k8sclient.Reader, ip *v1.IntegrationPlatform, o k8sclient.Object) (*v1.IntegrationProfile, error) { +// ApplyIntegrationProfile resolves integration profile from given object. +func ApplyIntegrationProfile(ctx context.Context, c k8sclient.Reader, o k8sclient.Object) (*v1.IntegrationProfile, error) { profile, err := findIntegrationProfile(ctx, c, o) if err != nil && !k8serrors.IsNotFound(err) { return nil, err } - if ip == nil || profile == nil { - return nil, nil - } - - if profile.Status.Build.RuntimeVersion != "" && profile.Status.Build.RuntimeVersion != ip.Status.Build.RuntimeVersion { - log.Debugf("Integration Platform %s [%s]: setting runtime version", ip.Name, ip.Namespace) - ip.Status.Build.RuntimeVersion = profile.Status.Build.RuntimeVersion - } - - if profile.Status.Build.RuntimeProvider != "" && profile.Status.Build.RuntimeProvider != ip.Status.Build.RuntimeProvider { - log.Debugf("Integration Platform %s [%s]: setting runtime provider", ip.Name, ip.Namespace) - ip.Status.Build.RuntimeProvider = profile.Status.Build.RuntimeProvider - } - - if profile.Status.Build.BaseImage != "" && profile.Status.Build.BaseImage != ip.Status.Build.BaseImage { - log.Debugf("Integration Platform %s [%s]: setting base image", ip.Name, ip.Namespace) - ip.Status.Build.BaseImage = profile.Status.Build.BaseImage - } - - if profile.Status.Build.Maven.LocalRepository != "" && - profile.Status.Build.Maven.LocalRepository != ip.Status.Build.Maven.LocalRepository { - log.Debugf("Integration Platform %s [%s]: setting local repository", ip.Name, ip.Namespace) - ip.Status.Build.Maven.LocalRepository = profile.Status.Build.Maven.LocalRepository - } - - if len(profile.Status.Build.Maven.CLIOptions) > 0 { - log.Debugf("Integration Platform %s [%s]: setting CLI options", ip.Name, ip.Namespace) - if len(ip.Status.Build.Maven.CLIOptions) == 0 { - ip.Status.Build.Maven.CLIOptions = make([]string, len(profile.Status.Build.Maven.CLIOptions)) - copy(ip.Status.Build.Maven.CLIOptions, profile.Status.Build.Maven.CLIOptions) - } else { - util.StringSliceUniqueConcat(&ip.Status.Build.Maven.CLIOptions, profile.Status.Build.Maven.CLIOptions) - } - } - - if len(profile.Status.Build.Maven.Properties) > 0 { - log.Debugf("Integration Platform %s [%s]: setting Maven properties", ip.Name, ip.Namespace) - if len(ip.Status.Build.Maven.Properties) == 0 { - ip.Status.Build.Maven.Properties = make(map[string]string, len(profile.Status.Build.Maven.Properties)) - } - - for key, val := range profile.Status.Build.Maven.Properties { - // only set unknown properties on target - if _, ok := ip.Status.Build.Maven.Properties[key]; !ok { - ip.Status.Build.Maven.Properties[key] = val - } - } - } - - if len(profile.Status.Build.Maven.Extension) > 0 && len(ip.Status.Build.Maven.Extension) == 0 { - log.Debugf("Integration Platform %s [%s]: setting Maven extensions", ip.Name, ip.Namespace) - ip.Status.Build.Maven.Extension = make([]v1.MavenArtifact, len(profile.Status.Build.Maven.Extension)) - copy(ip.Status.Build.Maven.Extension, profile.Status.Build.Maven.Extension) - } - - if profile.Status.Build.Registry.Address != "" && profile.Status.Build.Registry.Address != ip.Status.Build.Registry.Address { - log.Debugf("Integration Platform %s [%s]: setting registry", ip.Name, ip.Namespace) - profile.Status.Build.Registry.DeepCopyInto(&ip.Status.Build.Registry) - } - - if err := ip.Status.Traits.Merge(profile.Status.Traits); err != nil { - log.Errorf(err, "Integration Platform %s [%s]: failed to merge traits", ip.Name, ip.Namespace) - } else if err := ip.Status.Traits.Merge(ip.Spec.Traits); err != nil { - log.Errorf(err, "Integration Platform %s [%s]: failed to merge traits", ip.Name, ip.Namespace) - } - - // Build timeout - if profile.Status.Build.Timeout != nil { - log.Debugf("Integration Platform %s [%s]: setting build timeout", ip.Name, ip.Namespace) - ip.Status.Build.Timeout = profile.Status.Build.Timeout - } - - if len(profile.Status.Kamelet.Repositories) > 0 { - log.Debugf("Integration Platform %s [%s]: setting kamelet repositories", ip.Name, ip.Namespace) - ip.Status.Kamelet.Repositories = append(ip.Status.Kamelet.Repositories, profile.Status.Kamelet.Repositories...) - } - return profile, nil } diff --git a/pkg/platform/profile_test.go b/pkg/platform/profile_test.go index 8ae42bd55..238b2b437 100644 --- a/pkg/platform/profile_test.go +++ b/pkg/platform/profile_test.go @@ -23,11 +23,9 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" v1 "github.com/apache/camel-k/v2/pkg/apis/camel/v1" - "github.com/apache/camel-k/v2/pkg/apis/camel/v1/trait" "github.com/apache/camel-k/v2/pkg/internal" ) @@ -39,8 +37,6 @@ func TestFindIntegrationProfile(t *testing.T) { }, } - profile.ResyncStatusFullConfig() - c, err := internal.NewFakeClient(&profile) require.NoError(t, err) @@ -70,8 +66,6 @@ func TestFindIntegrationProfileWithNamespace(t *testing.T) { }, } - profile.ResyncStatusFullConfig() - c, err := internal.NewFakeClient(&profile) require.NoError(t, err) @@ -102,8 +96,6 @@ func TestFindIntegrationProfileInOperatorNamespace(t *testing.T) { }, } - profile.ResyncStatusFullConfig() - c, err := internal.NewFakeClient(&profile) require.NoError(t, err) @@ -126,198 +118,3 @@ func TestFindIntegrationProfileInOperatorNamespace(t *testing.T) { require.NoError(t, err) assert.NotNil(t, found) } - -func TestApplyIntegrationProfile(t *testing.T) { - profile := v1.IntegrationProfile{ - ObjectMeta: metav1.ObjectMeta{ - Name: "custom", - Namespace: "ns", - }, - Spec: v1.IntegrationProfileSpec{ - Build: v1.IntegrationProfileBuildSpec{ - Maven: v1.MavenSpec{ - Properties: map[string]string{ - "global_prop1": "global_value1", - "global_prop2": "global_value2", - }, - CLIOptions: []string{ - "-V", - "--no-transfer-progress", - "-Dstyle.color=never", - "-E", - }, - }, - RuntimeVersion: "0.99.0", - }, - Traits: v1.Traits{ - Logging: &trait.LoggingTrait{ - Level: "DEBUG", - }, - Container: &trait.ContainerTrait{ - ImagePullPolicy: corev1.PullAlways, - LimitCPU: "0.1", - }, - }, - }, - } - - profile.ResyncStatusFullConfig() - - c, err := internal.NewFakeClient(&profile) - require.NoError(t, err) - - ip := v1.IntegrationPlatform{ - ObjectMeta: metav1.ObjectMeta{ - Name: "local-camel-k", - Namespace: "ns", - }, - Spec: v1.IntegrationPlatformSpec{ - Build: v1.IntegrationPlatformBuildSpec{ - BuildConfiguration: v1.BuildConfiguration{ - Strategy: v1.BuildStrategyRoutine, - OrderStrategy: v1.BuildOrderStrategyFIFO, - }, - }, - Cluster: v1.IntegrationPlatformClusterOpenShift, - Profile: v1.TraitProfileOpenShift, - }, - } - - ip.ResyncStatusFullConfig() - - err = ConfigureDefaults(context.TODO(), c, &ip, true) - require.NoError(t, err) - - integration := v1.Integration{ - ObjectMeta: metav1.ObjectMeta{ - Name: "test", - Namespace: "ns", - Annotations: map[string]string{ - v1.IntegrationProfileAnnotation: "custom", - }, - }, - Status: v1.IntegrationStatus{ - Phase: v1.IntegrationPhaseRunning, - }, - } - - _, err = ApplyIntegrationProfile(context.TODO(), c, &ip, &integration) - require.NoError(t, err) - - assert.Equal(t, v1.IntegrationPlatformClusterOpenShift, ip.Status.Cluster) - assert.Equal(t, v1.TraitProfileOpenShift, ip.Status.Profile) - assert.Equal(t, v1.BuildStrategyRoutine, ip.Status.Build.BuildConfiguration.Strategy) - assert.Equal(t, v1.BuildOrderStrategyFIFO, ip.Status.Build.BuildConfiguration.OrderStrategy) - assert.True(t, ip.Status.Build.MaxRunningBuilds == 3) // default for build strategy routine - assert.Equal(t, len(profile.Status.Build.Maven.CLIOptions), len(ip.Status.Build.Maven.CLIOptions)) - assert.Equal(t, profile.Status.Build.Maven.CLIOptions, ip.Status.Build.Maven.CLIOptions) - assert.NotNil(t, ip.Status.Traits) - assert.NotNil(t, ip.Status.Traits.Logging) - assert.Equal(t, "DEBUG", ip.Status.Traits.Logging.Level) - assert.NotNil(t, ip.Status.Traits.Container) - assert.Equal(t, corev1.PullAlways, ip.Status.Traits.Container.ImagePullPolicy) - assert.Equal(t, "0.1", ip.Status.Traits.Container.LimitCPU) - assert.Equal(t, 2, len(ip.Status.Build.Maven.Properties)) - assert.Equal(t, "global_value1", ip.Status.Build.Maven.Properties["global_prop1"]) - assert.Equal(t, "global_value2", ip.Status.Build.Maven.Properties["global_prop2"]) -} - -func TestApplyIntegrationProfileAndRetainPlatformSpec(t *testing.T) { - profile := v1.IntegrationProfile{ - ObjectMeta: metav1.ObjectMeta{ - Name: DefaultPlatformName, - Namespace: "ns", - }, - Spec: v1.IntegrationProfileSpec{ - Build: v1.IntegrationProfileBuildSpec{ - Maven: v1.MavenSpec{ - Properties: map[string]string{ - "global_prop1": "global_value1", - "global_prop2": "global_value2", - }, - }, - }, - Traits: v1.Traits{ - Logging: &trait.LoggingTrait{ - Level: "DEBUG", - }, - Container: &trait.ContainerTrait{ - ImagePullPolicy: corev1.PullIfNotPresent, - LimitCPU: "0.1", - }, - }, - }, - } - - profile.ResyncStatusFullConfig() - - c, err := internal.NewFakeClient(&profile) - require.NoError(t, err) - - ip := v1.IntegrationPlatform{ - ObjectMeta: metav1.ObjectMeta{ - Name: "local-camel-k", - Namespace: "ns", - }, - Spec: v1.IntegrationPlatformSpec{ - Build: v1.IntegrationPlatformBuildSpec{ - BuildConfiguration: v1.BuildConfiguration{ - Strategy: v1.BuildStrategyPod, - OrderStrategy: v1.BuildOrderStrategyFIFO, - }, - MaxRunningBuilds: 1, - Maven: v1.MavenSpec{ - Properties: map[string]string{ - "local_prop1": "local_value1", - "global_prop2": "local_value2", - }, - }, - }, - Traits: v1.Traits{ - Container: &trait.ContainerTrait{ - ImagePullPolicy: corev1.PullAlways, - }, - }, - Cluster: v1.IntegrationPlatformClusterKubernetes, - Profile: v1.TraitProfileKnative, - }, - } - - ip.ResyncStatusFullConfig() - - err = ConfigureDefaults(context.TODO(), c, &ip, true) - require.NoError(t, err) - - integration := v1.Integration{ - ObjectMeta: metav1.ObjectMeta{ - Name: "test", - Namespace: "ns", - Annotations: map[string]string{ - v1.IntegrationProfileAnnotation: DefaultPlatformName, - }, - }, - Status: v1.IntegrationStatus{ - Phase: v1.IntegrationPhaseRunning, - }, - } - - _, err = ApplyIntegrationProfile(context.TODO(), c, &ip, &integration) - require.NoError(t, err) - - assert.Equal(t, v1.IntegrationPlatformClusterKubernetes, ip.Status.Cluster) - assert.Equal(t, v1.TraitProfileKnative, ip.Status.Profile) - assert.Equal(t, v1.BuildStrategyPod, ip.Status.Build.BuildConfiguration.Strategy) - assert.Equal(t, v1.BuildOrderStrategyFIFO, ip.Status.Build.BuildConfiguration.OrderStrategy) - assert.True(t, ip.Status.Build.MaxRunningBuilds == 1) - assert.Equal(t, 3, len(ip.Status.Build.Maven.CLIOptions)) - assert.NotNil(t, ip.Status.Traits) - assert.NotNil(t, ip.Status.Traits.Logging) - assert.Equal(t, "DEBUG", ip.Status.Traits.Logging.Level) - assert.NotNil(t, ip.Status.Traits.Container) - assert.Equal(t, corev1.PullAlways, ip.Status.Traits.Container.ImagePullPolicy) - assert.Equal(t, "0.1", ip.Status.Traits.Container.LimitCPU) - assert.Equal(t, 3, len(ip.Status.Build.Maven.Properties)) - assert.Equal(t, "global_value1", ip.Status.Build.Maven.Properties["global_prop1"]) - assert.Equal(t, "local_value2", ip.Status.Build.Maven.Properties["global_prop2"]) - assert.Equal(t, "local_value1", ip.Status.Build.Maven.Properties["local_prop1"]) -} diff --git a/pkg/resources/config/crd/bases/camel.apache.org_integrationprofiles.yaml b/pkg/resources/config/crd/bases/camel.apache.org_integrationprofiles.yaml index b8c743434..2c10d4958 100644 --- a/pkg/resources/config/crd/bases/camel.apache.org_integrationprofiles.yaml +++ b/pkg/resources/config/crd/bases/camel.apache.org_integrationprofiles.yaml @@ -51,7 +51,6 @@ spec: description: |- IntegrationProfile is the resource used to apply user defined settings to the Camel K operator behavior. It defines the behavior of all Custom Resources (`IntegrationKit`, `Integration`, `Kamelet`) in the given namespace. - Deprecated: may be removed in future releases. Make use of IntegrationPlatform instead. properties: apiVersion: description: |- @@ -2113,7 +2112,7 @@ spec: type: object type: object status: - description: IntegrationProfileStatus defines the observed state of IntegrationProfile. + description: 'Deprecated: no longer in use.' properties: build: description: specify how to build the Integration/IntegrationKits diff --git a/pkg/trait/camel.go b/pkg/trait/camel.go index 963b78231..43868a991 100644 --- a/pkg/trait/camel.go +++ b/pkg/trait/camel.go @@ -204,8 +204,8 @@ func determineRuntimeVersion(e *Environment) (string, error) { if e.IntegrationKit != nil && e.IntegrationKit.Status.RuntimeVersion != "" { return e.IntegrationKit.Status.RuntimeVersion, nil } - if e.IntegrationProfile != nil && e.IntegrationProfile.Status.Build.RuntimeVersion != "" { - return e.IntegrationProfile.Status.Build.RuntimeVersion, nil + if e.IntegrationProfile != nil && e.IntegrationProfile.Spec.Build.RuntimeVersion != "" { + return e.IntegrationProfile.Spec.Build.RuntimeVersion, nil } if e.Platform != nil && e.Platform.Status.Build.RuntimeVersion != "" { return e.Platform.Status.Build.RuntimeVersion, nil diff --git a/pkg/trait/quarkus.go b/pkg/trait/quarkus.go index d210eacdd..c8be8947c 100644 --- a/pkg/trait/quarkus.go +++ b/pkg/trait/quarkus.go @@ -315,7 +315,7 @@ func propagateKitTraits(e *Environment) v1.IntegrationKitTraits { } if e.IntegrationProfile != nil { - propagate(fmt.Sprintf("integration profile %q", e.IntegrationProfile.Name), e.IntegrationProfile.Status.Traits, &kitTraits, e) + propagate(fmt.Sprintf("integration profile %q", e.IntegrationProfile.Name), e.IntegrationProfile.Spec.Traits, &kitTraits, e) } propagate(fmt.Sprintf("integration %q", e.Integration.Name), e.Integration.Spec.Traits, &kitTraits, e) diff --git a/pkg/trait/trait.go b/pkg/trait/trait.go index 93c10a74a..7e698980f 100644 --- a/pkg/trait/trait.go +++ b/pkg/trait/trait.go @@ -122,7 +122,7 @@ func newEnvironment(ctx context.Context, c client.Client, integration *v1.Integr return nil, err } - ipr, err := platform.ApplyIntegrationProfile(ctx, c, pl, obj) + ipr, err := platform.ApplyIntegrationProfile(ctx, c, obj) if err != nil { return nil, err } diff --git a/pkg/trait/trait_configure.go b/pkg/trait/trait_configure.go index bd617bdcc..57bb60fb4 100644 --- a/pkg/trait/trait_configure.go +++ b/pkg/trait/trait_configure.go @@ -42,7 +42,7 @@ func (c *Catalog) Configure(env *Environment) error { } } if env.IntegrationProfile != nil { - if err := c.configureTraits(env.IntegrationProfile.Status.Traits); err != nil { + if err := c.configureTraits(env.IntegrationProfile.Spec.Traits); err != nil { return err } } diff --git a/pkg/trait/util.go b/pkg/trait/util.go index 6d930b407..3bc6c4c80 100644 --- a/pkg/trait/util.go +++ b/pkg/trait/util.go @@ -382,17 +382,24 @@ func extractAsArray(value string) []string { return []string{value} } -// NewSpecTraitsOptionsForIntegrationAndPlatform will merge traits giving priority to Integration configuration over Platform configuration. -func NewSpecTraitsOptionsForIntegrationAndPlatform(c client.Client, i *v1.Integration, pl *v1.IntegrationPlatform) (Options, error) { - var mergedTraits v1.Traits +// NewSpecTraitsOptionsForIntegrationAndPlatform will merge traits giving priority to Integration, Profile and Platform respectively. +func NewSpecTraitsOptionsForIntegrationAndPlatform( + c client.Client, i *v1.Integration, itp *v1.IntegrationProfile, pl *v1.IntegrationPlatform) (Options, error) { + mergedTraits := v1.Traits{} + itpTraits := v1.Traits{} if pl != nil { mergedTraits = pl.Status.Traits - if err := mergedTraits.Merge(i.Spec.Traits); err != nil { - return nil, err - } - } else { - mergedTraits = i.Spec.Traits } + if itp != nil { + itpTraits = itp.Spec.Traits + } + if err := mergedTraits.Merge(itpTraits); err != nil { + return nil, err + } + if err := mergedTraits.Merge(i.Spec.Traits); err != nil { + return nil, err + } + options, err := ToTraitMap(mergedTraits) if err != nil { return nil, err diff --git a/pkg/trait/util_test.go b/pkg/trait/util_test.go index d32247ce0..d08d61311 100644 --- a/pkg/trait/util_test.go +++ b/pkg/trait/util_test.go @@ -297,7 +297,7 @@ func TestMergePlatformTraits(t *testing.T) { c, err := internal.NewFakeClient() require.NoError(t, err) - mergedOptions, err := NewSpecTraitsOptionsForIntegrationAndPlatform(c, integration, platform) + mergedOptions, err := NewSpecTraitsOptionsForIntegrationAndPlatform(c, integration, nil, platform) require.NoError(t, err) assert.Equal(t, expectedOptions, mergedOptions) } @@ -334,7 +334,41 @@ func TestMergePlatformTraitsIntegrationPriority(t *testing.T) { c, err := internal.NewFakeClient() require.NoError(t, err) - mergedOptions, err := NewSpecTraitsOptionsForIntegrationAndPlatform(c, integration, platform) + mergedOptions, err := NewSpecTraitsOptionsForIntegrationAndPlatform(c, integration, nil, platform) + require.NoError(t, err) + assert.Equal(t, expectedOptions, mergedOptions) +} + +func TestMergeIntegrationProfileTraits(t *testing.T) { + integration := &v1.Integration{ + Spec: v1.IntegrationSpec{ + Traits: v1.Traits{ + Camel: &traitv1.CamelTrait{ + Properties: []string{"hello=world"}, + }, + }, + }, + } + profile := &v1.IntegrationProfile{ + Spec: v1.IntegrationProfileSpec{ + Traits: v1.Traits{ + Camel: &traitv1.CamelTrait{ + RuntimeVersion: "1.2.3", + }, + }, + }, + } + + expectedOptions := Options{ + "camel": { + "properties": []any{"hello=world"}, + "runtimeVersion": "1.2.3", + }, + } + + c, err := internal.NewFakeClient() + require.NoError(t, err) + mergedOptions, err := NewSpecTraitsOptionsForIntegrationAndPlatform(c, integration, profile, nil) require.NoError(t, err) assert.Equal(t, expectedOptions, mergedOptions) }