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
commit 229f465712f64dfe2740d5d6c2a1103d4d8341cb Author: Pasquale Congiusti <[email protected]> AuthorDate: Mon May 20 10:36:35 2024 +0200 fix(traits): knative service for synthetic kits Ref #5519 --- pkg/trait/knative_service.go | 26 ++++++- pkg/trait/trait_types_test.go | 171 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 195 insertions(+), 2 deletions(-) diff --git a/pkg/trait/knative_service.go b/pkg/trait/knative_service.go index d7ded440a..dca734ee0 100644 --- a/pkg/trait/knative_service.go +++ b/pkg/trait/knative_service.go @@ -148,13 +148,30 @@ func (t *knativeServiceTrait) Apply(e *Environment) error { } func (t *knativeServiceTrait) SelectControllerStrategy(e *Environment) (*ControllerStrategy, error) { - if !pointer.BoolDeref(t.Enabled, true) || e.CamelCatalog == nil { - // explicitly disabled or sourceless Integration (missing catalog) + if !pointer.BoolDeref(t.Enabled, true) { + // explicitly disabled by the user return nil, nil } // Knative serving is required if ok, _ := knative.IsServingInstalled(e.Client); !ok { + if t.isForcefullyEnabled() { + // User has forcefully request to use this feature. + // Warn the user that he requested a feature but it cannot be fulfilled due to missing + // API installation + return nil, fmt.Errorf("missing Knative Service API, cannot enable Knative service trait") + } + return nil, nil + } + + if e.CamelCatalog == nil { + if t.isForcefullyEnabled() { + // Likely a sourceless Integration. Here we must verify the user has forcefully enabled the feature in order to turn it on + // as we don't have the possibility to scan the Integration source to verify if there is any endpoint suitable with + // Knative + knativeServiceStrategy := ControllerStrategyKnativeService + return &knativeServiceStrategy, nil + } return nil, nil } @@ -175,6 +192,11 @@ func (t *knativeServiceTrait) SelectControllerStrategy(e *Environment) (*Control return nil, nil } +// This is true only when the user set the enabled flag on and the auto flag off +func (t *knativeServiceTrait) isForcefullyEnabled() bool { + return pointer.BoolDeref(t.Enabled, false) && !pointer.BoolDeref(t.Auto, true) +} + func (t *knativeServiceTrait) ControllerStrategySelectorOrder() int { return knativeServiceStrategySelectorOrder } diff --git a/pkg/trait/trait_types_test.go b/pkg/trait/trait_types_test.go index 978487b74..ab3eabef3 100644 --- a/pkg/trait/trait_types_test.go +++ b/pkg/trait/trait_types_test.go @@ -22,8 +22,16 @@ 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" + "k8s.io/utils/pointer" 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/util/camel" + "github.com/apache/camel-k/v2/pkg/util/defaults" + "github.com/apache/camel-k/v2/pkg/util/kubernetes" + "github.com/apache/camel-k/v2/pkg/util/test" ) func TestMultilinePropertiesHandled(t *testing.T) { @@ -164,3 +172,166 @@ func TestCapabilityPropertyKey(t *testing.T) { camelPropertyKeyDynamic := CapabilityPropertyKey(`quarkus.camel.cluster.kubernetes.labels."${camel.k.master.labelKey}"`, vars) assert.Equal(t, `quarkus.camel.cluster.kubernetes.labels."org.apache.camel/integration"`, camelPropertyKeyDynamic) } + +func TestDetermineControllerStrategyDefault(t *testing.T) { + e := createTestEnvironment(t, v1.DefaultTraitProfile) + strategy, err := e.DetermineControllerStrategy() + require.NoError(t, err) + assert.Equal(t, DefaultControllerStrategy, strategy) +} + +func TestDetermineControllerStrategyAutoKnative(t *testing.T) { + e := createTestEnvironment(t, v1.TraitProfileKnative) + strategy, err := e.DetermineControllerStrategy() + require.NoError(t, err) + assert.Equal(t, ControllerStrategyKnativeService, strategy) +} + +func TestDetermineControllerStrategySyntheticKitDefault(t *testing.T) { + e := createSyntethicKitTestEnvironment(t, v1.TraitProfileKnative) + strategy, err := e.DetermineControllerStrategy() + require.NoError(t, err) + assert.Equal(t, DefaultControllerStrategy, strategy) +} + +func TestDetermineControllerStrategySyntheticKitForceKnative(t *testing.T) { + e := createSyntethicKitTestEnvironment(t, v1.TraitProfileKnative) + e.Integration.Spec.Traits = v1.Traits{ + KnativeService: &trait.KnativeServiceTrait{ + Trait: trait.Trait{ + Enabled: pointer.Bool(true), + }, + Auto: pointer.Bool(false), + }, + } + e.Platform.ResyncStatusFullConfig() + _, err := e.Catalog.apply(e) + require.NoError(t, err) + + strategy, err := e.DetermineControllerStrategy() + require.NoError(t, err) + assert.Equal(t, ControllerStrategyKnativeService, strategy) +} + +func createTestEnvironment(t *testing.T, profile v1.TraitProfile) *Environment { + t.Helper() + + catalog, err := camel.DefaultCatalog() + require.NoError(t, err) + + client, _ := test.NewFakeClient() + traitCatalog := NewCatalog(nil) + + environment := &Environment{ + CamelCatalog: catalog, + Catalog: traitCatalog, + Client: client, + Integration: &v1.Integration{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test", + Namespace: "default", + }, + Status: v1.IntegrationStatus{ + Phase: v1.IntegrationPhaseDeploying, + }, + Spec: v1.IntegrationSpec{ + Profile: profile, + Sources: []v1.SourceSpec{ + { + DataSpec: v1.DataSpec{ + Name: "routes.js", + Content: `from("direct:test").log("hello")`, + }, + Language: v1.LanguageJavaScript, + }, + { + DataSpec: v1.DataSpec{ + Name: "rests.xml", + Content: `<rest path="/test"></rest>`, + }, + Language: v1.LanguageXML, + }, + }, + }, + }, + IntegrationKit: &v1.IntegrationKit{ + Status: v1.IntegrationKitStatus{ + Phase: v1.IntegrationKitPhaseReady, + }, + }, + Platform: &v1.IntegrationPlatform{ + Spec: v1.IntegrationPlatformSpec{ + Cluster: v1.IntegrationPlatformClusterKubernetes, + Build: v1.IntegrationPlatformBuildSpec{ + RuntimeVersion: catalog.Runtime.Version, + }, + }, + Status: v1.IntegrationPlatformStatus{ + Phase: v1.IntegrationPlatformPhaseReady, + }, + }, + EnvVars: make([]corev1.EnvVar, 0), + ExecutedTraits: make([]Trait, 0), + Resources: kubernetes.NewCollection(), + } + + environment.Platform.ResyncStatusFullConfig() + + _, err = traitCatalog.apply(environment) + require.NoError(t, err) + + return environment +} + +func createSyntethicKitTestEnvironment(t *testing.T, profile v1.TraitProfile) *Environment { + t.Helper() + client, _ := test.NewFakeClient() + traitCatalog := NewCatalog(nil) + environment := &Environment{ + Catalog: traitCatalog, + Client: client, + Integration: &v1.Integration{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test", + Namespace: "default", + }, + Status: v1.IntegrationStatus{ + // default init runtime value + RuntimeProvider: v1.RuntimeProviderQuarkus, + RuntimeVersion: defaults.DefaultRuntimeVersion, + Phase: v1.IntegrationPhaseDeploying, + }, + Spec: v1.IntegrationSpec{ + Profile: profile, + }, + }, + IntegrationKit: &v1.IntegrationKit{ + ObjectMeta: metav1.ObjectMeta{ + Labels: map[string]string{ + v1.IntegrationKitTypeLabel: v1.IntegrationKitTypeSynthetic, + }, + }, + Status: v1.IntegrationKitStatus{ + Phase: v1.IntegrationKitPhaseReady, + }, + }, + Platform: &v1.IntegrationPlatform{ + Spec: v1.IntegrationPlatformSpec{ + Cluster: v1.IntegrationPlatformClusterKubernetes, + }, + Status: v1.IntegrationPlatformStatus{ + Phase: v1.IntegrationPlatformPhaseReady, + }, + }, + EnvVars: make([]corev1.EnvVar, 0), + ExecutedTraits: make([]Trait, 0), + Resources: kubernetes.NewCollection(), + } + + environment.Platform.ResyncStatusFullConfig() + + _, err := traitCatalog.apply(environment) + require.NoError(t, err) + + return environment +}
