From 52fc63107d2fc5b09fcd371b3d0b536091f70b42 Mon Sep 17 00:00:00 2001 From: Pasquale Congiusti Date: Wed, 21 Aug 2024 09:44:56 +0200 Subject: [PATCH 1/4] chore: consume source code refactoring We should allow the consume of sources and meta from trait package only via consumer funcs. In this way we can control the logic for instance, allowing to consume only when sources or catalog are available. --- addons/keda/keda.go | 11 +- addons/master/master.go | 66 +++--- addons/resume/resume.go | 17 +- e2e/advanced/promote_test.go | 16 -- pkg/builder/quarkus.go | 25 +- pkg/cmd/promote.go | 261 +-------------------- pkg/metadata/metadata.go | 27 +-- pkg/metadata/metadata_capabilities_test.go | 2 +- pkg/metadata/metadata_dependencies_test.go | 44 ++-- pkg/metadata/metadata_http_test.go | 16 +- pkg/metadata/metadata_uri_test.go | 16 +- pkg/trait/container.go | 23 -- pkg/trait/container_test.go | 97 +------- pkg/trait/cron.go | 14 +- pkg/trait/dependencies.go | 36 ++- pkg/trait/kamelets.go | 15 +- pkg/trait/knative.go | 115 ++++----- pkg/trait/knative_service.go | 40 +--- pkg/trait/knative_test.go | 105 +++++++++ pkg/{util/kubernetes => trait}/resolver.go | 23 +- pkg/trait/security_context_test.go | 5 + pkg/trait/service.go | 17 +- pkg/trait/trait_types.go | 35 +++ pkg/trait/util.go | 42 +--- pkg/util/kamelets/util.go | 59 ----- 25 files changed, 363 insertions(+), 764 deletions(-) rename pkg/{util/kubernetes => trait}/resolver.go (81%) delete mode 100644 pkg/util/kamelets/util.go diff --git a/addons/keda/keda.go b/addons/keda/keda.go index 08b2fa8328..3060d48b3c 100644 --- a/addons/keda/keda.go +++ b/addons/keda/keda.go @@ -34,7 +34,6 @@ import ( "github.com/apache/camel-k/v2/pkg/platform" "github.com/apache/camel-k/v2/pkg/trait" "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/property" "github.com/apache/camel-k/v2/pkg/util/source" "github.com/apache/camel-k/v2/pkg/util/uri" @@ -315,12 +314,8 @@ func (t *kedaTrait) getTopControllerReference(e *trait.Environment) *v1.ObjectRe } func (t *kedaTrait) populateTriggersFromKamelets(e *trait.Environment) error { - sources, err := kubernetes.ResolveIntegrationSources(e.Ctx, e.Client, e.Integration, e.Resources) - if err != nil { - return err - } kameletURIs := make(map[string][]string) - if err := metadata.Each(e.CamelCatalog, sources, func(_ int, meta metadata.IntegrationMetadata) bool { + _, err := e.ConsumeMeta(func(meta metadata.IntegrationMetadata) bool { for _, kameletURI := range meta.FromURIs { if kameletStr := source.ExtractKamelet(kameletURI); kameletStr != "" && camelv1.ValidKameletName(kameletStr) { kamelet := kameletStr @@ -333,8 +328,10 @@ func (t *kedaTrait) populateTriggersFromKamelets(e *trait.Environment) error { kameletURIs[kamelet] = uriList } } + return true - }); err != nil { + }) + if err != nil { return err } diff --git a/addons/master/master.go b/addons/master/master.go index 7e3fbda0f2..5ebc04c797 100644 --- a/addons/master/master.go +++ b/addons/master/master.go @@ -99,52 +99,50 @@ func (t *masterTrait) Configure(e *trait.Environment) (bool, *trait.TraitConditi return ptr.Deref(t.Enabled, false), nil, nil } - // Check if the master component has been used - sources, err := kubernetes.ResolveIntegrationSources(e.Ctx, t.Client, e.Integration, e.Resources) - if err != nil { - return false, nil, err - } - - meta, err := metadata.ExtractAll(e.CamelCatalog, sources) - if err != nil { - return false, nil, err - } - - if t.Enabled == nil { + enabled, err := e.ConsumeMeta(func(meta metadata.IntegrationMetadata) bool { + found := false + loop: for _, endpoint := range meta.FromURIs { if uri.GetComponent(endpoint) == masterComponent { - enabled := true - t.Enabled = &enabled + found = true + break loop } } - // No master component, can skip the trait execution - if !ptr.Deref(t.Enabled, false) { - return false, nil, nil + if found { + if t.IncludeDelegateDependencies == nil || *t.IncludeDelegateDependencies { + t.delegateDependencies = findAdditionalDependencies(e, meta) + } } - } - if t.IncludeDelegateDependencies == nil || *t.IncludeDelegateDependencies { - t.delegateDependencies = findAdditionalDependencies(e, meta) - } - if t.ResourceName == nil { - val := e.Integration.Name + "-lock" - t.ResourceName = &val - } + return found + }) - if t.ResourceType == nil { - t.ResourceType = ptr.To(leaseResourceType) + if err != nil { + return false, nil, err } + if enabled { + if t.ResourceName == nil { + val := e.Integration.Name + "-lock" + t.ResourceName = &val + } - if t.LabelKey == nil { - val := v1.IntegrationLabel - t.LabelKey = &val - } + if t.ResourceType == nil { + t.ResourceType = ptr.To(leaseResourceType) + } + + if t.LabelKey == nil { + val := v1.IntegrationLabel + t.LabelKey = &val + } + + if t.LabelValue == nil { + t.LabelValue = &e.Integration.Name + } - if t.LabelValue == nil { - t.LabelValue = &e.Integration.Name + return true, nil, nil } - return ptr.Deref(t.Enabled, false), nil, nil + return false, nil, nil } func (t *masterTrait) Apply(e *trait.Environment) error { diff --git a/addons/resume/resume.go b/addons/resume/resume.go index 1dd92f0504..6fed7e3bfc 100644 --- a/addons/resume/resume.go +++ b/addons/resume/resume.go @@ -23,7 +23,6 @@ import ( "github.com/apache/camel-k/v2/pkg/metadata" "github.com/apache/camel-k/v2/pkg/trait" "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" "k8s.io/utils/ptr" ) @@ -87,21 +86,17 @@ func (r *resumeTrait) Configure(environment *trait.Environment) (bool, *trait.Tr } if ptr.Deref(r.Auto, true) { - // Check which components have been used - sources, err := kubernetes.ResolveIntegrationSources(environment.Ctx, r.Client, environment.Integration, environment.Resources) - if err != nil { - return false, nil, err - } + _, err := environment.ConsumeMeta(func(meta metadata.IntegrationMetadata) bool { + for _, endpoint := range meta.FromURIs { + log.Infof("Processing component %s", endpoint) + } - meta, err := metadata.ExtractAll(environment.CamelCatalog, sources) + return true + }) if err != nil { return false, nil, err } - for _, endpoint := range meta.FromURIs { - log.Infof("Processing component %s", endpoint) - } - if r.ResumeStrategy == "" { r.ResumeStrategy = KafkaSingle } diff --git a/e2e/advanced/promote_test.go b/e2e/advanced/promote_test.go index 4ec4dbdefd..ee405c9f62 100644 --- a/e2e/advanced/promote_test.go +++ b/e2e/advanced/promote_test.go @@ -91,19 +91,11 @@ func TestKamelCLIPromote(t *testing.T) { InstallOperatorWithConf(t, ctx, g, nsProd, operatorProdID, false, nil) g.Eventually(PlatformPhase(t, ctx, nsProd), TestTimeoutMedium).Should(Equal(v1.IntegrationPlatformPhaseReady)) - t.Run("no configmap in destination", func(t *testing.T) { - g.Expect(Kamel(t, ctx, "promote", "-n", nsDev, "promote-route", "--to", nsProd).Execute()).NotTo(Succeed()) - }) - // Prod content configmap var cmData = make(map[string]string) cmData["my-configmap-key"] = "I am production" CreatePlainTextConfigmap(t, ctx, nsProd, "my-cm-promote", cmData) - t.Run("no secret in destination", func(t *testing.T) { - g.Expect(Kamel(t, ctx, "promote", "-n", nsDev, "promote-route", "--to", nsProd).Execute()).NotTo(Succeed()) - }) - // Prod secret var secData = make(map[string]string) secData["my-secret-key"] = "very top secret production" @@ -143,10 +135,6 @@ func TestKamelCLIPromote(t *testing.T) { g.Expect(IntegrationPodImage(t, ctx, nsProd, "promote-route")()).Should(Equal(IntegrationPodImage(t, ctx, nsDev, "promote-route")())) }) - t.Run("no kamelet in destination", func(t *testing.T) { - g.Expect(Kamel(t, ctx, "promote", "-n", nsDev, "timer-kamelet-usage", "--to", nsProd).Execute()).NotTo(Succeed()) - }) - t.Run("kamelet integration promotion", func(t *testing.T) { g.Expect(CreateTimerKameletWithID(t, ctx, operatorProdID, nsProd, "my-own-timer-source")()).To(Succeed()) g.Expect(Kamel(t, ctx, "promote", "-n", nsDev, "timer-kamelet-usage", "--to", nsProd).Execute()).To(Succeed()) @@ -156,10 +144,6 @@ func TestKamelCLIPromote(t *testing.T) { g.Expect(IntegrationPodImage(t, ctx, nsProd, "timer-kamelet-usage")()).Should(Equal(IntegrationPodImage(t, ctx, nsDev, "timer-kamelet-usage")())) }) - t.Run("no kamelet for binding in destination", func(t *testing.T) { - g.Expect(Kamel(t, ctx, "promote", "-n", nsDev, "kb-timer-source-to-log", "--to", nsProd).Execute()).NotTo(Succeed()) - }) - t.Run("binding promotion", func(t *testing.T) { g.Expect(CreateTimerKameletWithID(t, ctx, operatorProdID, nsProd, "kb-timer-source")()).To(Succeed()) g.Expect(Kamel(t, ctx, "promote", "-n", nsDev, "kb-timer-source-to-log", "--to", nsProd).Execute()).To(Succeed()) diff --git a/pkg/builder/quarkus.go b/pkg/builder/quarkus.go index f39648b1ee..000155fdd4 100644 --- a/pkg/builder/quarkus.go +++ b/pkg/builder/quarkus.go @@ -32,9 +32,7 @@ import ( "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/digest" - "github.com/apache/camel-k/v2/pkg/util/kubernetes" "github.com/apache/camel-k/v2/pkg/util/maven" - corev1 "k8s.io/api/core/v1" ) const projectModePerm = 0600 @@ -67,35 +65,14 @@ var Quarkus = quarkusSteps{ ComputeQuarkusDependencies: NewStep(ProjectBuildPhase+1, computeQuarkusDependencies), } -func resolveBuildSources(ctx *builderContext) ([]v1.SourceSpec, error) { - resources := kubernetes.NewCollection() - return kubernetes.ResolveSources(ctx.Build.Sources, func(name string) (*corev1.ConfigMap, error) { - // the config map could be part of the resources created - // by traits - cm := resources.GetConfigMap(func(m *corev1.ConfigMap) bool { - return m.Name == name - }) - - if cm != nil { - return cm, nil - } - - return kubernetes.GetConfigMap(ctx.C, ctx.Client, name, ctx.Namespace) - }) -} - func prepareProjectWithSources(ctx *builderContext) error { - sources, err := resolveBuildSources(ctx) - if err != nil { - return err - } sourcesPath := filepath.Join(ctx.Path, "maven", "src", "main", "resources", "routes") if err := os.MkdirAll(sourcesPath, os.ModePerm); err != nil { return fmt.Errorf("failure while creating resource folder: %w", err) } sourceList := "" - for _, source := range sources { + for _, source := range ctx.Build.Sources { if sourceList != "" { sourceList += "," } diff --git a/pkg/cmd/promote.go b/pkg/cmd/promote.go index b8197b5565..0a368b28de 100644 --- a/pkg/cmd/promote.go +++ b/pkg/cmd/promote.go @@ -21,18 +21,12 @@ import ( "context" "errors" "fmt" - "reflect" - "regexp" "strings" v1 "github.com/apache/camel-k/v2/pkg/apis/camel/v1" traitv1 "github.com/apache/camel-k/v2/pkg/apis/camel/v1/trait" "github.com/apache/camel-k/v2/pkg/client" - "github.com/apache/camel-k/v2/pkg/trait" - "github.com/apache/camel-k/v2/pkg/util/camel" - "github.com/apache/camel-k/v2/pkg/util/kamelets" "github.com/apache/camel-k/v2/pkg/util/kubernetes" - "github.com/apache/camel-k/v2/pkg/util/resource" "github.com/spf13/cobra" corev1 "k8s.io/api/core/v1" rbacv1 "k8s.io/api/rbac/v1" @@ -41,8 +35,6 @@ import ( k8sclient "sigs.k8s.io/controller-runtime/pkg/client" ) -var namedConfRegExp = regexp.MustCompile("([a-z0-9-.]+)/.*") - // newCmdPromote --. func newCmdPromote(rootCmdOptions *RootCmdOptions) (*cobra.Command, *promoteCmdOptions) { options := promoteCmdOptions{ @@ -129,7 +121,7 @@ func (o *promoteCmdOptions) run(cmd *cobra.Command, args []string) error { if sourceIntegration.Status.Phase != v1.IntegrationPhaseRunning { return fmt.Errorf("could not promote an Integration in %s status", sourceIntegration.Status.Phase) } - sourceKit, err := o.getIntegrationKit(c, sourceIntegration.Status.IntegrationKit.Name) + sourceKit, err := o.getIntegrationKit(c, sourceIntegration.Status.IntegrationKit) if err != nil { return err } @@ -139,14 +131,6 @@ func (o *promoteCmdOptions) run(cmd *cobra.Command, args []string) error { return nil } - if !o.isDryRun() { - // Skip these checks if in dry mode - err = o.validateDestResources(c, sourceIntegration) - if err != nil { - return fmt.Errorf("could not validate destination resources: %w", err) - } - } - // Pipe promotion if promotePipe { destPipe, destKit := o.editPipe(sourcePipe, sourceIntegration, sourceKit) @@ -248,11 +232,11 @@ func (o *promoteCmdOptions) getIntegration(c client.Client, name string) (*v1.In return &it, nil } -func (o *promoteCmdOptions) getIntegrationKit(c client.Client, name string) (*v1.IntegrationKit, error) { - ik := v1.NewIntegrationKit(o.Namespace, name) +func (o *promoteCmdOptions) getIntegrationKit(c client.Client, ref *corev1.ObjectReference) (*v1.IntegrationKit, error) { + ik := v1.NewIntegrationKit(ref.Namespace, ref.Name) key := k8sclient.ObjectKey{ - Name: name, - Namespace: o.Namespace, + Name: ref.Name, + Namespace: ref.Namespace, } if err := c.Get(o.Context, key, ik); err != nil { return nil, err @@ -261,241 +245,6 @@ func (o *promoteCmdOptions) getIntegrationKit(c client.Client, name string) (*v1 return ik, nil } -func (o *promoteCmdOptions) validateDestResources(c client.Client, it *v1.Integration) error { - var configmaps []string - var secrets []string - var pvcs []string - var kamelets []string - - // Mount trait - mount, err := toPropertyMap(it.Spec.Traits.Mount) - if err != nil { - return err - } - for t, v := range mount { - switch t { - case "configs": - list, ok := v.([]interface{}) - if !ok { - return fmt.Errorf("invalid %s type: %s, value: %s", t, reflect.TypeOf(v), v) - } - for _, cn := range list { - s, ok := cn.(string) - if !ok { - return fmt.Errorf("invalid %s type: %s, value: %s", t, reflect.TypeOf(cn), cn) - } - if conf, parseErr := resource.ParseConfig(s); parseErr == nil { - if conf.StorageType() == resource.StorageTypeConfigmap { - configmaps = append(configmaps, conf.Name()) - } else if conf.StorageType() == resource.StorageTypeSecret { - secrets = append(secrets, conf.Name()) - } - } else { - return parseErr - } - } - case "resources": - list, ok := v.([]interface{}) - if !ok { - return fmt.Errorf("invalid %s type: %s, value: %s", t, reflect.TypeOf(v), v) - } - for _, cn := range list { - s, ok := cn.(string) - if !ok { - return fmt.Errorf("invalid %s type: %s, value: %s", t, reflect.TypeOf(cn), cn) - } - if conf, parseErr := resource.ParseResource(s); parseErr == nil { - if conf.StorageType() == resource.StorageTypeConfigmap { - configmaps = append(configmaps, conf.Name()) - } else if conf.StorageType() == resource.StorageTypeSecret { - secrets = append(secrets, conf.Name()) - } - } else { - return parseErr - } - } - case "volumes": - list, ok := v.([]interface{}) - if !ok { - return fmt.Errorf("invalid %s type: %s, value: %s", t, reflect.TypeOf(v), v) - } - for _, cn := range list { - s, ok := cn.(string) - if !ok { - return fmt.Errorf("invalid %s type: %s, value: %s", t, reflect.TypeOf(cn), cn) - } - if conf, parseErr := resource.ParseVolume(s); parseErr == nil { - if conf.StorageType() == resource.StorageTypePVC { - pvcs = append(pvcs, conf.Name()) - } - } else { - return parseErr - } - } - } - } - - // OpenAPI trait - openapi, err := toPropertyMap(it.Spec.Traits.OpenAPI) - if err != nil { - return err - } - for k, v := range openapi { - if k != "configmaps" { - continue - } - if list, ok := v.([]string); ok { - configmaps = append(configmaps, list...) - break - } - } - - // Kamelets trait - kamelet, err := toPropertyMap(it.Spec.Traits.Kamelets) - if err != nil { - return err - } - if list, ok := kamelet["list"].(string); ok { - kamelets = strings.Split(list, ",") - } - sourceKamelets, err := o.listKamelets(c, it) - if err != nil { - return err - } - kamelets = append(kamelets, sourceKamelets...) - - anyError := false - var errorTrace string - for _, name := range configmaps { - if !existsCm(o.Context, c, name, o.To) { - anyError = true - errorTrace += fmt.Sprintf("\n\tConfigmap %s is missing from %s namespace", name, o.To) - } - } - for _, name := range secrets { - if !existsSecret(o.Context, c, name, o.To) { - anyError = true - errorTrace += fmt.Sprintf("\n\tSecret %s is missing from %s namespace", name, o.To) - } - } - for _, name := range pvcs { - if !existsPv(o.Context, c, name, o.To) { - anyError = true - errorTrace += fmt.Sprintf("\n\tPersistentVolume %s is missing from %s namespace", name, o.To) - } - } - for _, name := range kamelets { - if !existsKamelet(o.Context, c, name, o.To) { - anyError = true - errorTrace += fmt.Sprintf("\n\tKamelet %s is missing from %s namespace", name, o.To) - } - } - - if anyError { - return fmt.Errorf(errorTrace) - } - - return nil -} - -func toPropertyMap(src interface{}) (map[string]interface{}, error) { - propMap, err := trait.ToPropertyMap(src) - if err != nil { - return nil, err - } - // Migrate legacy configuration properties before promoting - if err := trait.MigrateLegacyConfiguration(propMap); err != nil { - return nil, err - } - - return propMap, nil -} - -func (o *promoteCmdOptions) listKamelets(c client.Client, it *v1.Integration) ([]string, error) { - runtime := v1.RuntimeSpec{ - Version: it.Status.RuntimeVersion, - Provider: v1.RuntimeProviderQuarkus, - } - catalog, err := camel.LoadCatalog(o.Context, c, o.Namespace, runtime) - if err != nil { - return nil, err - } - kamelets, err := kamelets.ExtractKameletFromSources(o.Context, c, catalog, &kubernetes.Collection{}, it) - if err != nil { - return nil, err - } - - var filtered []string - for _, k := range kamelets { - // We must remove any default source/sink - if k == "source" || k == "sink" { - continue - } - - // We must drop any named configurations - match := namedConfRegExp.FindStringSubmatch(k) - if len(match) > 0 { - filtered = append(filtered, match[1]) - } else { - filtered = append(filtered, k) - } - } - - return filtered, nil -} - -func existsCm(ctx context.Context, c client.Client, name string, namespace string) bool { - var obj corev1.ConfigMap - key := k8sclient.ObjectKey{ - Name: name, - Namespace: namespace, - } - if err := c.Get(ctx, key, &obj); err != nil { - return false - } - - return true -} - -func existsSecret(ctx context.Context, c client.Client, name string, namespace string) bool { - var obj corev1.Secret - key := k8sclient.ObjectKey{ - Name: name, - Namespace: namespace, - } - if err := c.Get(ctx, key, &obj); err != nil { - return false - } - - return true -} - -func existsPv(ctx context.Context, c client.Client, name string, namespace string) bool { - var obj corev1.PersistentVolume - key := k8sclient.ObjectKey{ - Name: name, - Namespace: namespace, - } - if err := c.Get(ctx, key, &obj); err != nil { - return false - } - - return true -} - -func existsKamelet(ctx context.Context, c client.Client, name string, namespace string) bool { - var obj v1.Kamelet - key := k8sclient.ObjectKey{ - Name: name, - Namespace: namespace, - } - if err := c.Get(ctx, key, &obj); err != nil { - return false - } - - return true -} - func (o *promoteCmdOptions) editIntegration(it *v1.Integration, kit *v1.IntegrationKit) (*v1.Integration, *v1.IntegrationKit) { contImage := it.Status.Image // IntegrationKit diff --git a/pkg/metadata/metadata.go b/pkg/metadata/metadata.go index 5d54795293..fed3124798 100644 --- a/pkg/metadata/metadata.go +++ b/pkg/metadata/metadata.go @@ -32,7 +32,7 @@ func ExtractAll(catalog *camel.RuntimeCatalog, sources []v1.SourceSpec) (Integra meta.ExposesHTTPServices = false for _, source := range sources { - m, err := Extract(catalog, source) + m, err := extract(catalog, source) if err != nil { return IntegrationMetadata{}, err } @@ -53,6 +53,10 @@ func merge(m1 src.Metadata, m2 src.Metadata) src.Metadata { t = append(t, m1.ToURIs...) t = append(t, m2.ToURIs...) + k := make([]string, 0, len(m1.Kamelets)+len(m2.Kamelets)) + k = append(k, m1.Kamelets...) + k = append(k, m2.Kamelets...) + return src.Metadata{ FromURIs: f, ToURIs: t, @@ -60,11 +64,12 @@ func merge(m1 src.Metadata, m2 src.Metadata) src.Metadata { RequiredCapabilities: sets.Union(m1.RequiredCapabilities, m2.RequiredCapabilities), ExposesHTTPServices: m1.ExposesHTTPServices || m2.ExposesHTTPServices, PassiveEndpoints: m1.PassiveEndpoints && m2.PassiveEndpoints, + Kamelets: k, } } -// Extract returns metadata information from the source code. -func Extract(catalog *camel.RuntimeCatalog, source v1.SourceSpec) (IntegrationMetadata, error) { +// extract returns metadata information from the source code. +func extract(catalog *camel.RuntimeCatalog, source v1.SourceSpec) (IntegrationMetadata, error) { if source.ContentRef != "" { panic("source must be dereferenced before calling this method") } @@ -86,19 +91,3 @@ func Extract(catalog *camel.RuntimeCatalog, source v1.SourceSpec) (IntegrationMe Metadata: meta, }, nil } - -// Each traverses the sources with the provided consumer function. -func Each(catalog *camel.RuntimeCatalog, sources []v1.SourceSpec, consumer func(int, IntegrationMetadata) bool) error { - for i, s := range sources { - meta, err := Extract(catalog, s) - if err != nil { - return err - } - - if !consumer(i, meta) { - break - } - } - - return nil -} diff --git a/pkg/metadata/metadata_capabilities_test.go b/pkg/metadata/metadata_capabilities_test.go index 6917e6ddb0..3ced17d233 100644 --- a/pkg/metadata/metadata_capabilities_test.go +++ b/pkg/metadata/metadata_capabilities_test.go @@ -39,7 +39,7 @@ func TestPlatformHttpCapabilities(t *testing.T) { catalog, err := camel.DefaultCatalog() require.NoError(t, err) - meta, err := Extract(catalog, code) + meta, err := extract(catalog, code) require.NoError(t, err) assert.ElementsMatch( diff --git a/pkg/metadata/metadata_dependencies_test.go b/pkg/metadata/metadata_dependencies_test.go index f4dd111f8a..762bc34f43 100644 --- a/pkg/metadata/metadata_dependencies_test.go +++ b/pkg/metadata/metadata_dependencies_test.go @@ -46,7 +46,7 @@ func TestDependenciesJavaSource(t *testing.T) { catalog, err := camel.DefaultCatalog() require.NoError(t, err) - meta, err := Extract(catalog, code) + meta, err := extract(catalog, code) require.NoError(t, err) assert.ElementsMatch( @@ -80,7 +80,7 @@ func TestDependenciesJavaScript(t *testing.T) { catalog, err := camel.DefaultCatalog() require.NoError(t, err) - meta, err := Extract(catalog, code) + meta, err := extract(catalog, code) require.NoError(t, err) assert.ElementsMatch( @@ -115,7 +115,7 @@ func TestDependenciesGroovy(t *testing.T) { catalog, err := camel.DefaultCatalog() require.NoError(t, err) - meta, err := Extract(catalog, code) + meta, err := extract(catalog, code) require.NoError(t, err) assert.ElementsMatch( @@ -147,7 +147,7 @@ func TestDependencies(t *testing.T) { catalog, err := camel.DefaultCatalog() require.NoError(t, err) - meta, err := Extract(catalog, code) + meta, err := extract(catalog, code) require.NoError(t, err) assert.ElementsMatch(t, @@ -177,7 +177,7 @@ func TestDependencyInexistent(t *testing.T) { catalog, err := camel.DefaultCatalog() require.NoError(t, err) - _, err = Extract(catalog, code) + _, err = extract(catalog, code) require.Error(t, err) } @@ -202,7 +202,7 @@ func TestDependenciesQuarkus(t *testing.T) { require.NoError(t, err) assert.NotNil(t, catalog) - meta, err := Extract(catalog, code) + meta, err := extract(catalog, code) require.NoError(t, err) assert.ElementsMatch(t, @@ -233,7 +233,7 @@ func TestJacksonDependency(t *testing.T) { catalog, err := camel.DefaultCatalog() require.NoError(t, err) - meta, err := Extract(catalog, code) + meta, err := extract(catalog, code) require.NoError(t, err) assert.ElementsMatch( @@ -262,7 +262,7 @@ func TestJacksonImplicitDependency(t *testing.T) { catalog, err := camel.DefaultCatalog() require.NoError(t, err) - meta, err := Extract(catalog, code) + meta, err := extract(catalog, code) require.NoError(t, err) assert.ElementsMatch( @@ -297,7 +297,7 @@ func TestLanguageDependencies(t *testing.T) { catalog, err := camel.DefaultCatalog() require.NoError(t, err) - meta, err := Extract(catalog, code) + meta, err := extract(catalog, code) require.NoError(t, err) assert.ElementsMatch( t, @@ -332,7 +332,7 @@ func TestLanguageDependenciesTransformExpression(t *testing.T) { catalog, err := camel.DefaultCatalog() require.NoError(t, err) - meta, err := Extract(catalog, code) + meta, err := extract(catalog, code) require.NoError(t, err) assert.ElementsMatch( t, @@ -363,7 +363,7 @@ func TestCircuitBreakerDependency(t *testing.T) { catalog, err := camel.DefaultCatalog() require.NoError(t, err) - meta, err := Extract(catalog, code) + meta, err := extract(catalog, code) require.NoError(t, err) assert.ElementsMatch(t, @@ -394,7 +394,7 @@ func TestRestDependency(t *testing.T) { catalog, err := camel.DefaultCatalog() require.NoError(t, err) - meta, err := Extract(catalog, code) + meta, err := extract(catalog, code) require.NoError(t, err) assert.ElementsMatch( @@ -427,7 +427,7 @@ func TestRestWithPathDependency(t *testing.T) { catalog, err := camel.DefaultCatalog() require.NoError(t, err) - meta, err := Extract(catalog, code) + meta, err := extract(catalog, code) require.NoError(t, err) assert.ElementsMatch( @@ -458,7 +458,7 @@ func TestRestConfigurationDependency(t *testing.T) { catalog, err := camel.DefaultCatalog() require.NoError(t, err) - meta, err := Extract(catalog, code) + meta, err := extract(catalog, code) require.NoError(t, err) assert.ElementsMatch( @@ -488,7 +488,7 @@ func TestRestClosureDependencyGroovy(t *testing.T) { catalog, err := camel.DefaultCatalog() require.NoError(t, err) - meta, err := Extract(catalog, code) + meta, err := extract(catalog, code) require.NoError(t, err) assert.ElementsMatch( @@ -519,7 +519,7 @@ func TestRestClosureDependencyKotlin(t *testing.T) { catalog, err := camel.DefaultCatalog() require.NoError(t, err) - meta, err := Extract(catalog, code) + meta, err := extract(catalog, code) require.NoError(t, err) assert.ElementsMatch( @@ -554,7 +554,7 @@ func TestXMLCircuitBreakerDependency(t *testing.T) { catalog, err := camel.DefaultCatalog() require.NoError(t, err) - meta, err := Extract(catalog, code) + meta, err := extract(catalog, code) require.NoError(t, err) assert.ElementsMatch( @@ -594,7 +594,7 @@ func TestXMLRestDependency(t *testing.T) { catalog, err := camel.DefaultCatalog() require.NoError(t, err) - meta, err := Extract(catalog, code) + meta, err := extract(catalog, code) require.NoError(t, err) assert.ElementsMatch( @@ -652,7 +652,7 @@ func TestXMLLanguageDependencies(t *testing.T) { catalog, err := camel.DefaultCatalog() require.NoError(t, err) - meta, err := Extract(catalog, code) + meta, err := extract(catalog, code) require.NoError(t, err) assert.ElementsMatch( t, @@ -724,7 +724,7 @@ func TestYAMLRestDependency(t *testing.T) { catalog, err := camel.DefaultCatalog() require.NoError(t, err) - meta, err := Extract(catalog, code) + meta, err := extract(catalog, code) require.NoError(t, err) assert.ElementsMatch( @@ -751,7 +751,7 @@ func TestYAMLCircuitBreakerDependency(t *testing.T) { catalog, err := camel.DefaultCatalog() require.NoError(t, err) - meta, err := Extract(catalog, code) + meta, err := extract(catalog, code) require.NoError(t, err) assert.ElementsMatch( @@ -775,7 +775,7 @@ func TestYAMLLanguageDependencies(t *testing.T) { catalog, err := camel.DefaultCatalog() require.NoError(t, err) - meta, err := Extract(catalog, code) + meta, err := extract(catalog, code) require.NoError(t, err) assert.ElementsMatch( diff --git a/pkg/metadata/metadata_http_test.go b/pkg/metadata/metadata_http_test.go index 7f095105ac..07d563a976 100644 --- a/pkg/metadata/metadata_http_test.go +++ b/pkg/metadata/metadata_http_test.go @@ -42,7 +42,7 @@ func TestHttpJavaSource(t *testing.T) { catalog, err := camel.DefaultCatalog() require.NoError(t, err) - meta, err := Extract(catalog, code) + meta, err := extract(catalog, code) require.NoError(t, err) assert.True(t, meta.ExposesHTTPServices) @@ -67,7 +67,7 @@ func TestHttpOnlyJavaSource(t *testing.T) { catalog, err := camel.DefaultCatalog() require.NoError(t, err) - meta, err := Extract(catalog, code) + meta, err := extract(catalog, code) require.NoError(t, err) assert.True(t, meta.ExposesHTTPServices) @@ -89,7 +89,7 @@ func TestHttpOnlyJavaSourceRest(t *testing.T) { catalog, err := camel.DefaultCatalog() require.NoError(t, err) - meta, err := Extract(catalog, code) + meta, err := extract(catalog, code) require.NoError(t, err) assert.True(t, meta.ExposesHTTPServices) @@ -111,7 +111,7 @@ func TestHttpOnlyJavaSourceRest2(t *testing.T) { catalog, err := camel.DefaultCatalog() require.NoError(t, err) - meta, err := Extract(catalog, code) + meta, err := extract(catalog, code) require.NoError(t, err) assert.True(t, meta.ExposesHTTPServices) @@ -134,7 +134,7 @@ func TestNoHttpGroovySource(t *testing.T) { catalog, err := camel.DefaultCatalog() require.NoError(t, err) - meta, err := Extract(catalog, code) + meta, err := extract(catalog, code) require.NoError(t, err) assert.False(t, meta.ExposesHTTPServices) @@ -157,7 +157,7 @@ func TestHttpOnlyGroovySource(t *testing.T) { catalog, err := camel.DefaultCatalog() require.NoError(t, err) - meta, err := Extract(catalog, code) + meta, err := extract(catalog, code) require.NoError(t, err) assert.True(t, meta.ExposesHTTPServices) @@ -180,7 +180,7 @@ func TestHttpXMLSource(t *testing.T) { catalog, err := camel.DefaultCatalog() require.NoError(t, err) - meta, err := Extract(catalog, code) + meta, err := extract(catalog, code) require.NoError(t, err) assert.True(t, meta.ExposesHTTPServices) @@ -204,7 +204,7 @@ func TestHttpOnlyXMLSource(t *testing.T) { catalog, err := camel.DefaultCatalog() require.NoError(t, err) - meta, err := Extract(catalog, code) + meta, err := extract(catalog, code) require.NoError(t, err) assert.True(t, meta.ExposesHTTPServices) diff --git a/pkg/metadata/metadata_uri_test.go b/pkg/metadata/metadata_uri_test.go index a876f6b605..8ac841334e 100644 --- a/pkg/metadata/metadata_uri_test.go +++ b/pkg/metadata/metadata_uri_test.go @@ -50,7 +50,7 @@ func TestJava1(t *testing.T) { catalog, err := camel.DefaultCatalog() require.NoError(t, err) - metadata, err := Extract(catalog, source) + metadata, err := extract(catalog, source) require.NoError(t, err) assert.Contains(t, metadata.FromURIs, "timer:tick") @@ -88,7 +88,7 @@ func TestJava2(t *testing.T) { catalog, err := camel.DefaultCatalog() require.NoError(t, err) - metadata, err := Extract(catalog, source) + metadata, err := extract(catalog, source) require.NoError(t, err) assert.Contains(t, metadata.FromURIs, "timer:tick") @@ -121,7 +121,7 @@ func TestGroovy1(t *testing.T) { catalog, err := camel.DefaultCatalog() require.NoError(t, err) - metadata, err := Extract(catalog, source) + metadata, err := extract(catalog, source) require.NoError(t, err) assert.Contains(t, metadata.FromURIs, "timer:tick") @@ -152,7 +152,7 @@ func TestGroovy2(t *testing.T) { catalog, err := camel.DefaultCatalog() require.NoError(t, err) - metadata, err := Extract(catalog, source) + metadata, err := extract(catalog, source) require.NoError(t, err) assert.Empty(t, metadata.FromURIs) @@ -188,7 +188,7 @@ func TestXml1(t *testing.T) { catalog, err := camel.DefaultCatalog() require.NoError(t, err) - metadata, err := Extract(catalog, source) + metadata, err := extract(catalog, source) require.NoError(t, err) assert.Contains(t, metadata.FromURIs, "timer:hello?period=3000") @@ -223,7 +223,7 @@ func TestKotlin1(t *testing.T) { catalog, err := camel.DefaultCatalog() require.NoError(t, err) - metadata, err := Extract(catalog, source) + metadata, err := extract(catalog, source) require.NoError(t, err) assert.Contains(t, metadata.FromURIs, "timer:tick") @@ -255,7 +255,7 @@ func TestJavascript1(t *testing.T) { catalog, err := camel.DefaultCatalog() require.NoError(t, err) - metadata, err := Extract(catalog, source) + metadata, err := extract(catalog, source) require.NoError(t, err) assert.Empty(t, metadata.FromURIs) @@ -292,7 +292,7 @@ func TestJYaml(t *testing.T) { catalog, err := camel.DefaultCatalog() require.NoError(t, err) - metadata, err := Extract(catalog, source) + metadata, err := extract(catalog, source) require.NoError(t, err) assert.NotEmpty(t, metadata.FromURIs) diff --git a/pkg/trait/container.go b/pkg/trait/container.go index bfe098e7cb..4b4c059443 100644 --- a/pkg/trait/container.go +++ b/pkg/trait/container.go @@ -18,7 +18,6 @@ limitations under the License. package trait import ( - "errors" "fmt" "path/filepath" @@ -37,7 +36,6 @@ import ( "github.com/apache/camel-k/v2/pkg/util/defaults" "github.com/apache/camel-k/v2/pkg/util/digest" "github.com/apache/camel-k/v2/pkg/util/envvar" - "github.com/apache/camel-k/v2/pkg/util/knative" "github.com/apache/camel-k/v2/pkg/util/kubernetes" "github.com/apache/camel-k/v2/pkg/util/openshift" ) @@ -95,27 +93,6 @@ func (t *containerTrait) Configure(e *Environment) (bool, *TraitCondition, error return false, nil, nil } - knativeInstalled, _ := knative.IsEventingInstalled(e.Client) - if e.IntegrationInPhase(v1.IntegrationPhaseInitialization) && !knativeInstalled { - hasKnativeEndpoint, err := containsEndpoint("knative", e, t.Client) - if err != nil { - return false, nil, err - } - - if hasKnativeEndpoint { - // fail fast the integration as there is no knative installed in the cluster - t.L.ForIntegration(e.Integration).Infof("Integration %s/%s contains knative endpoint that cannot run, as knative is not installed in the cluster.", e.Integration.Namespace, e.Integration.Name) - err := errors.New("integration cannot run, as knative is not installed in the cluster") - return false, NewIntegrationCondition( - "Container", - v1.IntegrationConditionKnativeAvailable, - corev1.ConditionFalse, - v1.IntegrationConditionKnativeNotInstalledReason, - err.Error(), - ), err - } - } - if ptr.Deref(t.Auto, true) { if t.Expose == nil { e := e.Resources.GetServiceForIntegration(e.Integration) != nil diff --git a/pkg/trait/container_test.go b/pkg/trait/container_test.go index 0e208dcb5a..604b25d9d3 100644 --- a/pkg/trait/container_test.go +++ b/pkg/trait/container_test.go @@ -437,98 +437,6 @@ func TestContainerWithImagePullPolicy(t *testing.T) { assert.Equal(t, corev1.PullAlways, container.ImagePullPolicy) } -func TestRunKnativeEndpointWithKnativeNotInstalled(t *testing.T) { - environment := createEnvironment() - trait, _ := newContainerTrait().(*containerTrait) - environment.Integration.Spec.Sources = []v1.SourceSpec{ - { - DataSpec: v1.DataSpec{ - Name: "test.java", - Content: ` - from("knative:channel/test").to("log:${body}; - `, - }, - Language: v1.LanguageJavaSource, - }, - } - expectedCondition := NewIntegrationCondition( - "Container", - v1.IntegrationConditionKnativeAvailable, - corev1.ConditionFalse, - v1.IntegrationConditionKnativeNotInstalledReason, - "integration cannot run, as knative is not installed in the cluster", - ) - configured, condition, err := trait.Configure(environment) - require.Error(t, err) - assert.Equal(t, expectedCondition, condition) - assert.False(t, configured) -} - -func TestRunNonKnativeEndpointWithKnativeNotInstalled(t *testing.T) { - environment := createEnvironment() - trait, _ := newContainerTrait().(*containerTrait) - environment.Integration.Spec.Sources = []v1.SourceSpec{ - { - DataSpec: v1.DataSpec{ - Name: "test.java", - Content: ` - from("platform-http://my-site").to("log:${body}"); - `, - }, - Language: v1.LanguageJavaSource, - }, - } - - configured, condition, err := trait.Configure(environment) - require.NoError(t, err) - assert.Nil(t, condition) - assert.True(t, configured) - conditions := environment.Integration.Status.Conditions - assert.Empty(t, conditions) -} - -func createEnvironment() *Environment { - client, _ := test.NewFakeClient() - // disable the knative eventing api - fakeClient := client.(*test.FakeClient) //nolint - fakeClient.DisableAPIGroupDiscovery("eventing.knative.dev/v1") - - replicas := int32(3) - catalog, _ := camel.QuarkusCatalog() - - environment := &Environment{ - CamelCatalog: catalog, - Catalog: NewCatalog(nil), - Client: client, - Integration: &v1.Integration{ - ObjectMeta: metav1.ObjectMeta{ - Name: "integration-name", - }, - Spec: v1.IntegrationSpec{ - Replicas: &replicas, - Traits: v1.Traits{}, - }, - Status: v1.IntegrationStatus{ - Phase: v1.IntegrationPhaseInitialization, - }, - }, - Platform: &v1.IntegrationPlatform{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: "namespace", - }, - Spec: v1.IntegrationPlatformSpec{ - Cluster: v1.IntegrationPlatformClusterKubernetes, - Profile: v1.TraitProfileKubernetes, - }, - }, - Resources: kubernetes.NewCollection(), - ApplicationProperties: make(map[string]string), - } - environment.Platform.ResyncStatusFullConfig() - - return environment -} - func TestDeploymentContainerPorts(t *testing.T) { catalog, err := camel.DefaultCatalog() require.NoError(t, err) @@ -683,6 +591,11 @@ func TestDefaultKubernetesSecurityContext(t *testing.T) { func TestDefaultKnativeSecurityContext(t *testing.T) { environment := createSettingContextEnvironment(t, v1.TraitProfileKnative) + environment.Integration.Spec.Traits.KnativeService = &traitv1.KnativeServiceTrait{ + Trait: traitv1.Trait{ + Enabled: ptr.To(true), + }, + } traitCatalog := NewCatalog(nil) conditions, err := traitCatalog.apply(environment) diff --git a/pkg/trait/cron.go b/pkg/trait/cron.go index 9b7364bee1..55945f132a 100644 --- a/pkg/trait/cron.go +++ b/pkg/trait/cron.go @@ -32,7 +32,6 @@ import ( traitv1 "github.com/apache/camel-k/v2/pkg/apis/camel/v1/trait" "github.com/apache/camel-k/v2/pkg/metadata" "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/uri" ) @@ -356,17 +355,16 @@ func (t *cronTrait) getGlobalCron(e *Environment) (*cronInfo, error) { } func (t *cronTrait) getSourcesFromURIs(e *Environment) ([]string, error) { - var sources []v1.SourceSpec - var err error - if sources, err = kubernetes.ResolveIntegrationSources(e.Ctx, t.Client, e.Integration, e.Resources); err != nil { - return nil, err - } - meta, err := metadata.ExtractAll(e.CamelCatalog, sources) + var fromUris []string + _, err := e.ConsumeMeta(func(meta metadata.IntegrationMetadata) bool { + fromUris = meta.FromURIs + return true + }) if err != nil { return nil, err } - return meta.FromURIs, nil + return fromUris, nil } func getCronForURIs(camelURIs []string) *cronInfo { diff --git a/pkg/trait/dependencies.go b/pkg/trait/dependencies.go index b598f12931..187e3bc265 100644 --- a/pkg/trait/dependencies.go +++ b/pkg/trait/dependencies.go @@ -23,7 +23,6 @@ import ( "github.com/apache/camel-k/v2/pkg/metadata" "github.com/apache/camel-k/v2/pkg/util" "github.com/apache/camel-k/v2/pkg/util/camel" - "github.com/apache/camel-k/v2/pkg/util/kubernetes" "github.com/apache/camel-k/v2/pkg/util/sets" ) @@ -72,26 +71,25 @@ func (t *dependenciesTrait) Apply(e *Environment) error { dependencies.Add(d.GetDependencyID()) } - sources, err := kubernetes.ResolveIntegrationSources(e.Ctx, e.Client, e.Integration, e.Resources) - if err != nil { - return err - } - for _, s := range sources { - // Add source-related dependencies - srcDeps, err := ExtractSourceDependencies(s, e.CamelCatalog) - if err != nil { - return err - } - dependencies.Merge(srcDeps) - - meta, err := metadata.Extract(e.CamelCatalog, s) - if err != nil { - return err - } - meta.RequiredCapabilities.Each(func(item string) bool { - util.StringSliceUniqueAdd(&e.Integration.Status.Capabilities, item) + _, err := e.consumeSourcesMeta( + func(sources []v1.SourceSpec) bool { + for _, s := range sources { + // Add source-related language dependencies + srcDeps := ExtractSourceLoaderDependencies(s, e.CamelCatalog) + dependencies.Merge(srcDeps) + } + return true + }, + func(meta metadata.IntegrationMetadata) bool { + dependencies.Merge(meta.Dependencies) + meta.RequiredCapabilities.Each(func(item string) bool { + util.StringSliceUniqueAdd(&e.Integration.Status.Capabilities, item) + return true + }) return true }) + if err != nil { + return err } // Add dependencies back to integration diff --git a/pkg/trait/kamelets.go b/pkg/trait/kamelets.go index a67570b7de..936770b6d6 100644 --- a/pkg/trait/kamelets.go +++ b/pkg/trait/kamelets.go @@ -32,13 +32,14 @@ import ( v1 "github.com/apache/camel-k/v2/pkg/apis/camel/v1" traitv1 "github.com/apache/camel-k/v2/pkg/apis/camel/v1/trait" "github.com/apache/camel-k/v2/pkg/kamelet/repository" + "github.com/apache/camel-k/v2/pkg/metadata" "github.com/apache/camel-k/v2/pkg/platform" "github.com/apache/camel-k/v2/pkg/util" "github.com/apache/camel-k/v2/pkg/util/boolean" "github.com/apache/camel-k/v2/pkg/util/camel" "github.com/apache/camel-k/v2/pkg/util/digest" "github.com/apache/camel-k/v2/pkg/util/dsl" - "github.com/apache/camel-k/v2/pkg/util/kamelets" + "github.com/apache/camel-k/v2/pkg/util/source" ) const ( @@ -82,11 +83,19 @@ func (t *kameletsTrait) Configure(e *Environment) (bool, *TraitCondition, error) // user has to specify forcefully auto=false option and pass a list of kamelets explicitly return false, NewIntegrationConditionPlatformDisabledCatalogMissing(), nil } - kamelets, err := kamelets.ExtractKameletFromSources(e.Ctx, e.Client, e.CamelCatalog, e.Resources, e.Integration) + var kamelets []string + _, err := e.ConsumeMeta(func(meta metadata.IntegrationMetadata) bool { + util.StringSliceUniqueConcat(&kamelets, meta.Kamelets) + return true + }) if err != nil { return false, nil, err } - + // Check if a Kamelet is configured as default error handler URI + defaultErrorHandlerURI := e.Integration.Spec.GetConfigurationProperty(v1.ErrorHandlerAppPropertiesPrefix + ".deadLetterUri") + if defaultErrorHandlerURI != "" && strings.HasPrefix(defaultErrorHandlerURI, "kamelet:") { + kamelets = append(kamelets, source.ExtractKamelet(defaultErrorHandlerURI)) + } if len(kamelets) > 0 { sort.Strings(kamelets) t.List = strings.Join(kamelets, ",") diff --git a/pkg/trait/knative.go b/pkg/trait/knative.go index 677cf2f4d1..de24fc9aa5 100644 --- a/pkg/trait/knative.go +++ b/pkg/trait/knative.go @@ -42,9 +42,7 @@ import ( traitv1 "github.com/apache/camel-k/v2/pkg/apis/camel/v1/trait" "github.com/apache/camel-k/v2/pkg/metadata" "github.com/apache/camel-k/v2/pkg/util" - "github.com/apache/camel-k/v2/pkg/util/camel" knativeutil "github.com/apache/camel-k/v2/pkg/util/knative" - "github.com/apache/camel-k/v2/pkg/util/kubernetes" ) const ( @@ -79,10 +77,7 @@ func (t *knativeTrait) Configure(e *Environment) (bool, *TraitCondition, error) return false, NewIntegrationConditionUserDisabled("Knative"), 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 + if ptr.Deref(t.Enabled, false) { return true, nil, nil } return false, NewIntegrationConditionPlatformDisabledCatalogMissing(), nil @@ -90,61 +85,64 @@ func (t *knativeTrait) Configure(e *Environment) (bool, *TraitCondition, error) if !e.IntegrationInPhase(v1.IntegrationPhaseInitialization) && !e.IntegrationInRunningPhases() { return false, nil, nil } - if !ptr.Deref(t.Auto, true) { - return true, nil, nil - } - sources, err := kubernetes.ResolveIntegrationSources(e.Ctx, e.Client, e.Integration, e.Resources) + knativeInstalled, err := knativeutil.IsEventingInstalled(e.Client) if err != nil { return false, nil, err } - if len(t.ChannelSources) == 0 { - items, err := filterMetaItems(e.CamelCatalog, sources, knativeapi.CamelServiceTypeChannel, "from") - if err != nil { - return false, nil, err + + if !ptr.Deref(t.Auto, true) { + if !knativeInstalled { + return false, NewIntegrationCondition( + "Knative", + v1.IntegrationConditionKnativeAvailable, + corev1.ConditionFalse, + v1.IntegrationConditionKnativeNotInstalledReason, + "integration cannot run. Knative is not installed in the cluster", + ), fmt.Errorf("integration cannot run. Knative is not installed in the cluster") } - t.ChannelSources = items + return true, nil, nil } - if len(t.ChannelSinks) == 0 { - items, err := filterMetaItems(e.CamelCatalog, sources, knativeapi.CamelServiceTypeChannel, "to") - if err != nil { - return false, nil, err + + _, err = e.ConsumeMeta(func(meta metadata.IntegrationMetadata) bool { + if len(t.ChannelSources) == 0 { + t.ChannelSources = filterMetaItems(meta, knativeapi.CamelServiceTypeChannel, "from") } - t.ChannelSinks = items - } - if len(t.EndpointSources) == 0 { - items, err := filterMetaItems(e.CamelCatalog, sources, knativeapi.CamelServiceTypeEndpoint, "from") - if err != nil { - return false, nil, err + if len(t.ChannelSinks) == 0 { + t.ChannelSinks = filterMetaItems(meta, knativeapi.CamelServiceTypeChannel, "to") } - t.EndpointSources = items - } - if len(t.EndpointSinks) == 0 { - items, err := filterMetaItems(e.CamelCatalog, sources, knativeapi.CamelServiceTypeEndpoint, "to") - if err != nil { - return false, nil, err + if len(t.EndpointSources) == 0 { + t.EndpointSources = filterMetaItems(meta, knativeapi.CamelServiceTypeEndpoint, "from") } - t.EndpointSinks = items - } - if len(t.EventSources) == 0 { - items, err := filterMetaItems(e.CamelCatalog, sources, knativeapi.CamelServiceTypeEvent, "from") - if err != nil { - return false, nil, err + if len(t.EndpointSinks) == 0 { + t.EndpointSinks = filterMetaItems(meta, knativeapi.CamelServiceTypeEndpoint, "to") } - t.EventSources = items - } - if len(t.EventSinks) == 0 { - items, err := filterMetaItems(e.CamelCatalog, sources, knativeapi.CamelServiceTypeEvent, "to") - if err != nil { - return false, nil, err + if len(t.EventSources) == 0 { + t.EventSources = filterMetaItems(meta, knativeapi.CamelServiceTypeEvent, "from") + } + if len(t.EventSinks) == 0 { + t.EventSinks = filterMetaItems(meta, knativeapi.CamelServiceTypeEvent, "to") } - t.EventSinks = items + return true + }) + if err != nil { + return false, nil, err } + hasKnativeEndpoint := len(t.ChannelSources) > 0 || len(t.ChannelSinks) > 0 || len(t.EndpointSources) > 0 || len(t.EndpointSinks) > 0 || len(t.EventSources) > 0 || len(t.EventSinks) > 0 t.Enabled = &hasKnativeEndpoint if !hasKnativeEndpoint { return false, nil, nil } + if !knativeInstalled { + return false, NewIntegrationCondition( + "Knative", + v1.IntegrationConditionKnativeAvailable, + corev1.ConditionFalse, + v1.IntegrationConditionKnativeNotInstalledReason, + "integration cannot run. Knative is not installed in the cluster", + ), fmt.Errorf("integration cannot run. Knative is not installed in the cluster") + } if t.FilterSourceChannels == nil { // Filtering is no longer used by default t.FilterSourceChannels = ptr.To(false) @@ -157,42 +155,29 @@ func (t *knativeTrait) Configure(e *Environment) (bool, *TraitCondition, error) return true, nil, nil } -// This is true only when the user set the enabled flag on and the auto flag off. -func (t *knativeTrait) isForcefullyEnabled() bool { - return ptr.Deref(t.Enabled, false) && !ptr.Deref(t.Auto, true) -} - -func filterMetaItems(catalog *camel.RuntimeCatalog, sources []v1.SourceSpec, cst knativeapi.CamelServiceType, uriType string) ([]string, error) { +func filterMetaItems(meta metadata.IntegrationMetadata, cst knativeapi.CamelServiceType, uriType string) []string { items := make([]string, 0) - if err := metadata.Each(catalog, sources, func(_ int, meta metadata.IntegrationMetadata) bool { - var uris []string - if uriType == "from" { - uris = meta.FromURIs - } else if uriType == "to" { - uris = meta.ToURIs - } - items = append(items, knativeutil.FilterURIs(uris, cst)...) - return true - }); err != nil { - return nil, err + var uris []string + if uriType == "from" { + uris = meta.FromURIs + } else if uriType == "to" { + uris = meta.ToURIs } - + items = append(items, knativeutil.FilterURIs(uris, cst)...) sort.Strings(items) - return items, nil + return items } func (t *knativeTrait) Apply(e *Environment) error { if e.IntegrationInPhase(v1.IntegrationPhaseInitialization) { util.StringSliceUniqueAdd(&e.Integration.Status.Capabilities, v1.CapabilityKnative) } - if len(t.ChannelSources) > 0 || len(t.EndpointSources) > 0 || len(t.EventSources) > 0 { util.StringSliceUniqueAdd(&e.Integration.Status.Capabilities, v1.CapabilityPlatformHTTP) } if len(t.ChannelSinks) > 0 || len(t.EndpointSinks) > 0 || len(t.EventSinks) > 0 { util.StringSliceUniqueAdd(&e.Integration.Status.Capabilities, v1.CapabilityPlatformHTTP) } - if !e.IntegrationInRunningPhases() { return nil } diff --git a/pkg/trait/knative_service.go b/pkg/trait/knative_service.go index fab0b05a7b..3d55db707a 100644 --- a/pkg/trait/knative_service.go +++ b/pkg/trait/knative_service.go @@ -32,7 +32,6 @@ import ( "github.com/apache/camel-k/v2/pkg/metadata" "github.com/apache/camel-k/v2/pkg/util/boolean" "github.com/apache/camel-k/v2/pkg/util/knative" - "github.com/apache/camel-k/v2/pkg/util/kubernetes" ) const ( @@ -152,49 +151,34 @@ func (t *knativeServiceTrait) SelectControllerStrategy(e *Environment) (*Control // 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. + if ptr.Deref(t.Enabled, false) { // 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") } + // Fallback to other strategies otherwise 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 + controllerStrategy := ControllerStrategyKnativeService + if ptr.Deref(t.Enabled, false) { + return &controllerStrategy, nil } - var sources []v1.SourceSpec - var err error - if sources, err = kubernetes.ResolveIntegrationSources(e.Ctx, t.Client, e.Integration, e.Resources); err != nil { - return nil, err - } - - meta, err := metadata.ExtractAll(e.CamelCatalog, sources) + enabled, err := e.ConsumeMeta(func(meta metadata.IntegrationMetadata) bool { + return meta.ExposesHTTPServices || meta.PassiveEndpoints + }) if err != nil { return nil, err } - if meta.ExposesHTTPServices || meta.PassiveEndpoints { - knativeServiceStrategy := ControllerStrategyKnativeService - return &knativeServiceStrategy, nil + if enabled { + controllerStrategy := ControllerStrategyKnativeService + return &controllerStrategy, nil } - 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 ptr.Deref(t.Enabled, false) && !ptr.Deref(t.Auto, true) + return nil, nil } func (t *knativeServiceTrait) ControllerStrategySelectorOrder() int { diff --git a/pkg/trait/knative_test.go b/pkg/trait/knative_test.go index cc5625bf1e..9aaadba604 100644 --- a/pkg/trait/knative_test.go +++ b/pkg/trait/knative_test.go @@ -44,11 +44,14 @@ import ( "github.com/apache/camel-k/v2/pkg/util/boolean" "github.com/apache/camel-k/v2/pkg/util/camel" "github.com/apache/camel-k/v2/pkg/util/knative" + "github.com/apache/camel-k/v2/pkg/util/kubernetes" k8sutils "github.com/apache/camel-k/v2/pkg/util/kubernetes" "github.com/apache/camel-k/v2/pkg/util/test" ) func TestKnativeEnvConfigurationFromTrait(t *testing.T) { + client, err := test.NewFakeClient() + require.NoError(t, err) catalog, err := camel.DefaultCatalog() require.NoError(t, err) @@ -57,6 +60,7 @@ func TestKnativeEnvConfigurationFromTrait(t *testing.T) { environment := Environment{ CamelCatalog: catalog, Catalog: traitCatalog, + Client: client, Integration: &v1.Integration{ ObjectMeta: metav1.ObjectMeta{ Name: "test", @@ -160,6 +164,8 @@ func TestKnativeEnvConfigurationFromTrait(t *testing.T) { } func TestKnativeEnvConfigurationFromSource(t *testing.T) { + client, err := test.NewFakeClient() + require.NoError(t, err) catalog, err := camel.DefaultCatalog() require.NoError(t, err) @@ -168,6 +174,7 @@ func TestKnativeEnvConfigurationFromSource(t *testing.T) { environment := Environment{ CamelCatalog: catalog, Catalog: traitCatalog, + Client: client, Integration: &v1.Integration{ ObjectMeta: metav1.ObjectMeta{ Name: "test", @@ -1229,6 +1236,8 @@ func TestKnativePlatformHttpDependencies(t *testing.T) { } func TestKnativeEnabled(t *testing.T) { + client, err := test.NewFakeClient() + require.NoError(t, err) catalog, err := camel.DefaultCatalog() require.NoError(t, err) @@ -1237,6 +1246,7 @@ func TestKnativeEnabled(t *testing.T) { environment := Environment{ CamelCatalog: catalog, Catalog: traitCatalog, + Client: client, Integration: &v1.Integration{ ObjectMeta: metav1.ObjectMeta{ Name: "test", @@ -1299,6 +1309,8 @@ func TestKnativeEnabled(t *testing.T) { } func TestKnativeNotEnabled(t *testing.T) { + client, err := test.NewFakeClient() + require.NoError(t, err) catalog, err := camel.DefaultCatalog() require.NoError(t, err) @@ -1307,6 +1319,7 @@ func TestKnativeNotEnabled(t *testing.T) { environment := Environment{ CamelCatalog: catalog, Catalog: traitCatalog, + Client: client, Integration: &v1.Integration{ ObjectMeta: metav1.ObjectMeta{ Name: "test", @@ -1704,3 +1717,95 @@ func TestKnativeSyntheticKitEnabled(t *testing.T) { assert.True(t, ok) assert.Nil(t, condition) } + +func TestRunKnativeEndpointWithKnativeNotInstalled(t *testing.T) { + environment := createEnvironmentMissingEventingCRDs() + trait, _ := newKnativeTrait().(*knativeTrait) + environment.Integration.Spec.Sources = []v1.SourceSpec{ + { + DataSpec: v1.DataSpec{ + Name: "test.java", + Content: ` + from("knative:channel/test").to("log:${body}; + `, + }, + Language: v1.LanguageJavaSource, + }, + } + expectedCondition := NewIntegrationCondition( + "Knative", + v1.IntegrationConditionKnativeAvailable, + corev1.ConditionFalse, + v1.IntegrationConditionKnativeNotInstalledReason, + "integration cannot run. Knative is not installed in the cluster", + ) + configured, condition, err := trait.Configure(environment) + require.Error(t, err) + assert.Equal(t, expectedCondition, condition) + assert.False(t, configured) +} + +func TestRunNonKnativeEndpointWithKnativeNotInstalled(t *testing.T) { + environment := createEnvironmentMissingEventingCRDs() + trait, _ := newKnativeTrait().(*knativeTrait) + environment.Integration.Spec.Sources = []v1.SourceSpec{ + { + DataSpec: v1.DataSpec{ + Name: "test.java", + Content: ` + from("platform-http://my-site").to("log:${body}"); + `, + }, + Language: v1.LanguageJavaSource, + }, + } + + configured, condition, err := trait.Configure(environment) + require.NoError(t, err) + assert.Nil(t, condition) + assert.False(t, configured) + conditions := environment.Integration.Status.Conditions + assert.Empty(t, conditions) +} + +func createEnvironmentMissingEventingCRDs() *Environment { + client, _ := test.NewFakeClient() + // disable the knative eventing api + fakeClient := client.(*test.FakeClient) //nolint + fakeClient.DisableAPIGroupDiscovery("eventing.knative.dev/v1") + + replicas := int32(3) + catalog, _ := camel.QuarkusCatalog() + + environment := &Environment{ + CamelCatalog: catalog, + Catalog: NewCatalog(nil), + Client: client, + Integration: &v1.Integration{ + ObjectMeta: metav1.ObjectMeta{ + Name: "integration-name", + }, + Spec: v1.IntegrationSpec{ + Replicas: &replicas, + Traits: v1.Traits{}, + }, + Status: v1.IntegrationStatus{ + Phase: v1.IntegrationPhaseInitialization, + }, + }, + Platform: &v1.IntegrationPlatform{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "namespace", + }, + Spec: v1.IntegrationPlatformSpec{ + Cluster: v1.IntegrationPlatformClusterKubernetes, + Profile: v1.TraitProfileKubernetes, + }, + }, + Resources: kubernetes.NewCollection(), + ApplicationProperties: make(map[string]string), + } + environment.Platform.ResyncStatusFullConfig() + + return environment +} diff --git a/pkg/util/kubernetes/resolver.go b/pkg/trait/resolver.go similarity index 81% rename from pkg/util/kubernetes/resolver.go rename to pkg/trait/resolver.go index 8c61849c13..e750429866 100644 --- a/pkg/util/kubernetes/resolver.go +++ b/pkg/trait/resolver.go @@ -15,7 +15,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package kubernetes +package trait import ( "context" @@ -23,17 +23,18 @@ import ( v1 "github.com/apache/camel-k/v2/pkg/apis/camel/v1" "github.com/apache/camel-k/v2/pkg/util/gzip" + "github.com/apache/camel-k/v2/pkg/util/kubernetes" corev1 "k8s.io/api/core/v1" controller "sigs.k8s.io/controller-runtime/pkg/client" ) -// ResolveSources --. -func ResolveSources(elements []v1.SourceSpec, mapLookup func(string) (*corev1.ConfigMap, error)) ([]v1.SourceSpec, error) { +// resolveSources --. +func resolveSources(elements []v1.SourceSpec, mapLookup func(string) (*corev1.ConfigMap, error)) ([]v1.SourceSpec, error) { for i := range len(elements) { r := &elements[i] - if err := Resolve(&r.DataSpec, mapLookup); err != nil { + if err := resolve(&r.DataSpec, mapLookup); err != nil { return nil, err } } @@ -41,8 +42,8 @@ func ResolveSources(elements []v1.SourceSpec, mapLookup func(string) (*corev1.Co return elements, nil } -// Resolve --. -func Resolve(data *v1.DataSpec, mapLookup func(string) (*corev1.ConfigMap, error)) error { +// resolve --. +func resolve(data *v1.DataSpec, mapLookup func(string) (*corev1.ConfigMap, error)) error { // if it is a reference, get the content from the // referenced ConfigMap if data.ContentRef != "" { @@ -81,18 +82,18 @@ func Resolve(data *v1.DataSpec, mapLookup func(string) (*corev1.ConfigMap, error return nil } -// ResolveIntegrationSources --. -func ResolveIntegrationSources( +// resolveIntegrationSources --. +func resolveIntegrationSources( context context.Context, client controller.Reader, integration *v1.Integration, - resources *Collection) ([]v1.SourceSpec, error) { + resources *kubernetes.Collection) ([]v1.SourceSpec, error) { if integration == nil { return nil, nil } - return ResolveSources(integration.AllSources(), func(name string) (*corev1.ConfigMap, error) { + return resolveSources(integration.AllSources(), func(name string) (*corev1.ConfigMap, error) { // the config map could be part of the resources created // by traits cm := resources.GetConfigMap(func(m *corev1.ConfigMap) bool { @@ -103,6 +104,6 @@ func ResolveIntegrationSources( return cm, nil } - return GetConfigMap(context, client, name, integration.Namespace) + return kubernetes.GetConfigMap(context, client, name, integration.Namespace) }) } diff --git a/pkg/trait/security_context_test.go b/pkg/trait/security_context_test.go index 633177233b..9315657fa0 100644 --- a/pkg/trait/security_context_test.go +++ b/pkg/trait/security_context_test.go @@ -90,6 +90,11 @@ func TestDefaultPodOpenshiftSecurityContext(t *testing.T) { func TestDefaultPodKnativeSecurityContext(t *testing.T) { environment := createPodSettingContextEnvironment(t, v1.TraitProfileKnative) + environment.Integration.Spec.Traits.KnativeService = &traitv1.KnativeServiceTrait{ + Trait: traitv1.Trait{ + Enabled: ptr.To(true), + }, + } traitCatalog := NewCatalog(nil) conditions, err := traitCatalog.apply(environment) diff --git a/pkg/trait/service.go b/pkg/trait/service.go index 51859517f4..8ed0547003 100644 --- a/pkg/trait/service.go +++ b/pkg/trait/service.go @@ -27,7 +27,6 @@ import ( v1 "github.com/apache/camel-k/v2/pkg/apis/camel/v1" traitv1 "github.com/apache/camel-k/v2/pkg/apis/camel/v1/trait" "github.com/apache/camel-k/v2/pkg/metadata" - "github.com/apache/camel-k/v2/pkg/util/kubernetes" ) const ( @@ -76,7 +75,9 @@ func (t *serviceTrait) Configure(e *Environment) (bool, *TraitCondition, error) } if ptr.Deref(t.Auto, true) { - sources, err := kubernetes.ResolveIntegrationSources(e.Ctx, t.Client, e.Integration, e.Resources) + exposeHTTPServices, err := e.ConsumeMeta(func(meta metadata.IntegrationMetadata) bool { + return meta.ExposesHTTPServices + }) var condition *TraitCondition if err != nil { condition = NewIntegrationCondition( @@ -88,16 +89,10 @@ func (t *serviceTrait) Configure(e *Environment) (bool, *TraitCondition, error) ) return false, condition, err } - - meta, err := metadata.ExtractAll(e.CamelCatalog, sources) - if err != nil { - return false, nil, err - } - if !meta.ExposesHTTPServices { - return false, nil, nil - } + return exposeHTTPServices, nil, nil } - return true, nil, nil + + return ptr.Deref(t.Enabled, false), nil, nil } func (t *serviceTrait) Apply(e *Environment) error { diff --git a/pkg/trait/trait_types.go b/pkg/trait/trait_types.go index c4028faae5..7e95a88681 100644 --- a/pkg/trait/trait_types.go +++ b/pkg/trait/trait_types.go @@ -35,6 +35,7 @@ import ( 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/metadata" "github.com/apache/camel-k/v2/pkg/platform" "github.com/apache/camel-k/v2/pkg/util/boolean" "github.com/apache/camel-k/v2/pkg/util/camel" @@ -748,3 +749,37 @@ func CapabilityPropertyKey(camelPropertyKey string, vars map[string]string) stri } return camelPropertyKey } + +// ConsumeMeta is used to consume metadata information coming from Integration sources. If no sources available, +// would return false. +func (e *Environment) ConsumeMeta(consumeMeta func(metadata.IntegrationMetadata) bool) (bool, error) { + return e.consumeSourcesMeta(nil, consumeMeta) +} + +// consumeSourcesMeta is used to consume both sources and metadata information coming from Integration sources. +// If no sources available would return false. +func (e *Environment) consumeSourcesMeta( + consumeSources func(sources []v1.SourceSpec) bool, + consumeMeta func(metadata.IntegrationMetadata) bool) (bool, error) { + var sources []v1.SourceSpec + var err error + if sources, err = resolveIntegrationSources(e.Ctx, e.Client, e.Integration, e.Resources); err != nil { + return false, err + } + if len(sources) < 1 { + // No sources available + return false, nil + } + if consumeSources != nil { + consumeSources(sources) + } + if e.CamelCatalog == nil { + return false, fmt.Errorf("cannot extract metadata from sources. Camel Catalog is null") + } + meta, err := metadata.ExtractAll(e.CamelCatalog, sources) + if err != nil { + return false, err + } + + return consumeMeta(meta), nil +} diff --git a/pkg/trait/util.go b/pkg/trait/util.go index 1ed81bbc31..6a8083b59c 100644 --- a/pkg/trait/util.go +++ b/pkg/trait/util.go @@ -31,13 +31,10 @@ import ( 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/metadata" "github.com/apache/camel-k/v2/pkg/util" "github.com/apache/camel-k/v2/pkg/util/camel" - "github.com/apache/camel-k/v2/pkg/util/kubernetes" "github.com/apache/camel-k/v2/pkg/util/property" "github.com/apache/camel-k/v2/pkg/util/sets" - "github.com/apache/camel-k/v2/pkg/util/uri" ) func ptrFrom[T any](value T) *T { @@ -141,17 +138,9 @@ func filterTransferableAnnotations(annotations map[string]string) map[string]str return res } -// ExtractSourceDependencies extracts dependencies from source. -func ExtractSourceDependencies(source v1.SourceSpec, catalog *camel.RuntimeCatalog) (*sets.Set, error) { +// ExtractSourceLoaderDependencies extracts dependencies from source. +func ExtractSourceLoaderDependencies(source v1.SourceSpec, catalog *camel.RuntimeCatalog) *sets.Set { dependencies := sets.NewSet() - - // Add auto-detected dependencies - meta, err := metadata.Extract(catalog, source) - if err != nil { - return nil, err - } - dependencies.Merge(meta.Dependencies) - // Add loader dependencies lang := source.InferLanguage() for loader, v := range catalog.Loaders { @@ -174,7 +163,7 @@ func ExtractSourceDependencies(source v1.SourceSpec, catalog *camel.RuntimeCatal } } - return dependencies, nil + return dependencies } // AssertTraitsType asserts that traits is either v1.Traits or v1.IntegrationKitTraits. @@ -544,31 +533,6 @@ func NewTraitsOptionsForKameletBinding(c client.Client, kb *v1alpha1.KameletBind return newTraitsOptions(c, options, kb.ObjectMeta.Annotations) } -// verify if the integration in the Environment contains an endpoint. -func containsEndpoint(name string, e *Environment, c client.Client) (bool, error) { - sources, err := kubernetes.ResolveIntegrationSources(e.Ctx, c, e.Integration, e.Resources) - if err != nil { - return false, err - } - - meta, err := metadata.ExtractAll(e.CamelCatalog, sources) - if err != nil { - return false, err - } - - hasKnativeEndpoint := false - endpoints := make([]string, 0) - endpoints = append(endpoints, meta.FromURIs...) - endpoints = append(endpoints, meta.ToURIs...) - for _, endpoint := range endpoints { - if uri.GetComponent(endpoint) == name { - hasKnativeEndpoint = true - break - } - } - return hasKnativeEndpoint, nil -} - // HasMatchingTraits verifies if two traits options match. func HasMatchingTraits(traitMap Options, kitTraitMap Options) (bool, error) { catalog := NewCatalog(nil) diff --git a/pkg/util/kamelets/util.go b/pkg/util/kamelets/util.go deleted file mode 100644 index 839cbc10ee..0000000000 --- a/pkg/util/kamelets/util.go +++ /dev/null @@ -1,59 +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 kamelets - -import ( - "context" - "strings" - - 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/metadata" - "github.com/apache/camel-k/v2/pkg/util" - "github.com/apache/camel-k/v2/pkg/util/camel" - "github.com/apache/camel-k/v2/pkg/util/kubernetes" - "github.com/apache/camel-k/v2/pkg/util/source" -) - -// ExtractKameletFromSources provide a list of Kamelets referred into the Integration sources. -func ExtractKameletFromSources(context context.Context, c client.Client, catalog *camel.RuntimeCatalog, resources *kubernetes.Collection, it *v1.Integration) ([]string, error) { - var kamelets []string - - sources, err := kubernetes.ResolveIntegrationSources(context, c, it, resources) - if err != nil { - return nil, err - } - - if err := metadata.Each(catalog, sources, func(_ int, meta metadata.IntegrationMetadata) bool { - util.StringSliceUniqueConcat(&kamelets, meta.Kamelets) - return true - }); err != nil { - return nil, err - } - - // Check if a Kamelet is configured as default error handler URI - defaultErrorHandlerURI := it.Spec.GetConfigurationProperty(v1.ErrorHandlerAppPropertiesPrefix + ".deadLetterUri") - if defaultErrorHandlerURI != "" { - if strings.HasPrefix(defaultErrorHandlerURI, "kamelet:") { - kamelets = append(kamelets, source.ExtractKamelet(defaultErrorHandlerURI)) - } - } - - return kamelets, nil -} From 54f8734375549480bfa7c8bda1bc6c215a007a3b Mon Sep 17 00:00:00 2001 From: Pasquale Congiusti Date: Wed, 21 Aug 2024 11:35:54 +0200 Subject: [PATCH 2/4] feat(trait): operate via default catalog With this refactoring, we allow any trait to be executed with at least a default CamelCatalog. This is useful when we run sourceless where, from now on, we can pick the catalog used to operate, regardless if it's a managed Integration or not. --- .../ROOT/partials/apis/camel-k-crds.adoc | 47 +++++++++++++ helm/camel-k/crds/camel-k-crds.yaml | 22 ++++++ pkg/apis/camel/v1/common_types.go | 6 ++ pkg/apis/camel/v1/integration_types.go | 3 + pkg/apis/camel/v1/integrationkit_types.go | 2 + pkg/apis/camel/v1/zz_generated.deepcopy.go | 17 +++++ .../applyconfiguration/camel/v1/catalog.go | 53 +++++++++++++++ .../camel/v1/integrationkitstatus.go | 9 +++ .../camel/v1/integrationstatus.go | 9 +++ pkg/client/camel/applyconfiguration/utils.go | 2 + pkg/controller/integrationkit/initialize.go | 2 +- .../camel.apache.org_integrationkits.yaml | 9 +++ .../bases/camel.apache.org_integrations.yaml | 13 ++++ pkg/trait/camel.go | 67 ++++++++++++------- pkg/trait/camel_test.go | 39 +++++++++-- pkg/trait/logging_test.go | 8 +-- pkg/trait/trait_types.go | 5 +- pkg/trait/trait_types_test.go | 9 ++- 18 files changed, 281 insertions(+), 41 deletions(-) create mode 100644 pkg/client/camel/applyconfiguration/camel/v1/catalog.go diff --git a/docs/modules/ROOT/partials/apis/camel-k-crds.adoc b/docs/modules/ROOT/partials/apis/camel-k-crds.adoc index a2ce10971c..8fc12f3a23 100644 --- a/docs/modules/ROOT/partials/apis/camel-k-crds.adoc +++ b/docs/modules/ROOT/partials/apis/camel-k-crds.adoc @@ -1476,6 +1476,38 @@ map[string]string Set of generic metadata +|=== + +[#_camel_apache_org_v1_Catalog] +=== Catalog + +*Appears on:* + +* <<#_camel_apache_org_v1_IntegrationKitStatus, IntegrationKitStatus>> +* <<#_camel_apache_org_v1_IntegrationStatus, IntegrationStatus>> + +Catalog represents the Camel Catalog runtime specification. + +[cols="2,2a",options="header"] +|=== +|Field +|Description + +|`version` + +string +| + + + + +|`provider` + +*xref:#_camel_apache_org_v1_RuntimeProvider[RuntimeProvider]* +| + + + + + |=== [#_camel_apache_org_v1_Configurable] @@ -2648,6 +2680,13 @@ the runtime version for which this kit was configured the runtime provider for which this kit was configured +|`catalog` + +*xref:#_camel_apache_org_v1_Catalog[Catalog]* +| + + +the catalog used to build/operate the IntegrationKit. + |`platform` + string | @@ -3522,6 +3561,13 @@ the runtime version targeted for this Integration the runtime provider targeted for this Integration +|`catalog` + +*xref:#_camel_apache_org_v1_Catalog[Catalog]* +| + + +the catalog used to build/operate the Integration. + |`configuration` + *xref:#_camel_apache_org_v1_ConfigurationSpec[[\]ConfigurationSpec]* | @@ -5259,6 +5305,7 @@ ResourceCondition is a common type for all conditions. *Appears on:* +* <<#_camel_apache_org_v1_Catalog, Catalog>> * <<#_camel_apache_org_v1_IntegrationKitStatus, IntegrationKitStatus>> * <<#_camel_apache_org_v1_IntegrationPlatformBuildSpec, IntegrationPlatformBuildSpec>> * <<#_camel_apache_org_v1_IntegrationProfileBuildSpec, IntegrationProfileBuildSpec>> diff --git a/helm/camel-k/crds/camel-k-crds.yaml b/helm/camel-k/crds/camel-k-crds.yaml index 10f51c0fb9..548e5e2816 100644 --- a/helm/camel-k/crds/camel-k-crds.yaml +++ b/helm/camel-k/crds/camel-k-crds.yaml @@ -3057,6 +3057,15 @@ spec: baseImage: description: base image used by the kit (could be another IntegrationKit) type: string + catalog: + description: the catalog used to build/operate the IntegrationKit. + properties: + provider: + description: RuntimeProvider is the provider chosen for the runtime. + type: string + version: + type: string + type: object conditions: description: a list of conditions which happened for the events related the kit @@ -11397,6 +11406,10 @@ spec: jsonPath: .status.runtimeVersion name: Runtime Version type: string + - description: The catalog version + jsonPath: .status.catalog.version + name: Catalog Version + type: string - description: The integration kit jsonPath: .status.integrationKit.name name: Kit @@ -19374,6 +19387,15 @@ spec: items: type: string type: array + catalog: + description: the catalog used to build/operate the Integration. + properties: + provider: + description: RuntimeProvider is the provider chosen for the runtime. + type: string + version: + type: string + type: object conditions: description: a list of events happened for the Integration items: diff --git a/pkg/apis/camel/v1/common_types.go b/pkg/apis/camel/v1/common_types.go index ed4bb2af05..80466ab4c3 100644 --- a/pkg/apis/camel/v1/common_types.go +++ b/pkg/apis/camel/v1/common_types.go @@ -123,6 +123,12 @@ type ConfigurationSpec struct { Value string `json:"value"` } +// Catalog represents the Camel Catalog runtime specification. +type Catalog struct { + Version string `json:"version,omitempty" yaml:"version,omitempty"` + Provider RuntimeProvider `json:"provider,omitempty" yaml:"provider,omitempty"` +} + // Artifact represents a materialized artifact (a jar dependency or in general a file used by the build). type Artifact struct { // the identification (GAV for maven dependencies or file name for other file types) diff --git a/pkg/apis/camel/v1/integration_types.go b/pkg/apis/camel/v1/integration_types.go index 4ba8630528..a68533cda6 100644 --- a/pkg/apis/camel/v1/integration_types.go +++ b/pkg/apis/camel/v1/integration_types.go @@ -37,6 +37,7 @@ import ( // +kubebuilder:printcolumn:name="Ready",type=string,JSONPath=`.status.conditions[?(@.type=="Ready")].status`,description="The integration readiness" // +kubebuilder:printcolumn:name="Runtime Provider",type=string,JSONPath=`.status.runtimeProvider`,description="The runtime version" // +kubebuilder:printcolumn:name="Runtime Version",type=string,JSONPath=`.status.runtimeVersion`,description="The runtime provider" +// +kubebuilder:printcolumn:name="Catalog Version",type=string,JSONPath=`.status.catalog.version`,description="The catalog version" // +kubebuilder:printcolumn:name="Kit",type=string,JSONPath=`.status.integrationKit.name`,description="The integration kit" // +kubebuilder:printcolumn:name="Replicas",type=integer,JSONPath=`.status.replicas`,description="The number of pods" @@ -106,6 +107,8 @@ type IntegrationStatus struct { RuntimeVersion string `json:"runtimeVersion,omitempty"` // the runtime provider targeted for this Integration RuntimeProvider RuntimeProvider `json:"runtimeProvider,omitempty"` + // the catalog used to build/operate the Integration. + Catalog *Catalog `json:"catalog,omitempty"` // Deprecated: // a list of configuration specification Configuration []ConfigurationSpec `json:"configuration,omitempty"` diff --git a/pkg/apis/camel/v1/integrationkit_types.go b/pkg/apis/camel/v1/integrationkit_types.go index d6b6957934..3d2d703319 100644 --- a/pkg/apis/camel/v1/integrationkit_types.go +++ b/pkg/apis/camel/v1/integrationkit_types.go @@ -117,6 +117,8 @@ type IntegrationKitStatus struct { RuntimeVersion string `json:"runtimeVersion,omitempty"` // the runtime provider for which this kit was configured RuntimeProvider RuntimeProvider `json:"runtimeProvider,omitempty"` + // the catalog used to build/operate the IntegrationKit. + Catalog *Catalog `json:"catalog,omitempty"` // the platform for which this kit was configured Platform string `json:"platform,omitempty"` // the Camel K operator version for which this kit was configured diff --git a/pkg/apis/camel/v1/zz_generated.deepcopy.go b/pkg/apis/camel/v1/zz_generated.deepcopy.go index b3fb311675..8a5844fe1f 100644 --- a/pkg/apis/camel/v1/zz_generated.deepcopy.go +++ b/pkg/apis/camel/v1/zz_generated.deepcopy.go @@ -658,6 +658,21 @@ func (in *Capability) DeepCopy() *Capability { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Catalog) DeepCopyInto(out *Catalog) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Catalog. +func (in *Catalog) DeepCopy() *Catalog { + if in == nil { + return nil + } + out := new(Catalog) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ConfigurationSpec) DeepCopyInto(out *ConfigurationSpec) { *out = *in @@ -1314,6 +1329,7 @@ func (in *IntegrationKitStatus) DeepCopyInto(out *IntegrationKitStatus) { *out = new(Failure) (*in).DeepCopyInto(*out) } + out.Catalog = in.Catalog if in.Conditions != nil { in, out := &in.Conditions, &out.Conditions *out = make([]IntegrationKitCondition, len(*in)) @@ -1830,6 +1846,7 @@ func (in *IntegrationStatus) DeepCopyInto(out *IntegrationStatus) { (*in)[i].DeepCopyInto(&(*out)[i]) } } + out.Catalog = in.Catalog if in.Configuration != nil { in, out := &in.Configuration, &out.Configuration *out = make([]ConfigurationSpec, len(*in)) diff --git a/pkg/client/camel/applyconfiguration/camel/v1/catalog.go b/pkg/client/camel/applyconfiguration/camel/v1/catalog.go new file mode 100644 index 0000000000..eda43018f5 --- /dev/null +++ b/pkg/client/camel/applyconfiguration/camel/v1/catalog.go @@ -0,0 +1,53 @@ +/* +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. +*/ + +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package v1 + +import ( + v1 "github.com/apache/camel-k/v2/pkg/apis/camel/v1" +) + +// CatalogApplyConfiguration represents an declarative configuration of the Catalog type for use +// with apply. +type CatalogApplyConfiguration struct { + Version *string `json:"version,omitempty"` + Provider *v1.RuntimeProvider `json:"provider,omitempty"` +} + +// CatalogApplyConfiguration constructs an declarative configuration of the Catalog type for use with +// apply. +func Catalog() *CatalogApplyConfiguration { + return &CatalogApplyConfiguration{} +} + +// WithVersion sets the Version field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Version field is set to the value of the last call. +func (b *CatalogApplyConfiguration) WithVersion(value string) *CatalogApplyConfiguration { + b.Version = &value + return b +} + +// WithProvider sets the Provider field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Provider field is set to the value of the last call. +func (b *CatalogApplyConfiguration) WithProvider(value v1.RuntimeProvider) *CatalogApplyConfiguration { + b.Provider = &value + return b +} diff --git a/pkg/client/camel/applyconfiguration/camel/v1/integrationkitstatus.go b/pkg/client/camel/applyconfiguration/camel/v1/integrationkitstatus.go index 12650227af..8bc13a36d2 100644 --- a/pkg/client/camel/applyconfiguration/camel/v1/integrationkitstatus.go +++ b/pkg/client/camel/applyconfiguration/camel/v1/integrationkitstatus.go @@ -36,6 +36,7 @@ type IntegrationKitStatusApplyConfiguration struct { Failure *FailureApplyConfiguration `json:"failure,omitempty"` RuntimeVersion *string `json:"runtimeVersion,omitempty"` RuntimeProvider *v1.RuntimeProvider `json:"runtimeProvider,omitempty"` + Catalog *CatalogApplyConfiguration `json:"catalog,omitempty"` Platform *string `json:"platform,omitempty"` Version *string `json:"version,omitempty"` Conditions []IntegrationKitConditionApplyConfiguration `json:"conditions,omitempty"` @@ -132,6 +133,14 @@ func (b *IntegrationKitStatusApplyConfiguration) WithRuntimeProvider(value v1.Ru return b } +// WithCatalog sets the Catalog field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Catalog field is set to the value of the last call. +func (b *IntegrationKitStatusApplyConfiguration) WithCatalog(value *CatalogApplyConfiguration) *IntegrationKitStatusApplyConfiguration { + b.Catalog = value + return b +} + // WithPlatform sets the Platform field in the declarative configuration to the given value // and returns the receiver, so that objects can be built by chaining "With" function invocations. // If called multiple times, the Platform field is set to the value of the last call. diff --git a/pkg/client/camel/applyconfiguration/camel/v1/integrationstatus.go b/pkg/client/camel/applyconfiguration/camel/v1/integrationstatus.go index d17acaa2b2..851decd192 100644 --- a/pkg/client/camel/applyconfiguration/camel/v1/integrationstatus.go +++ b/pkg/client/camel/applyconfiguration/camel/v1/integrationstatus.go @@ -39,6 +39,7 @@ type IntegrationStatusApplyConfiguration struct { GeneratedSources []SourceSpecApplyConfiguration `json:"generatedSources,omitempty"` RuntimeVersion *string `json:"runtimeVersion,omitempty"` RuntimeProvider *v1.RuntimeProvider `json:"runtimeProvider,omitempty"` + Catalog *CatalogApplyConfiguration `json:"catalog,omitempty"` Configuration []ConfigurationSpecApplyConfiguration `json:"configuration,omitempty"` Conditions []IntegrationConditionApplyConfiguration `json:"conditions,omitempty"` Version *string `json:"version,omitempty"` @@ -149,6 +150,14 @@ func (b *IntegrationStatusApplyConfiguration) WithRuntimeProvider(value v1.Runti return b } +// WithCatalog sets the Catalog field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Catalog field is set to the value of the last call. +func (b *IntegrationStatusApplyConfiguration) WithCatalog(value *CatalogApplyConfiguration) *IntegrationStatusApplyConfiguration { + b.Catalog = value + return b +} + // WithConfiguration adds the given value to the Configuration field in the declarative configuration // and returns the receiver, so that objects can be build by chaining "With" function invocations. // If called multiple times, values provided by each call will be appended to the Configuration field. diff --git a/pkg/client/camel/applyconfiguration/utils.go b/pkg/client/camel/applyconfiguration/utils.go index 6632cd8230..626858470c 100644 --- a/pkg/client/camel/applyconfiguration/utils.go +++ b/pkg/client/camel/applyconfiguration/utils.go @@ -76,6 +76,8 @@ func ForKind(kind schema.GroupVersionKind) interface{} { return &camelv1.CamelSchemeScopeApplyConfiguration{} case v1.SchemeGroupVersion.WithKind("Capability"): return &camelv1.CapabilityApplyConfiguration{} + case v1.SchemeGroupVersion.WithKind("Catalog"): + return &camelv1.CatalogApplyConfiguration{} case v1.SchemeGroupVersion.WithKind("ConfigurationSpec"): return &camelv1.ConfigurationSpecApplyConfiguration{} case v1.SchemeGroupVersion.WithKind("DataSpec"): diff --git a/pkg/controller/integrationkit/initialize.go b/pkg/controller/integrationkit/initialize.go index 75b23ac95c..aa27e0c419 100644 --- a/pkg/controller/integrationkit/initialize.go +++ b/pkg/controller/integrationkit/initialize.go @@ -83,7 +83,7 @@ func (action *initializeAction) image(ctx context.Context, env *trait.Environmen catalog, err := kubernetes.GetCamelCatalog( ctx, action.client, - fmt.Sprintf("camel-catalog-%s", strings.ToLower(env.RuntimeVersion)), + fmt.Sprintf("camel-catalog-%s", strings.ToLower(env.CamelCatalog.GetRuntimeVersion())), kit.Namespace, ) diff --git a/pkg/resources/config/crd/bases/camel.apache.org_integrationkits.yaml b/pkg/resources/config/crd/bases/camel.apache.org_integrationkits.yaml index 0c9c03bec8..bb13ed757b 100644 --- a/pkg/resources/config/crd/bases/camel.apache.org_integrationkits.yaml +++ b/pkg/resources/config/crd/bases/camel.apache.org_integrationkits.yaml @@ -468,6 +468,15 @@ spec: baseImage: description: base image used by the kit (could be another IntegrationKit) type: string + catalog: + description: the catalog used to build/operate the IntegrationKit. + properties: + provider: + description: RuntimeProvider is the provider chosen for the runtime. + type: string + version: + type: string + type: object conditions: description: a list of conditions which happened for the events related the kit diff --git a/pkg/resources/config/crd/bases/camel.apache.org_integrations.yaml b/pkg/resources/config/crd/bases/camel.apache.org_integrations.yaml index 1f8528993a..1d3a4c5619 100644 --- a/pkg/resources/config/crd/bases/camel.apache.org_integrations.yaml +++ b/pkg/resources/config/crd/bases/camel.apache.org_integrations.yaml @@ -53,6 +53,10 @@ spec: jsonPath: .status.runtimeVersion name: Runtime Version type: string + - description: The catalog version + jsonPath: .status.catalog.version + name: Catalog Version + type: string - description: The integration kit jsonPath: .status.integrationKit.name name: Kit @@ -8030,6 +8034,15 @@ spec: items: type: string type: array + catalog: + description: the catalog used to build/operate the Integration. + properties: + provider: + description: RuntimeProvider is the provider chosen for the runtime. + type: string + version: + type: string + type: object conditions: description: a list of events happened for the Integration items: diff --git a/pkg/trait/camel.go b/pkg/trait/camel.go index 8a6c5a04e1..093d81767e 100644 --- a/pkg/trait/camel.go +++ b/pkg/trait/camel.go @@ -77,38 +77,57 @@ func (t *camelTrait) Configure(e *Environment) (bool, *TraitCondition, error) { } } - return true, nil, nil + var cond *TraitCondition + if e.IntegrationKit != nil && e.IntegrationKit.IsSynthetic() { + // We set a condition to warn the user the catalog used to run the Integration + // may differ from the runtime version which we don't control + cond = NewIntegrationCondition( + "Camel", + v1.IntegrationConditionTraitInfo, + corev1.ConditionTrue, + traitConfigurationReason, + fmt.Sprintf( + "Operated with CamelCatalog version %s which may be different from the runtime used in the container", + t.RuntimeVersion, + ), + ) + } + + return true, cond, nil } -//nolint:nestif func (t *camelTrait) Apply(e *Environment) error { - if e.IntegrationKit != nil && e.IntegrationKit.IsSynthetic() { - // Synthetic Integration Kit - - // This is required as during init phase, the trait set by default these values - // which are widely used in the platform for different purposese. - if e.Integration != nil { - e.Integration.Status.RuntimeVersion = "" - e.Integration.Status.RuntimeProvider = "" + if e.CamelCatalog == nil { + if err := t.loadOrCreateCatalog(e, t.RuntimeVersion); err != nil { + return err } - } else { - // Managed Integration - if e.CamelCatalog == nil { - if err := t.loadOrCreateCatalog(e, t.RuntimeVersion); err != nil { - return err - } - } - e.RuntimeVersion = e.CamelCatalog.Runtime.Version - if e.Integration != nil { - e.Integration.Status.RuntimeVersion = e.CamelCatalog.Runtime.Version - e.Integration.Status.RuntimeProvider = e.CamelCatalog.Runtime.Provider + } + + if e.Integration != nil { + e.Integration.Status.RuntimeVersion = e.CamelCatalog.Runtime.Version + e.Integration.Status.RuntimeProvider = e.CamelCatalog.Runtime.Provider + e.Integration.Status.Catalog = &v1.Catalog{ + Version: e.CamelCatalog.Runtime.Version, + Provider: e.CamelCatalog.Runtime.Provider, } - if e.IntegrationKit != nil { - e.IntegrationKit.Status.RuntimeVersion = e.CamelCatalog.Runtime.Version - e.IntegrationKit.Status.RuntimeProvider = e.CamelCatalog.Runtime.Provider + } + if e.IntegrationKit != nil { + e.IntegrationKit.Status.RuntimeVersion = e.CamelCatalog.Runtime.Version + e.IntegrationKit.Status.RuntimeProvider = e.CamelCatalog.Runtime.Provider + e.IntegrationKit.Status.Catalog = &v1.Catalog{ + Version: e.CamelCatalog.Runtime.Version, + Provider: e.CamelCatalog.Runtime.Provider, } } + if e.IntegrationKit != nil && e.IntegrationKit.IsSynthetic() { + // Synthetic Integration Kit + e.Integration.Status.RuntimeVersion = "" + e.Integration.Status.RuntimeProvider = "" + e.IntegrationKit.Status.RuntimeVersion = "" + e.IntegrationKit.Status.RuntimeProvider = "" + } + if e.IntegrationKitInPhase(v1.IntegrationKitPhaseReady) && e.IntegrationInRunningPhases() { // Get all resources maps := t.computeConfigMaps(e) diff --git a/pkg/trait/camel_test.go b/pkg/trait/camel_test.go index d3fe63e356..531e725e35 100644 --- a/pkg/trait/camel_test.go +++ b/pkg/trait/camel_test.go @@ -19,6 +19,7 @@ package trait import ( "context" + "fmt" "testing" corev1 "k8s.io/api/core/v1" @@ -55,9 +56,12 @@ func TestApplyCamelTraitSucceeds(t *testing.T) { err = trait.Apply(environment) require.NoError(t, err) - assert.Equal(t, "0.0.1", environment.RuntimeVersion) + assert.Equal(t, "0.0.1", environment.CamelCatalog.GetRuntimeVersion()) assert.Equal(t, "0.0.1", environment.Integration.Status.RuntimeVersion) assert.Equal(t, "0.0.1", environment.IntegrationKit.Status.RuntimeVersion) + expectedCatalog := &v1.Catalog{Version: "0.0.1", Provider: v1.RuntimeProviderQuarkus} + assert.Equal(t, expectedCatalog, environment.Integration.Status.Catalog) + assert.Equal(t, expectedCatalog, environment.IntegrationKit.Status.Catalog) // Test regex as well assert.True(t, exactVersionRegexp.MatchString("1.2.3")) @@ -71,7 +75,17 @@ func TestApplyCamelTraitExternalKit(t *testing.T) { configured, condition, err := trait.Configure(environment) require.NoError(t, err) - assert.Nil(t, condition) + expectedCondition := NewIntegrationCondition( + "Camel", + v1.IntegrationConditionTraitInfo, + corev1.ConditionTrue, + traitConfigurationReason, + fmt.Sprintf( + "Operated with CamelCatalog version %s which may be different from the runtime used in the container", + "0.0.1", + ), + ) + assert.Equal(t, expectedCondition, condition) assert.True(t, configured) err = trait.Apply(environment) require.NoError(t, err) @@ -79,6 +93,9 @@ func TestApplyCamelTraitExternalKit(t *testing.T) { assert.Equal(t, v1.RuntimeProvider(""), environment.Integration.Status.RuntimeProvider) assert.Equal(t, "", environment.IntegrationKit.Status.RuntimeVersion) assert.Equal(t, v1.RuntimeProvider(""), environment.Integration.Status.RuntimeProvider) + expectedCatalog := &v1.Catalog{Version: "0.0.1", Provider: v1.RuntimeProviderQuarkus} + assert.Equal(t, expectedCatalog, environment.Integration.Status.Catalog) + assert.Equal(t, expectedCatalog, environment.IntegrationKit.Status.Catalog) } func TestApplyCamelTraitWithoutEnvironmentCatalogAndUnmatchableVersionFails(t *testing.T) { @@ -214,7 +231,17 @@ func TestApplyCamelTraitSyntheticKitWithProperties(t *testing.T) { configured, condition, err := trait.Configure(environment) require.NoError(t, err) - assert.Nil(t, condition) + expectedCondition := NewIntegrationCondition( + "Camel", + v1.IntegrationConditionTraitInfo, + corev1.ConditionTrue, + traitConfigurationReason, + fmt.Sprintf( + "Operated with CamelCatalog version %s which may be different from the runtime used in the container", + "0.0.1", + ), + ) + assert.Equal(t, expectedCondition, condition) assert.True(t, configured) err = trait.Apply(environment) @@ -274,8 +301,8 @@ func TestCamelMatches(t *testing.T) { func TestCamelCatalogSemver(t *testing.T) { trait, environment := createNominalCamelTest(true) environment.Integration.Status.Phase = v1.IntegrationPhaseBuildingKit + environment.CamelCatalog.Runtime.Version = "2.16.1" trait.RuntimeVersion = "2.x" - environment.CamelCatalog.CamelCatalogSpec.Runtime.Version = "2.16.0" configured, condition, err := trait.Configure(environment) require.NoError(t, err) @@ -284,8 +311,8 @@ func TestCamelCatalogSemver(t *testing.T) { err = trait.Apply(environment) require.NoError(t, err) - // 2.x will translate with 2.16.0 as it is already existing - assert.Equal(t, environment.CamelCatalog.CamelCatalogSpec.Runtime.Version, environment.RuntimeVersion) + // 2.x will translate with 2.16.1 as it is already existing + assert.Equal(t, "2.16.1", environment.CamelCatalog.GetRuntimeVersion()) } func TestCamelTraitSyntheticIntegration(t *testing.T) { diff --git a/pkg/trait/logging_test.go b/pkg/trait/logging_test.go index 1ba6c482e0..7d77ff7e07 100644 --- a/pkg/trait/logging_test.go +++ b/pkg/trait/logging_test.go @@ -156,10 +156,10 @@ func TestJsonLoggingTrait(t *testing.T) { func TestDefaultQuarkusLogging(t *testing.T) { env := createDefaultLoggingTestEnv(t) - // Simulate a synthetic Integration Kit for which the catalog is not available - env.CamelCatalog = nil - env.IntegrationKit.Labels = map[string]string{ - v1.IntegrationKitTypeLabel: v1.IntegrationKitTypeSynthetic, + // Simulate an older catalog configuration which is missing the logging + // capability + env.CamelCatalog.Runtime.Capabilities["logging"] = v1.Capability{ + RuntimeProperties: nil, } env.EnvVars = []corev1.EnvVar{} conditions, err := NewLoggingTestCatalog().apply(env) diff --git a/pkg/trait/trait_types.go b/pkg/trait/trait_types.go index 7e95a88681..299b7f1c28 100644 --- a/pkg/trait/trait_types.go +++ b/pkg/trait/trait_types.go @@ -206,9 +206,8 @@ type ControllerStrategySelector interface { // //nolint:containedctx type Environment struct { - CamelCatalog *camel.RuntimeCatalog - RuntimeVersion string - Catalog *Catalog + CamelCatalog *camel.RuntimeCatalog + Catalog *Catalog // The Go standard context for the traits execution Ctx context.Context // The client to the API server diff --git a/pkg/trait/trait_types_test.go b/pkg/trait/trait_types_test.go index 497cd034af..50146584fe 100644 --- a/pkg/trait/trait_types_test.go +++ b/pkg/trait/trait_types_test.go @@ -282,9 +282,12 @@ func createSyntethicKitTestEnvironment(t *testing.T, profile v1.TraitProfile) *E t.Helper() client, _ := test.NewFakeClient() traitCatalog := NewCatalog(nil) + catalog, err := camel.DefaultCatalog() + require.NoError(t, err) environment := &Environment{ - Catalog: traitCatalog, - Client: client, + CamelCatalog: catalog, + Catalog: traitCatalog, + Client: client, Integration: &v1.Integration{ ObjectMeta: metav1.ObjectMeta{ Name: "test", @@ -325,7 +328,7 @@ func createSyntethicKitTestEnvironment(t *testing.T, profile v1.TraitProfile) *E environment.Platform.ResyncStatusFullConfig() - _, err := traitCatalog.apply(environment) + _, err = traitCatalog.apply(environment) require.NoError(t, err) return environment From a4314672ed180edafa4fd0e08c02905eedfc1ffe Mon Sep 17 00:00:00 2001 From: Pasquale Congiusti Date: Thu, 22 Aug 2024 10:48:36 +0200 Subject: [PATCH 3/4] chore(traits): removed camel catalog condition The default is to have a CamelCatalog, so, there is no need to skip traits any longer --- addons/keda/keda.go | 3 --- addons/master/master.go | 4 ---- addons/resume/resume.go | 3 --- addons/telemetry/telemetry.go | 11 ++--------- addons/telemetry/telemetry_test.go | 3 --- pkg/trait/builder.go | 3 --- pkg/trait/cron.go | 3 --- pkg/trait/dependencies.go | 3 --- pkg/trait/error_handler.go | 4 ---- pkg/trait/health.go | 6 +++--- pkg/trait/kamelets.go | 5 ----- pkg/trait/kamelets_test.go | 9 ++++----- pkg/trait/knative.go | 10 ++-------- pkg/trait/knative_test.go | 5 +---- pkg/trait/logging.go | 2 +- pkg/trait/openapi.go | 8 +------- pkg/trait/quarkus.go | 3 --- pkg/trait/service.go | 3 --- pkg/trait/service_binding.go | 3 --- pkg/trait/trait_condition_types.go | 15 --------------- 20 files changed, 14 insertions(+), 92 deletions(-) diff --git a/addons/keda/keda.go b/addons/keda/keda.go index 3060d48b3c..531753827f 100644 --- a/addons/keda/keda.go +++ b/addons/keda/keda.go @@ -119,9 +119,6 @@ func (t *kedaTrait) Configure(e *trait.Environment) (bool, *trait.TraitCondition if e.Integration == nil || !ptr.Deref(t.Enabled, false) { return false, nil, nil } - if e.CamelCatalog == nil { - return false, trait.NewIntegrationConditionPlatformDisabledCatalogMissing(), nil - } if !e.IntegrationInPhase(camelv1.IntegrationPhaseInitialization) && !e.IntegrationInRunningPhases() { return false, nil, nil } diff --git a/addons/master/master.go b/addons/master/master.go index 5ebc04c797..f893e19bc3 100644 --- a/addons/master/master.go +++ b/addons/master/master.go @@ -88,13 +88,9 @@ func (t *masterTrait) Configure(e *trait.Environment) (bool, *trait.TraitConditi if !ptr.Deref(t.Enabled, true) { return false, trait.NewIntegrationConditionUserDisabled(masterComponent), nil } - if e.CamelCatalog == nil { - return false, trait.NewIntegrationConditionPlatformDisabledCatalogMissing(), nil - } if !e.IntegrationInPhase(v1.IntegrationPhaseInitialization, v1.IntegrationPhaseBuildingKit) && !e.IntegrationInRunningPhases() { return false, nil, nil } - if !ptr.Deref(t.Auto, true) { return ptr.Deref(t.Enabled, false), nil, nil } diff --git a/addons/resume/resume.go b/addons/resume/resume.go index 6fed7e3bfc..45d56756c7 100644 --- a/addons/resume/resume.go +++ b/addons/resume/resume.go @@ -78,9 +78,6 @@ func (r *resumeTrait) Configure(environment *trait.Environment) (bool, *trait.Tr if !ptr.Deref(r.Enabled, false) { return false, nil, nil } - if environment.CamelCatalog == nil { - return false, trait.NewIntegrationConditionPlatformDisabledCatalogMissing(), nil - } if !environment.IntegrationInPhase(v1.IntegrationPhaseInitialization) && !environment.IntegrationInRunningPhases() { return false, nil, nil } diff --git a/addons/telemetry/telemetry.go b/addons/telemetry/telemetry.go index 806bbd1b9b..07908c13fc 100644 --- a/addons/telemetry/telemetry.go +++ b/addons/telemetry/telemetry.go @@ -90,17 +90,10 @@ func NewTelemetryTrait() trait.Trait { } } -func (t *telemetryTrait) isForcefullyEnabled() bool { - return ptr.Deref(t.Enabled, false) && !ptr.Deref(t.Auto, true) -} - func (t *telemetryTrait) Configure(e *trait.Environment) (bool, *trait.TraitCondition, error) { if e.Integration == nil || !ptr.Deref(t.Enabled, false) { return false, nil, nil } - if e.CamelCatalog == nil && !t.isForcefullyEnabled() { - return false, trait.NewIntegrationConditionPlatformDisabledCatalogMissing(), nil - } if !ptr.Deref(t.Auto, true) { return true, nil, nil @@ -143,7 +136,7 @@ func (t *telemetryTrait) Configure(e *trait.Environment) (bool, *trait.TraitCond func (t *telemetryTrait) Apply(e *trait.Environment) error { util.StringSliceUniqueAdd(&e.Integration.Status.Capabilities, v1.CapabilityTelemetry) - if t.isForcefullyEnabled() || e.CamelCatalog.Runtime.Capabilities["telemetry"].RuntimeProperties != nil { + if e.CamelCatalog.Runtime.Capabilities["telemetry"].RuntimeProperties != nil { t.setCatalogConfiguration(e) } else { t.setRuntimeProviderProperties(e) @@ -175,7 +168,7 @@ func (t *telemetryTrait) setCatalogConfiguration(e *trait.Environment) { e.ApplicationProperties["camel.k.telemetry.samplerParentBased"] = boolean.FalseString } - if e.CamelCatalog != nil && e.CamelCatalog.Runtime.Capabilities["telemetry"].RuntimeProperties != nil { + if e.CamelCatalog.Runtime.Capabilities["telemetry"].RuntimeProperties != nil { for _, cp := range e.CamelCatalog.Runtime.Capabilities["telemetry"].RuntimeProperties { e.ApplicationProperties[trait.CapabilityPropertyKey(cp.Key, e.ApplicationProperties)] = cp.Value } diff --git a/addons/telemetry/telemetry_test.go b/addons/telemetry/telemetry_test.go index d854312703..ad57ba96c7 100644 --- a/addons/telemetry/telemetry_test.go +++ b/addons/telemetry/telemetry_test.go @@ -93,8 +93,6 @@ func TestTelemetryTraitWithValues(t *testing.T) { func TestTelemetryForSourceless(t *testing.T) { e := createEnvironment(t, camel.QuarkusCatalog) - // CamelCatalog not necessarily available during a sourceless deployment - e.CamelCatalog = nil telemetry := NewTelemetryTrait() tt, _ := telemetry.(*telemetryTrait) tt.Enabled = ptr.To(true) @@ -104,7 +102,6 @@ func TestTelemetryForSourceless(t *testing.T) { tt.Sampler = "ratio" tt.SamplerRatio = "0.001" tt.SamplerParentBased = ptr.To(false) - assert.True(t, tt.isForcefullyEnabled()) ok, condition, err := telemetry.Configure(e) require.NoError(t, err) diff --git a/pkg/trait/builder.go b/pkg/trait/builder.go index 6ba5d7f7f1..bb4cdc159d 100644 --- a/pkg/trait/builder.go +++ b/pkg/trait/builder.go @@ -93,9 +93,6 @@ func (t *builderTrait) Configure(e *Environment) (bool, *TraitCondition, error) if e.IntegrationKit == nil { return false, nil, nil } - if e.CamelCatalog == nil { - return false, NewIntegrationConditionPlatformDisabledCatalogMissing(), nil - } condition := t.adaptDeprecatedFields() if e.Platform.Status.Build.PublishStrategy == v1.IntegrationPlatformBuildPublishStrategySpectrum { condition = newOrAppend(condition, "Spectrum publishing strategy is deprecated and may be removed in future releases. Make sure to use any supported publishing strategy instead.") diff --git a/pkg/trait/cron.go b/pkg/trait/cron.go index 55945f132a..b86216041f 100644 --- a/pkg/trait/cron.go +++ b/pkg/trait/cron.go @@ -88,9 +88,6 @@ func (t *cronTrait) Configure(e *Environment) (bool, *TraitCondition, error) { if !e.IntegrationInPhase(v1.IntegrationPhaseInitialization) && !e.IntegrationInRunningPhases() { return false, nil, nil } - if e.CamelCatalog == nil { - return false, NewIntegrationConditionPlatformDisabledCatalogMissing(), nil - } if _, ok := e.CamelCatalog.Runtime.Capabilities[v1.CapabilityCron]; !ok { return false, NewIntegrationCondition( "Cron", diff --git a/pkg/trait/dependencies.go b/pkg/trait/dependencies.go index 187e3bc265..55b1559dee 100644 --- a/pkg/trait/dependencies.go +++ b/pkg/trait/dependencies.go @@ -46,9 +46,6 @@ func (t *dependenciesTrait) Configure(e *Environment) (bool, *TraitCondition, er if e.Integration == nil { return false, nil, nil } - if e.CamelCatalog == nil { - return false, NewIntegrationConditionPlatformDisabledCatalogMissing(), nil - } return e.IntegrationInPhase(v1.IntegrationPhaseInitialization), nil, nil } diff --git a/pkg/trait/error_handler.go b/pkg/trait/error_handler.go index 3aa8c1c842..05eabeaa19 100644 --- a/pkg/trait/error_handler.go +++ b/pkg/trait/error_handler.go @@ -49,10 +49,6 @@ func (t *errorHandlerTrait) Configure(e *Environment) (bool, *TraitCondition, er if e.Integration == nil { return false, nil, nil } - if e.CamelCatalog == nil { - return false, NewIntegrationConditionPlatformDisabledCatalogMissing(), nil - } - if !e.IntegrationInPhase(v1.IntegrationPhaseInitialization) && !e.IntegrationInRunningPhases() { return false, nil, nil } diff --git a/pkg/trait/health.go b/pkg/trait/health.go index c4b7e6eec2..98d87b046d 100644 --- a/pkg/trait/health.go +++ b/pkg/trait/health.go @@ -76,7 +76,7 @@ func (t *healthTrait) Configure(e *Environment) (bool, *TraitCondition, error) { func (t *healthTrait) setProbesValues(e *Environment) { if t.LivenessProbe == "" { - if e.CamelCatalog != nil && e.CamelCatalog.Runtime.Capabilities["health"].Metadata != nil { + if e.CamelCatalog.Runtime.Capabilities["health"].Metadata != nil { t.LivenessProbe = e.CamelCatalog.Runtime.Capabilities["health"].Metadata["defaultLivenessProbePath"] } else { // Deprecated: to be removed @@ -84,7 +84,7 @@ func (t *healthTrait) setProbesValues(e *Environment) { } } if t.ReadinessProbe == "" { - if e.CamelCatalog != nil && e.CamelCatalog.Runtime.Capabilities["health"].Metadata != nil { + if e.CamelCatalog.Runtime.Capabilities["health"].Metadata != nil { t.ReadinessProbe = e.CamelCatalog.Runtime.Capabilities["health"].Metadata["defaultReadinessProbePath"] } else { // Deprecated: to be removed @@ -92,7 +92,7 @@ func (t *healthTrait) setProbesValues(e *Environment) { } } if t.StartupProbe == "" { - if e.CamelCatalog != nil && e.CamelCatalog.Runtime.Capabilities["health"].Metadata != nil { + if e.CamelCatalog.Runtime.Capabilities["health"].Metadata != nil { t.StartupProbe = e.CamelCatalog.Runtime.Capabilities["health"].Metadata["defaultStartupProbePath"] } else { // Deprecated: to be removed diff --git a/pkg/trait/kamelets.go b/pkg/trait/kamelets.go index 936770b6d6..912bb63975 100644 --- a/pkg/trait/kamelets.go +++ b/pkg/trait/kamelets.go @@ -78,11 +78,6 @@ func (t *kameletsTrait) Configure(e *Environment) (bool, *TraitCondition, error) t.MountPoint = filepath.Join(camel.BasePath, "kamelets") } if ptr.Deref(t.Auto, true) { - if e.CamelCatalog == nil { - // Cannot execute this trait for synthetic IntegrationKit. In order to use it, the - // user has to specify forcefully auto=false option and pass a list of kamelets explicitly - return false, NewIntegrationConditionPlatformDisabledCatalogMissing(), nil - } var kamelets []string _, err := e.ConsumeMeta(func(meta metadata.IntegrationMetadata) bool { util.StringSliceUniqueConcat(&kamelets, meta.Kamelets) diff --git a/pkg/trait/kamelets_test.go b/pkg/trait/kamelets_test.go index afa018df11..d59e56d797 100644 --- a/pkg/trait/kamelets_test.go +++ b/pkg/trait/kamelets_test.go @@ -618,17 +618,16 @@ func TestKameletSyntheticKitAutoConditionFalse(t *testing.T) { }), }, }) - environment.CamelCatalog = nil environment.Integration.Spec.Sources = nil trait.List = "timer-source" - // Auto=true by default, so, we will need to skip as - // we cannot parse sources + // Auto=true by default. The source parsing will be empty as + // there are no available sources. enabled, condition, err := trait.Configure(environment) require.NoError(t, err) - assert.False(t, enabled) - assert.NotNil(t, condition) + assert.True(t, enabled) + assert.Nil(t, condition) kameletsBundle := environment.Resources.GetConfigMap(func(cm *corev1.ConfigMap) bool { return cm.Labels[kubernetes.ConfigMapTypeLabel] == KameletBundleType diff --git a/pkg/trait/knative.go b/pkg/trait/knative.go index de24fc9aa5..9f52337284 100644 --- a/pkg/trait/knative.go +++ b/pkg/trait/knative.go @@ -76,12 +76,6 @@ func (t *knativeTrait) Configure(e *Environment) (bool, *TraitCondition, error) if !ptr.Deref(t.Enabled, true) { return false, NewIntegrationConditionUserDisabled("Knative"), nil } - if e.CamelCatalog == nil { - if ptr.Deref(t.Enabled, false) { - return true, nil, nil - } - return false, NewIntegrationConditionPlatformDisabledCatalogMissing(), nil - } if !e.IntegrationInPhase(v1.IntegrationPhaseInitialization) && !e.IntegrationInRunningPhases() { return false, nil, nil } @@ -130,8 +124,8 @@ func (t *knativeTrait) Configure(e *Environment) (bool, *TraitCondition, error) } hasKnativeEndpoint := len(t.ChannelSources) > 0 || len(t.ChannelSinks) > 0 || len(t.EndpointSources) > 0 || len(t.EndpointSinks) > 0 || len(t.EventSources) > 0 || len(t.EventSinks) > 0 - t.Enabled = &hasKnativeEndpoint - if !hasKnativeEndpoint { + + if !hasKnativeEndpoint && !ptr.Deref(t.Enabled, false) { return false, nil, nil } if !knativeInstalled { diff --git a/pkg/trait/knative_test.go b/pkg/trait/knative_test.go index 9aaadba604..7a8a7e45f0 100644 --- a/pkg/trait/knative_test.go +++ b/pkg/trait/knative_test.go @@ -1303,8 +1303,6 @@ func TestKnativeEnabled(t *testing.T) { // apply the knative trait require.NoError(t, knTrait.Apply(&environment)) - - assert.True(t, *knTrait.Enabled) assert.Contains(t, environment.Integration.Status.Capabilities, v1.CapabilityKnative) } @@ -1704,14 +1702,13 @@ func TestKnativeSyntheticKitDefault(t *testing.T) { ok, condition, err := knTrait.Configure(&e) require.NoError(t, err) assert.False(t, ok) - assert.NotNil(t, condition) + assert.Nil(t, condition) } func TestKnativeSyntheticKitEnabled(t *testing.T) { e := NewFakeEnvironmentForSyntheticKit(t) knTrait, _ := newKnativeTrait().(*knativeTrait) knTrait.Enabled = ptr.To(true) - knTrait.Auto = ptr.To(false) ok, condition, err := knTrait.Configure(&e) require.NoError(t, err) assert.True(t, ok) diff --git a/pkg/trait/logging.go b/pkg/trait/logging.go index 60cdb4113d..fdd6656a47 100644 --- a/pkg/trait/logging.go +++ b/pkg/trait/logging.go @@ -62,7 +62,7 @@ func (l loggingTrait) Configure(e *Environment) (bool, *TraitCondition, error) { } func (l loggingTrait) Apply(e *Environment) error { - if e.CamelCatalog != nil && e.CamelCatalog.Runtime.Capabilities["logging"].RuntimeProperties != nil { + if e.CamelCatalog.Runtime.Capabilities["logging"].RuntimeProperties != nil { l.setCatalogConfiguration(e) } else { l.setEnvConfiguration(e) diff --git a/pkg/trait/openapi.go b/pkg/trait/openapi.go index cb201d0804..fbc1bf49d9 100644 --- a/pkg/trait/openapi.go +++ b/pkg/trait/openapi.go @@ -202,13 +202,7 @@ func (t *openAPITrait) createNewOpenAPIConfigMap(e *Environment, resource v1.Dat return err } - // If the catalog is missing, we use the default version used by the IntegrationPlatform - runtimeVersion := e.Platform.Status.Build.RuntimeVersion - if e.CamelCatalog != nil { - runtimeVersion = e.CamelCatalog.Runtime.Version - } - - project := t.generateMavenProject(runtimeVersion) + project := t.generateMavenProject(e.CamelCatalog.Runtime.Version) mc := maven.NewContext(tmpDir) mc.LocalRepository = e.Platform.Status.Build.Maven.LocalRepository mc.AdditionalArguments = e.Platform.Status.Build.Maven.CLIOptions diff --git a/pkg/trait/quarkus.go b/pkg/trait/quarkus.go index d720db315c..b161ee6fb0 100644 --- a/pkg/trait/quarkus.go +++ b/pkg/trait/quarkus.go @@ -140,9 +140,6 @@ func (t *quarkusTrait) Matches(trait Trait) bool { } func (t *quarkusTrait) Configure(e *Environment) (bool, *TraitCondition, error) { - if e.CamelCatalog == nil { - return false, NewIntegrationConditionPlatformDisabledCatalogMissing(), nil - } condition := t.adaptDeprecatedFields() return e.IntegrationInPhase(v1.IntegrationPhaseBuildingKit) || diff --git a/pkg/trait/service.go b/pkg/trait/service.go index 8ed0547003..087f289dba 100644 --- a/pkg/trait/service.go +++ b/pkg/trait/service.go @@ -58,9 +58,6 @@ func (t *serviceTrait) Configure(e *Environment) (bool, *TraitCondition, error) "explicitly disabled", ), nil } - if e.CamelCatalog == nil { - return false, NewIntegrationConditionPlatformDisabledCatalogMissing(), nil - } // in case the knative-service and service trait are enabled, the knative-service has priority // then this service is disabled if e.GetTrait(knativeServiceTraitID) != nil { diff --git a/pkg/trait/service_binding.go b/pkg/trait/service_binding.go index e2956858fa..b8fd4ba45e 100644 --- a/pkg/trait/service_binding.go +++ b/pkg/trait/service_binding.go @@ -74,9 +74,6 @@ func (t *serviceBindingTrait) Configure(e *Environment) (bool, *TraitCondition, if !ptr.Deref(t.Enabled, true) { return false, NewIntegrationConditionUserDisabled("ServiceBinding"), nil } - if e.CamelCatalog == nil { - return false, NewIntegrationConditionPlatformDisabledCatalogMissing(), nil - } if len(t.Services) == 0 { return false, nil, nil } diff --git a/pkg/trait/trait_condition_types.go b/pkg/trait/trait_condition_types.go index f1febd59a4..942a3dbd68 100644 --- a/pkg/trait/trait_condition_types.go +++ b/pkg/trait/trait_condition_types.go @@ -56,25 +56,10 @@ func NewIntegrationConditionUserDisabled(traitID string) *TraitCondition { return NewIntegrationCondition(traitID, v1.IntegrationConditionTraitInfo, corev1.ConditionTrue, traitConfigurationReason, userDisabledMessage) } -func NewIntegrationConditionUserEnabledWithMessage(traitID string, message string) *TraitCondition { - return NewIntegrationCondition(traitID, v1.IntegrationConditionTraitInfo, corev1.ConditionTrue, traitConfigurationReason, fmt.Sprintf("%s: %s", userEnabledMessage, message)) -} - func NewIntegrationConditionPlatformDisabledWithMessage(traitID string, message string) *TraitCondition { return NewIntegrationCondition(traitID, v1.IntegrationConditionTraitInfo, corev1.ConditionTrue, traitConfigurationReason, fmt.Sprintf("%s: %s", platformDisabledMessage, message)) } -// This one is reused among different traits in order to avoid polluting the conditions with the same message. -func NewIntegrationConditionPlatformDisabledCatalogMissing() *TraitCondition { - return NewIntegrationCondition( - "Generic", - v1.IntegrationConditionTraitInfo, - corev1.ConditionTrue, - traitConfigurationReason, - "no camel catalog available for this Integration. Several traits have not been executed for this reason. Check applied trait condition to know more.", - ) -} - func (tc *TraitCondition) integrationCondition() (v1.IntegrationConditionType, corev1.ConditionStatus, string, string) { return v1.IntegrationConditionType(tc.typeForCondition()), tc.conditionStatus, From b4dfeadd10fb8341c8697abdfed560a06d33fd28 Mon Sep 17 00:00:00 2001 From: Pasquale Congiusti Date: Mon, 26 Aug 2024 14:58:08 +0200 Subject: [PATCH 4/4] chore(doc): camel runtimes adjustment --- .../ROOT/pages/running/camel-runtimes.adoc | 260 +----------------- 1 file changed, 6 insertions(+), 254 deletions(-) diff --git a/docs/modules/ROOT/pages/running/camel-runtimes.adoc b/docs/modules/ROOT/pages/running/camel-runtimes.adoc index 3eacd79873..34da12edf7 100644 --- a/docs/modules/ROOT/pages/running/camel-runtimes.adoc +++ b/docs/modules/ROOT/pages/running/camel-runtimes.adoc @@ -17,262 +17,14 @@ The step above is a very quick way to create a basic Camel application in any of At this stage we do have a container image with our Camel application. We can use the `kamel` CLI to run our Camel application via `kamel run --image docker.io/my-org/my-app:1.0.0` tuning, if it's the case, with any of the trait or configuration required. Mind that, when you run an Integration with this option, the operator will create a **synthetic** IntegrationKit. -NOTE: certain traits (ie, JVM) won't be available when running an application built externally. - If all is good, in a few seconds (there is no build involved) you should have your application up and running and you can monitor and operate with Camel K as usual. -[[traits-and-dependencies]] -== Traits and dependencies - -Certain Camel K operational aspect may be driven by traits. When you're building the application outside the operator, some of those traits may not be executed as they are executed during the building phase that we are skipping when running **sourceless Integrations**. Here we provided a list of those traits that may not work when building the application outside the Camel K operator. - -NOTE: this is a best effort analysis taking as reference the work available in version 2.3. - -* Build column show those traits that affects the build (will be skipped for sourceless Integrations). -* Dependencies column show those traits that will add some dependency (you may need to manually add those dependencies). -* Runtime column show those traits that will influence the runtime, mostly via properties (you may need to manually add those properties to the bundled `application.properties`). -* Deployment column show those traits that will be executed for the deployment (nothing should be required). - -[cols="1,1,1,1,1"] -|=== -|Trait -|Build -|Dependencies -|Runtime -|Deployment - -|Affinity -|x -|x -|x -|v - -|Builder -|v -|x -|x -|x - -|Camel -|x -|x -|v -|x - -|Container -|x -|x -|x -|v - -|Cron -|x -|v -|v -|x - -|Dependencies -|v -|v -|x -|x - -|Deployer -|x -|x -|x -|v - -|Deployment -|x -|x -|x -|v - -|Environment -|x -|x -|x -|v - -|Error Handler -|x -|v -|x -|x - -|GC (Garbage Collector) -|x -|x -|x -|v - -|Health -|x -|v -|v -|v - -|Ingress -|x -|x -|x -|v - -|Istio -|x -|x -|x -|v - -|Jolokia -|x -|v -|v -|v - -|JVM -|x -|x -|v -|v - -|Kamelets -|x -|x -|v -|x - -|Knative Service -|x -|x -|x -|v - -|Knative -|x -|v -|x -|x - -|Logging -|x -|x -|v -|v - -|Mount -|x -|x -|x -|v - -|Openapi -|x -|v -|v -|v - -|Owner -|x -|x -|x -|v - -|PDB -|x -|x -|x -|v - -|Platform -|x -|x -|x -|v - -|Pod -|x -|x -|x -|v - -|Prometheus -|v -|v -|x -|x - -|Pull Secret -|x -|x -|x -|v - -|Quarkus -|v -|x -|x -|x - -|Service -|x -|x -|x -|v - -|Service Binding -|x -|x -|v -|v - -|Toleration -|x -|x -|x -|v - -|Keda -|x -|x -|x -|v - -|Master -|v -|v -|v -|x - -|Resume -|v -|v -|x -|x - -|Strimzi -|x -|x -|x -|v - -|Telemetry -|x -|x -|v -|x +[[camel-runtime-discovery]] +== Camel Runtime version discovery -|Three Scale -|x -|x -|x -|v +Every Camel application requires a `CamelCatalog` object to know how to perform certain runtime configuration. When you run a **sourceless Integrations** there is no easy way to automatically discover for which runtime your application was built. In this case, we suggest you to specify the `camel.runtime-version` trait in order to improve the compatibility between the operator configuration and the specific runtime you're running. If no runtime version is specified, then, as default, the operator will use the one specified in the IntegrationPlatform. -|Vaults -|x -|v -|v -|x +[[traits]] +== Trait configuration -|=== +Certain Camel K operational aspect may be driven by traits. When you're building the application outside the operator, some of those traits may not be executed as they are executed during the building phase that we are skipping when running **sourceless Integrations**. There is also no possible way to auto-tune certain traits that require the presence of the source. In this case, you should instead provide a trait configuration with the values that are required by your Integration (for example, Knative, Service and other deployment traits). \ No newline at end of file