astefanutti commented on a change in pull request #2838:
URL: https://github.com/apache/camel-k/pull/2838#discussion_r773124441



##########
File path: pkg/client/serverside.go
##########
@@ -0,0 +1,130 @@
+/*
+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 client
+
+import (
+       "context"
+       "fmt"
+       "net/http"
+       "strings"
+       "sync"
+       "sync/atomic"
+
+       "github.com/apache/camel-k/pkg/util/log"
+       "github.com/apache/camel-k/pkg/util/patch"
+       "github.com/pkg/errors"
+       k8serrors "k8s.io/apimachinery/pkg/api/errors"
+       "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
+       "k8s.io/apimachinery/pkg/runtime"
+       "k8s.io/apimachinery/pkg/types"
+       ctrl "sigs.k8s.io/controller-runtime/pkg/client"
+)
+
+type ServerOrClientSideApplier struct {

Review comment:
       nit: I'd suggest to rename the file to `apply.go` as it's not restricted 
to server-side (even if it's the intent).

##########
File path: pkg/client/serverside.go
##########
@@ -0,0 +1,130 @@
+/*
+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 client
+
+import (
+       "context"
+       "fmt"
+       "net/http"
+       "strings"
+       "sync"
+       "sync/atomic"
+
+       "github.com/apache/camel-k/pkg/util/log"
+       "github.com/apache/camel-k/pkg/util/patch"
+       "github.com/pkg/errors"
+       k8serrors "k8s.io/apimachinery/pkg/api/errors"
+       "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
+       "k8s.io/apimachinery/pkg/runtime"
+       "k8s.io/apimachinery/pkg/types"
+       ctrl "sigs.k8s.io/controller-runtime/pkg/client"
+)
+
+type ServerOrClientSideApplier struct {
+       Client             ctrl.Client
+       hasServerSideApply atomic.Value
+       tryServerSideApply sync.Once
+}
+
+func (c *defaultClient) ServerOrClientSideApplier() ServerOrClientSideApplier {
+       return ServerOrClientSideApplier{
+               Client: c,
+       }
+}
+
+func (a *ServerOrClientSideApplier) Apply(ctx context.Context, object 
ctrl.Object) error {
+       once := false
+       var err error
+       // nolint: ifshort
+       needsRetry := false
+       a.tryServerSideApply.Do(func() {
+               once = true
+               if err = a.serverSideApply(ctx, object); err != nil {
+                       if isIncompatibleServerError(err) {
+                               log.Info("Fallback to client-side apply for 
installing resources")
+                               a.hasServerSideApply.Store(false)
+                               err = nil
+                       } else {
+                               needsRetry = true

Review comment:
       Out of curiosity, what is the reason behind moving the reset out of the 
critical section?

##########
File path: addons/keda/keda.go
##########
@@ -0,0 +1,551 @@
+/*
+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 keda
+
+import (
+       "bytes"
+       "encoding/json"
+       "fmt"
+       "sort"
+       "strings"
+       "text/template"
+
+       kedav1alpha1 "github.com/apache/camel-k/addons/keda/duck/v1alpha1"
+       camelv1 "github.com/apache/camel-k/pkg/apis/camel/v1"
+       camelv1alpha1 "github.com/apache/camel-k/pkg/apis/camel/v1alpha1"
+       "github.com/apache/camel-k/pkg/kamelet/repository"
+       "github.com/apache/camel-k/pkg/metadata"
+       "github.com/apache/camel-k/pkg/platform"
+       "github.com/apache/camel-k/pkg/trait"
+       "github.com/apache/camel-k/pkg/util"
+       "github.com/apache/camel-k/pkg/util/kubernetes"
+       "github.com/apache/camel-k/pkg/util/property"
+       "github.com/apache/camel-k/pkg/util/source"
+       "github.com/apache/camel-k/pkg/util/uri"
+       "github.com/pkg/errors"
+       scase "github.com/stoewer/go-strcase"
+       v1 "k8s.io/api/core/v1"
+       metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+       ctrl "sigs.k8s.io/controller-runtime/pkg/client"
+)
+
+const (
+       // kameletURNMetadataPrefix allows binding Kamelet properties to KEDA 
metadata.
+       kameletURNMetadataPrefix = "urn:keda:metadata:"
+       // kameletURNAuthenticationPrefix allows binding Kamelet properties to 
KEDA authentication options.
+       kameletURNAuthenticationPrefix = "urn:keda:authentication:"
+       // kameletURNRequiredTag is used to mark properties required by KEDA.
+       kameletURNRequiredTag = "urn:keda:required"
+
+       // kameletAnnotationType indicates the scaler type associated to a 
Kamelet.
+       kameletAnnotationType = "camel.apache.org/keda.type"
+       // kameletAnnotationMetadataPrefix is used to define virtual metadata 
fields computed from Kamelet properties.
+       kameletAnnotationMetadataPrefix = "camel.apache.org/keda.metadata."
+       // kameletAnnotationAuthenticationPrefix is used to define virtual 
authentication fields computed from Kamelet properties.
+       kameletAnnotationAuthenticationPrefix = 
"camel.apache.org/keda.authentication."
+)
+
+// The KEDA trait can be used for automatic integration with KEDA autoscalers.
+// The trait can be either manually configured using the `triggers` option or 
automatically configured
+// via markers in the Kamelets.
+//
+// For information on how to use KEDA enabled Kamelets with the KEDA trait, 
refer to
+// xref:ROOT:kamelets/kamelets-user.adoc#kamelet-keda-user[the KEDA section in 
the Kamelets user guide].
+// If you want to create Kamelets that contain KEDA metadata, refer to
+// xref:ROOT:kamelets/kamelets-dev.adoc#kamelet-keda-dev[the KEDA section in 
the Kamelets development guide].
+//
+// The KEDA trait is disabled by default.
+//
+// +camel-k:trait=keda.
+type kedaTrait struct {
+       trait.BaseTrait `property:",squash"`
+       // Enables automatic configuration of the trait. Allows the trait to 
infer KEDA triggers from the Kamelets.
+       Auto *bool `property:"auto" json:"auto,omitempty"`
+       // Convert metadata properties to camelCase (needed because Camel K 
trait properties use kebab-case from command line). Disabled by default.

Review comment:
       Are they really kebab-cased? It's true for top-level keys, but the 
hierarchical ones are unstructured and arbitrary?

##########
File path: addons/keda/keda.go
##########
@@ -0,0 +1,551 @@
+/*
+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 keda
+
+import (
+       "bytes"
+       "encoding/json"
+       "fmt"
+       "sort"
+       "strings"
+       "text/template"
+
+       kedav1alpha1 "github.com/apache/camel-k/addons/keda/duck/v1alpha1"
+       camelv1 "github.com/apache/camel-k/pkg/apis/camel/v1"
+       camelv1alpha1 "github.com/apache/camel-k/pkg/apis/camel/v1alpha1"
+       "github.com/apache/camel-k/pkg/kamelet/repository"
+       "github.com/apache/camel-k/pkg/metadata"
+       "github.com/apache/camel-k/pkg/platform"
+       "github.com/apache/camel-k/pkg/trait"
+       "github.com/apache/camel-k/pkg/util"
+       "github.com/apache/camel-k/pkg/util/kubernetes"
+       "github.com/apache/camel-k/pkg/util/property"
+       "github.com/apache/camel-k/pkg/util/source"
+       "github.com/apache/camel-k/pkg/util/uri"
+       "github.com/pkg/errors"
+       scase "github.com/stoewer/go-strcase"
+       v1 "k8s.io/api/core/v1"
+       metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+       ctrl "sigs.k8s.io/controller-runtime/pkg/client"
+)
+
+const (
+       // kameletURNMetadataPrefix allows binding Kamelet properties to KEDA 
metadata.
+       kameletURNMetadataPrefix = "urn:keda:metadata:"
+       // kameletURNAuthenticationPrefix allows binding Kamelet properties to 
KEDA authentication options.
+       kameletURNAuthenticationPrefix = "urn:keda:authentication:"
+       // kameletURNRequiredTag is used to mark properties required by KEDA.
+       kameletURNRequiredTag = "urn:keda:required"
+
+       // kameletAnnotationType indicates the scaler type associated to a 
Kamelet.
+       kameletAnnotationType = "camel.apache.org/keda.type"
+       // kameletAnnotationMetadataPrefix is used to define virtual metadata 
fields computed from Kamelet properties.
+       kameletAnnotationMetadataPrefix = "camel.apache.org/keda.metadata."
+       // kameletAnnotationAuthenticationPrefix is used to define virtual 
authentication fields computed from Kamelet properties.
+       kameletAnnotationAuthenticationPrefix = 
"camel.apache.org/keda.authentication."
+)
+
+// The KEDA trait can be used for automatic integration with KEDA autoscalers.
+// The trait can be either manually configured using the `triggers` option or 
automatically configured
+// via markers in the Kamelets.
+//
+// For information on how to use KEDA enabled Kamelets with the KEDA trait, 
refer to
+// xref:ROOT:kamelets/kamelets-user.adoc#kamelet-keda-user[the KEDA section in 
the Kamelets user guide].
+// If you want to create Kamelets that contain KEDA metadata, refer to
+// xref:ROOT:kamelets/kamelets-dev.adoc#kamelet-keda-dev[the KEDA section in 
the Kamelets development guide].
+//
+// The KEDA trait is disabled by default.
+//
+// +camel-k:trait=keda.
+type kedaTrait struct {
+       trait.BaseTrait `property:",squash"`
+       // Enables automatic configuration of the trait. Allows the trait to 
infer KEDA triggers from the Kamelets.
+       Auto *bool `property:"auto" json:"auto,omitempty"`
+       // Convert metadata properties to camelCase (needed because Camel K 
trait properties use kebab-case from command line). Disabled by default.
+       CamelCaseConversion *bool `property:"camel-case-conversion" 
json:"camelCaseConversion,omitempty"`
+       // Set the spec->replicas field on the top level controller to an 
explicit value if missing, to allow KEDA to recognize it as a scalable resource.

Review comment:
       I'm sure you've come to the conclusion it's necessary, but that smells 
for an outside reader. My understand from the Keda documentation is that the 
only requirement for custom resources to be Keda-scalable is to declare a 
`scale` sub-resource. Also, the path to the replicas spec is variable, and 
abstracted by the `scale` sub-resource. Does that mean Keda access the replicas 
spec directly, rather than via the `scale` endpoint?   

##########
File path: pkg/client/serverside.go
##########
@@ -0,0 +1,130 @@
+/*
+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 client
+
+import (
+       "context"
+       "fmt"
+       "net/http"
+       "strings"
+       "sync"
+       "sync/atomic"
+
+       "github.com/apache/camel-k/pkg/util/log"
+       "github.com/apache/camel-k/pkg/util/patch"
+       "github.com/pkg/errors"
+       k8serrors "k8s.io/apimachinery/pkg/api/errors"
+       "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
+       "k8s.io/apimachinery/pkg/runtime"
+       "k8s.io/apimachinery/pkg/types"
+       ctrl "sigs.k8s.io/controller-runtime/pkg/client"
+)
+
+type ServerOrClientSideApplier struct {
+       Client             ctrl.Client
+       hasServerSideApply atomic.Value
+       tryServerSideApply sync.Once
+}
+
+func (c *defaultClient) ServerOrClientSideApplier() ServerOrClientSideApplier {

Review comment:
       Maybe it could also be used in the _deployer_ trait while we are at it?

##########
File path: addons/keda/keda.go
##########
@@ -0,0 +1,551 @@
+/*
+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 keda
+
+import (
+       "bytes"
+       "encoding/json"
+       "fmt"
+       "sort"
+       "strings"
+       "text/template"
+
+       kedav1alpha1 "github.com/apache/camel-k/addons/keda/duck/v1alpha1"
+       camelv1 "github.com/apache/camel-k/pkg/apis/camel/v1"
+       camelv1alpha1 "github.com/apache/camel-k/pkg/apis/camel/v1alpha1"
+       "github.com/apache/camel-k/pkg/kamelet/repository"
+       "github.com/apache/camel-k/pkg/metadata"
+       "github.com/apache/camel-k/pkg/platform"
+       "github.com/apache/camel-k/pkg/trait"
+       "github.com/apache/camel-k/pkg/util"
+       "github.com/apache/camel-k/pkg/util/kubernetes"
+       "github.com/apache/camel-k/pkg/util/property"
+       "github.com/apache/camel-k/pkg/util/source"
+       "github.com/apache/camel-k/pkg/util/uri"
+       "github.com/pkg/errors"
+       scase "github.com/stoewer/go-strcase"
+       v1 "k8s.io/api/core/v1"
+       metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+       ctrl "sigs.k8s.io/controller-runtime/pkg/client"
+)
+
+const (
+       // kameletURNMetadataPrefix allows binding Kamelet properties to KEDA 
metadata.
+       kameletURNMetadataPrefix = "urn:keda:metadata:"
+       // kameletURNAuthenticationPrefix allows binding Kamelet properties to 
KEDA authentication options.
+       kameletURNAuthenticationPrefix = "urn:keda:authentication:"
+       // kameletURNRequiredTag is used to mark properties required by KEDA.
+       kameletURNRequiredTag = "urn:keda:required"
+
+       // kameletAnnotationType indicates the scaler type associated to a 
Kamelet.
+       kameletAnnotationType = "camel.apache.org/keda.type"
+       // kameletAnnotationMetadataPrefix is used to define virtual metadata 
fields computed from Kamelet properties.
+       kameletAnnotationMetadataPrefix = "camel.apache.org/keda.metadata."
+       // kameletAnnotationAuthenticationPrefix is used to define virtual 
authentication fields computed from Kamelet properties.
+       kameletAnnotationAuthenticationPrefix = 
"camel.apache.org/keda.authentication."
+)
+
+// The KEDA trait can be used for automatic integration with KEDA autoscalers.
+// The trait can be either manually configured using the `triggers` option or 
automatically configured
+// via markers in the Kamelets.
+//
+// For information on how to use KEDA enabled Kamelets with the KEDA trait, 
refer to
+// xref:ROOT:kamelets/kamelets-user.adoc#kamelet-keda-user[the KEDA section in 
the Kamelets user guide].
+// If you want to create Kamelets that contain KEDA metadata, refer to
+// xref:ROOT:kamelets/kamelets-dev.adoc#kamelet-keda-dev[the KEDA section in 
the Kamelets development guide].
+//
+// The KEDA trait is disabled by default.
+//
+// +camel-k:trait=keda.
+type kedaTrait struct {
+       trait.BaseTrait `property:",squash"`
+       // Enables automatic configuration of the trait. Allows the trait to 
infer KEDA triggers from the Kamelets.
+       Auto *bool `property:"auto" json:"auto,omitempty"`
+       // Convert metadata properties to camelCase (needed because Camel K 
trait properties use kebab-case from command line). Disabled by default.
+       CamelCaseConversion *bool `property:"camel-case-conversion" 
json:"camelCaseConversion,omitempty"`
+       // Set the spec->replicas field on the top level controller to an 
explicit value if missing, to allow KEDA to recognize it as a scalable resource.
+       HackControllerReplicas *bool `property:"hack-controller-replicas" 
json:"hackControllerReplicas,omitempty"`
+       // Interval (seconds) to check each trigger on (minimum 10 seconds).
+       PollingInterval *int32 `property:"polling-interval" 
json:"pollingInterval,omitempty"`
+       // The wait period between the last active trigger reported and scaling 
the resource back to 0.
+       CooldownPeriod *int32 `property:"cooldown-period" 
json:"cooldownPeriod,omitempty"`
+       // Enabling this property allows KEDA to scale the resource down to the 
specified number of replicas.
+       IdleReplicaCount *int32 `property:"idle-replica-count" 
json:"idleReplicaCount,omitempty"`
+       // Minimum number of replicas.
+       MinReplicaCount *int32 `property:"min-replica-count" 
json:"minReplicaCount,omitempty"`
+       // Maximum number of replicas.
+       MaxReplicaCount *int32 `property:"max-replica-count" 
json:"maxReplicaCount,omitempty"`
+       // Definition of triggers according to the KEDA format. Each trigger 
must contain `type` field corresponding
+       // to the name of a KEDA autoscaler and a key/value map named 
`metadata` containing specific trigger options.
+       // An optional `authentication-secret` can be declared per trigger and 
the operator will link each entry of
+       // the secret to a KEDA authentication parameter.
+       Triggers []kedaTrigger `property:"triggers" json:"triggers,omitempty"`
+}
+
+type kedaTrigger struct {
+       Type                 string            `property:"type" 
json:"type,omitempty"`
+       Metadata             map[string]string `property:"metadata" 
json:"metadata,omitempty"`
+       AuthenticationSecret string            
`property:"authentication-secret" json:"authenticationSecret,omitempty"`
+       authentication       map[string]string
+}
+
+// NewKedaTrait --.
+func NewKedaTrait() trait.Trait {
+       return &kedaTrait{
+               BaseTrait: trait.NewBaseTrait("keda", 
trait.TraitOrderPostProcessResources),
+       }
+}
+
+func (t *kedaTrait) Configure(e *trait.Environment) (bool, error) {
+       if t.Enabled == nil || !*t.Enabled {
+               return false, nil
+       }
+
+       if !e.IntegrationInPhase(camelv1.IntegrationPhaseInitialization) && 
!e.IntegrationInRunningPhases() {
+               return false, nil
+       }
+
+       if t.Auto == nil || *t.Auto {
+               if err := t.populateTriggersFromKamelets(e); err != nil {
+                       return false, err
+               }
+       }
+
+       return len(t.Triggers) > 0, nil
+}
+
+func (t *kedaTrait) Apply(e *trait.Environment) error {
+       if e.IntegrationInPhase(camelv1.IntegrationPhaseInitialization) {
+               if t.HackControllerReplicas == nil || *t.HackControllerReplicas 
{
+                       if err := t.hackControllerReplicas(e); err != nil {
+                               return err
+                       }
+               }
+       } else if e.IntegrationInRunningPhases() {
+               if err := t.addScalingResources(e); err != nil {
+                       return err
+               }
+       }
+
+       return nil
+}
+
+func (t *kedaTrait) addScalingResources(e *trait.Environment) error {
+       if len(t.Triggers) == 0 {
+               return nil
+       }
+
+       obj := kedav1alpha1.NewScaledObject(e.Integration.Namespace, 
e.Integration.Name)
+       obj.Spec.ScaleTargetRef = t.getTopControllerReference(e)
+       if t.PollingInterval != nil {
+               obj.Spec.PollingInterval = t.PollingInterval
+       }
+       if t.CooldownPeriod != nil {
+               obj.Spec.CooldownPeriod = t.CooldownPeriod
+       }
+       if t.IdleReplicaCount != nil {
+               obj.Spec.IdleReplicaCount = t.IdleReplicaCount
+       }
+       if t.MinReplicaCount != nil {
+               obj.Spec.MinReplicaCount = t.MinReplicaCount
+       }
+       if t.MaxReplicaCount != nil {
+               obj.Spec.MaxReplicaCount = t.MaxReplicaCount
+       }
+       for idx, trigger := range t.Triggers {
+               meta := make(map[string]string)
+               for k, v := range trigger.Metadata {
+                       kk := k
+                       if t.CamelCaseConversion != nil && 
*t.CamelCaseConversion {
+                               kk = scase.LowerCamelCase(k)
+                       }
+                       meta[kk] = v
+               }
+               var authenticationRef *kedav1alpha1.ScaledObjectAuthRef
+               if len(trigger.authentication) > 0 && 
trigger.AuthenticationSecret != "" {
+                       return errors.New("an authentication secret cannot be 
provided for auto-configured triggers")
+               }
+               extConfigName := fmt.Sprintf("%s-keda-%d", e.Integration.Name, 
idx)
+               if len(trigger.authentication) > 0 {
+                       // Save all authentication config in a secret
+                       secret := v1.Secret{
+                               TypeMeta: metav1.TypeMeta{
+                                       Kind:       "Secret",
+                                       APIVersion: 
v1.SchemeGroupVersion.String(),
+                               },
+                               ObjectMeta: metav1.ObjectMeta{
+                                       Namespace: e.Integration.Namespace,
+                                       Name:      extConfigName,
+                               },
+                               StringData: trigger.authentication,
+                       }
+                       e.Resources.Add(&secret)
+
+                       // Link the secret using a TriggerAuthentication
+                       triggerAuth := kedav1alpha1.TriggerAuthentication{
+                               TypeMeta: metav1.TypeMeta{
+                                       Kind:       "TriggerAuthentication",
+                                       APIVersion: 
kedav1alpha1.SchemeGroupVersion.String(),
+                               },
+                               ObjectMeta: metav1.ObjectMeta{
+                                       Namespace: e.Integration.Namespace,
+                                       Name:      extConfigName,
+                               },
+                       }
+                       for _, k := range 
util.SortedStringMapKeys(trigger.authentication) {
+                               triggerAuth.Spec.SecretTargetRef = 
append(triggerAuth.Spec.SecretTargetRef, kedav1alpha1.AuthSecretTargetRef{
+                                       Parameter: k,
+                                       Name:      extConfigName,
+                                       Key:       k,
+                               })
+                       }
+                       e.Resources.Add(&triggerAuth)
+                       authenticationRef = &kedav1alpha1.ScaledObjectAuthRef{
+                               Name: extConfigName,
+                       }
+               } else if trigger.AuthenticationSecret != "" {
+                       s := v1.Secret{}
+                       key := ctrl.ObjectKey{
+                               Namespace: e.Integration.Namespace,
+                               Name:      trigger.AuthenticationSecret,
+                       }
+                       if err := e.Client.Get(e.Ctx, key, &s); err != nil {
+                               return errors.Wrapf(err, "could not load secret 
named %q in namespace %q", trigger.AuthenticationSecret, 
e.Integration.Namespace)
+                       }
+                       // Fill a TriggerAuthentication from the secret
+                       triggerAuth := kedav1alpha1.TriggerAuthentication{
+                               TypeMeta: metav1.TypeMeta{
+                                       Kind:       "TriggerAuthentication",
+                                       APIVersion: 
kedav1alpha1.SchemeGroupVersion.String(),
+                               },
+                               ObjectMeta: metav1.ObjectMeta{
+                                       Namespace: e.Integration.Namespace,
+                                       Name:      extConfigName,
+                               },
+                       }
+                       sortedKeys := make([]string, 0, len(s.Data))
+                       for k := range s.Data {
+                               sortedKeys = append(sortedKeys, k)
+                       }
+                       sort.Strings(sortedKeys)
+                       for _, k := range sortedKeys {
+                               triggerAuth.Spec.SecretTargetRef = 
append(triggerAuth.Spec.SecretTargetRef, kedav1alpha1.AuthSecretTargetRef{
+                                       Parameter: k,
+                                       Name:      s.Name,
+                                       Key:       k,
+                               })
+                       }
+                       e.Resources.Add(&triggerAuth)
+                       authenticationRef = &kedav1alpha1.ScaledObjectAuthRef{
+                               Name: extConfigName,
+                       }
+               }
+
+               st := kedav1alpha1.ScaleTriggers{
+                       Type:              trigger.Type,
+                       Metadata:          meta,
+                       AuthenticationRef: authenticationRef,
+               }
+               obj.Spec.Triggers = append(obj.Spec.Triggers, st)
+       }
+       e.Resources.Add(&obj)
+       return nil
+}
+
+func (t *kedaTrait) hackControllerReplicas(e *trait.Environment) error {
+       ctrlRef := t.getTopControllerReference(e)
+       if ctrlRef.Kind == camelv1alpha1.KameletBindingKind {
+               // Update the KameletBinding directly (do not add it to env 
resources, it's the integration parent)
+               key := ctrl.ObjectKey{
+                       Namespace: e.Integration.Namespace,
+                       Name:      ctrlRef.Name,
+               }
+               klb := camelv1alpha1.KameletBinding{}
+               if err := e.Client.Get(e.Ctx, key, &klb); err != nil {
+                       return err
+               }
+               if klb.Spec.Replicas == nil {
+                       one := int32(1)
+                       klb.Spec.Replicas = &one
+                       if err := e.Client.Update(e.Ctx, &klb); err != nil {
+                               return err
+                       }
+               }
+       } else if e.Integration.Spec.Replicas == nil {
+               one := int32(1)
+               e.Integration.Spec.Replicas = &one
+               // Update the Integration directly as the spec section is not 
merged by default

Review comment:
       nit: Maybe patching the `scale` endpoint could be used instead, rather 
than updating the whole resource:
   
   
https://github.com/apache/camel-k/blob/fef775de02b3a59b9c844ba8bf9c418bf8a708b7/e2e/common/scale_integration_test.go#L79




-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


Reply via email to