Skip to content

Commit

Permalink
fix(#5402): Evaluate Knative profile based on Serving/Eventing installed
Browse files Browse the repository at this point in the history
- Use Knative profile when Serving or Eventing is installed on cluster
- Make sure to enable Knative trait when Serving or Eventing is installed
- Enable knative-service trait only when Knative Serving is installed
- Garbage collect Serving and Eventing resources in gc trait only when Serving/Eventing is installed on the cluster
- Do not use Serving service in Knative trigger when not installed on cluster
- Use arbitrary Service as a subscriber in Knative trigger when Serving is not available
  • Loading branch information
christophd committed Apr 26, 2024
1 parent 698b470 commit d558b0d
Show file tree
Hide file tree
Showing 12 changed files with 469 additions and 69 deletions.
2 changes: 1 addition & 1 deletion pkg/controller/integration/platform_setup.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ func determineBestTraitProfile(c client.Client, integration *v1.Integration, p *
// Use platform spec profile if set
return p.Spec.Profile, nil
}
if ok, err := knative.IsServingInstalled(c); err != nil {
if ok, err := knative.IsInstalled(c); err != nil {
return "", err
} else if ok {
return v1.TraitProfileKnative, nil
Expand Down
2 changes: 1 addition & 1 deletion pkg/controller/kameletbinding/integration.go
Original file line number Diff line number Diff line change
Expand Up @@ -248,7 +248,7 @@ func determineTraitProfile(ctx context.Context, c client.Client, binding *v1alph
return pl.Spec.Profile, nil
}
}
if ok, err := knative.IsServingInstalled(c); err != nil {
if ok, err := knative.IsInstalled(c); err != nil {
return "", err
} else if ok {
return v1.TraitProfileKnative, nil
Expand Down
2 changes: 1 addition & 1 deletion pkg/controller/pipe/integration.go
Original file line number Diff line number Diff line change
Expand Up @@ -248,7 +248,7 @@ func determineTraitProfile(ctx context.Context, c client.Client, binding *v1.Pip
return pl.Spec.Profile, nil
}
}
if ok, err := knative.IsServingInstalled(c); err != nil {
if ok, err := knative.IsInstalled(c); err != nil {
return "", err
} else if ok {
return v1.TraitProfileKnative, nil
Expand Down
45 changes: 25 additions & 20 deletions pkg/trait/gc.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ 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/util"
"github.com/apache/camel-k/v2/pkg/util/knative"
"github.com/apache/camel-k/v2/pkg/util/log"
)

Expand Down Expand Up @@ -86,20 +87,6 @@ var (
Version: batchv1.SchemeGroupVersion.Version,
}: {},
}
deletableTypesByProfile = map[v1.TraitProfile]map[schema.GroupVersionKind]struct{}{
v1.TraitProfileKnative: {
schema.GroupVersionKind{
Kind: "Service",
Group: "serving.knative.dev",
Version: "v1",
}: {},
schema.GroupVersionKind{
Kind: "Trigger",
Group: "eventing.knative.dev",
Version: "v1",
}: {},
},
}
)

type gcTrait struct {
Expand Down Expand Up @@ -160,12 +147,30 @@ func (t *gcTrait) garbageCollectResources(e *Environment) error {
}

profile := e.DetermineProfile()
if profileDeletableTypes, ok := deletableTypesByProfile[profile]; ok {
// copy profile related deletable types if not already present
for key, value := range profileDeletableTypes {
if _, found := deletableGVKs[key]; !found {
deletableGVKs[key] = value
}
deletableTypesByProfile := map[schema.GroupVersionKind]struct{}{}

if profile == v1.TraitProfileKnative {
if ok, _ := knative.IsServingInstalled(e.Client); ok {
deletableTypesByProfile[schema.GroupVersionKind{
Kind: "Service",
Group: "serving.knative.dev",
Version: "v1",
}] = struct{}{}
}

if ok, _ := knative.IsEventingInstalled(e.Client); ok {
deletableTypesByProfile[schema.GroupVersionKind{
Kind: "Trigger",
Group: "eventing.knative.dev",
Version: "v1",
}] = struct{}{}
}
}

// copy profile related deletable types if not already present
for key, value := range deletableTypesByProfile {
if _, found := deletableGVKs[key]; !found {
deletableGVKs[key] = value
}
}

Expand Down
31 changes: 28 additions & 3 deletions pkg/trait/knative.go
Original file line number Diff line number Diff line change
Expand Up @@ -331,7 +331,9 @@ func (t *knativeTrait) configureEvents(e *Environment, env *knativeapi.CamelEnvi
serviceName = "default"
}
servicePath := fmt.Sprintf("/events/%s", eventType)
t.createTrigger(e, ref, eventType, servicePath)
if triggerErr := t.createTrigger(e, ref, eventType, servicePath); triggerErr != nil {
return triggerErr
}

if !env.ContainsService(serviceName, knativeapi.CamelEndpointKindSource, knativeapi.CamelServiceTypeEvent, ref.APIVersion, ref.Kind) {
svc := knativeapi.CamelServiceDefinition{
Expand Down Expand Up @@ -475,7 +477,7 @@ func (t *knativeTrait) configureSinkBinding(e *Environment, env *knativeapi.Came
return err
}

func (t *knativeTrait) createTrigger(e *Environment, ref *corev1.ObjectReference, eventType string, path string) {
func (t *knativeTrait) createTrigger(e *Environment, ref *corev1.ObjectReference, eventType string, path string) error {
// TODO extend to additional filters too, to filter them at source and not at destination
found := e.Resources.HasKnativeTrigger(func(trigger *eventing.Trigger) bool {
return trigger.Spec.Broker == ref.Name &&
Expand All @@ -486,9 +488,32 @@ func (t *knativeTrait) createTrigger(e *Environment, ref *corev1.ObjectReference
if ref.Namespace == "" {
ref.Namespace = e.Integration.Namespace
}
trigger := knativeutil.CreateTrigger(*ref, e.Integration.Name, eventType, path)

controllerStrategy, err := e.DetermineControllerStrategy()
if err != nil {
return err
}

var trigger *eventing.Trigger
switch controllerStrategy {
case ControllerStrategyKnativeService:
trigger, err = knativeutil.CreateKnativeServiceTrigger(*ref, e.Integration.Name, eventType, path)
if err != nil {
return err
}
case ControllerStrategyDeployment:
trigger, err = knativeutil.CreateServiceTrigger(*ref, e.Integration.Name, eventType, path)
if err != nil {
return err
}
default:
return fmt.Errorf("failed to create Knative trigger: unsupported controller strategy %s", controllerStrategy)
}

e.Resources.Add(trigger)
}

return nil
}

func (t *knativeTrait) ifServiceMissingDo(
Expand Down
6 changes: 6 additions & 0 deletions pkg/trait/knative_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ 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/knative"
"github.com/apache/camel-k/v2/pkg/util/kubernetes"
)

Expand Down Expand Up @@ -149,6 +150,11 @@ func (t *knativeServiceTrait) SelectControllerStrategy(e *Environment) (*Control
return nil, nil
}

// Knative serving is required
if ok, _ := knative.IsServingInstalled(e.Client); !ok {
return nil, nil
}

var sources []v1.SourceSpec
var err error
if sources, err = kubernetes.ResolveIntegrationSources(e.Ctx, t.Client, e.Integration, e.Resources); err != nil {
Expand Down
75 changes: 75 additions & 0 deletions pkg/trait/knative_service_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -414,6 +414,81 @@ func TestKnativeServiceNotApplicable(t *testing.T) {
}))
}

func TestKnativeServiceNoServingAvailable(t *testing.T) {
catalog, err := camel.DefaultCatalog()
require.NoError(t, err)

client, _ := test.NewFakeClient()
fakeClient := client.(*test.FakeClient) //nolint
fakeClient.DisableKnativeServing()

traitCatalog := NewCatalog(nil)

environment := Environment{
CamelCatalog: catalog,
Catalog: traitCatalog,
Client: client,
Integration: &v1.Integration{
ObjectMeta: metav1.ObjectMeta{
Name: KnativeServiceTestName,
Namespace: KnativeServiceTestNamespace,
},
Status: v1.IntegrationStatus{
Phase: v1.IntegrationPhaseDeploying,
},
Spec: v1.IntegrationSpec{
Profile: v1.TraitProfileKnative,
Sources: []v1.SourceSpec{
{
DataSpec: v1.DataSpec{
Name: "routes.js",
Content: `from("platform-http:test").log("hello")`,
},
Language: v1.LanguageJavaScript,
},
},
},
},
IntegrationKit: &v1.IntegrationKit{
Status: v1.IntegrationKitStatus{
Phase: v1.IntegrationKitPhaseReady,
},
},
Platform: &v1.IntegrationPlatform{
Spec: v1.IntegrationPlatformSpec{
Cluster: v1.IntegrationPlatformClusterOpenShift,
Build: v1.IntegrationPlatformBuildSpec{
PublishStrategy: v1.IntegrationPlatformBuildPublishStrategyS2I,
Registry: v1.RegistrySpec{Address: "registry"},
RuntimeVersion: catalog.Runtime.Version,
},
},
Status: v1.IntegrationPlatformStatus{
Phase: v1.IntegrationPlatformPhaseReady,
},
},
EnvVars: make([]corev1.EnvVar, 0),
ExecutedTraits: make([]Trait, 0),
Resources: kubernetes.NewCollection(),
}
environment.Platform.ResyncStatusFullConfig()

// don't care about conditions in this unit test
_, err = traitCatalog.apply(&environment)

require.NoError(t, err)
assert.NotEmpty(t, environment.ExecutedTraits)
assert.Nil(t, environment.GetTrait("knative-service"))

assert.Nil(t, environment.Resources.GetKnativeService(func(service *serving.Service) bool {
return service.Name == KnativeServiceTestName
}))

assert.NotNil(t, environment.Resources.GetDeployment(func(deployment *appsv1.Deployment) bool {
return deployment.Name == KnativeServiceTestName
}))
}

func TestKnativeServiceWithRollout(t *testing.T) {
environment := createKnativeServiceTestEnvironment(t, &traitv1.KnativeServiceTrait{RolloutDuration: "60s"})
assert.NotEmpty(t, environment.ExecutedTraits)
Expand Down
Loading

0 comments on commit d558b0d

Please sign in to comment.