This is an automated email from the ASF dual-hosted git repository. pcongiusti pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/camel-k.git
The following commit(s) were added to refs/heads/main by this push: new 58c4fdac8 fix(knative): enable service container port 58c4fdac8 is described below commit 58c4fdac889eaccb938aa4b26b24116842d37ed6 Author: Pasquale Congiusti <pasquale.congiu...@gmail.com> AuthorDate: Wed Mar 27 10:57:17 2024 +0100 fix(knative): enable service container port The container port was skipped in case of a Knative service, as the Service resource is missing in such case. --- pkg/trait/container.go | 100 +++++++++++++++------------------- pkg/trait/container_test.go | 127 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 169 insertions(+), 58 deletions(-) diff --git a/pkg/trait/container.go b/pkg/trait/container.go index b58842df1..7d32a06d6 100644 --- a/pkg/trait/container.go +++ b/pkg/trait/container.go @@ -176,57 +176,36 @@ func (t *containerTrait) configureContainer(e *Environment) error { if e.ApplicationProperties == nil { e.ApplicationProperties = make(map[string]string) } - container := corev1.Container{ Name: t.Name, Image: e.Integration.Status.Image, Env: make([]corev1.EnvVar, 0), } - if t.ImagePullPolicy != "" { container.ImagePullPolicy = t.ImagePullPolicy } - // combine Environment of integration with platform, kit, integration for _, env := range e.collectConfigurationPairs("env") { envvar.SetVal(&container.Env, env.Name, env.Value) } - envvar.SetVal(&container.Env, digest.IntegrationDigestEnvVar, e.Integration.Status.Digest) envvar.SetVal(&container.Env, "CAMEL_K_CONF", filepath.Join(camel.BasePath, "application.properties")) envvar.SetVal(&container.Env, "CAMEL_K_CONF_D", camel.ConfDPath) - e.addSourcesProperties() - if props, err := e.computeApplicationProperties(); err != nil { - return err - } else if props != nil { - e.Resources.Add(props) - } - - t.configureResources(&container) - if pointer.BoolDeref(t.Expose, false) { - t.configureService(e, &container) - } - t.configureCapabilities(e) - - t.configureSecurityContext(e, &container) - var containers *[]corev1.Container visited := false - + knative := false // Deployment if err := e.Resources.VisitDeploymentE(func(deployment *appsv1.Deployment) error { for _, envVar := range e.EnvVars { envvar.SetVar(&container.Env, envVar) } - containers = &deployment.Spec.Template.Spec.Containers visited = true return nil }); err != nil { return err } - // Knative Service if err := e.Resources.VisitKnativeServiceE(func(service *serving.Service) error { for _, env := range e.EnvVars { @@ -236,34 +215,43 @@ func (t *containerTrait) configureContainer(e *Environment) error { case env.ValueFrom.FieldRef != nil && env.ValueFrom.FieldRef.FieldPath == "metadata.namespace": envvar.SetVar(&container.Env, corev1.EnvVar{Name: env.Name, Value: e.Integration.Namespace}) case env.ValueFrom.FieldRef != nil: - t.L.Infof("Skipping environment variable %s (fieldRef)", env.Name) + t.L.Debugf("Skipping environment variable %s (fieldRef)", env.Name) case env.ValueFrom.ResourceFieldRef != nil: - t.L.Infof("Skipping environment variable %s (resourceFieldRef)", env.Name) + t.L.Debugf("Skipping environment variable %s (resourceFieldRef)", env.Name) default: envvar.SetVar(&container.Env, env) } } - containers = &service.Spec.ConfigurationSpec.Template.Spec.Containers visited = true + knative = true return nil }); err != nil { return err } - // CronJob if err := e.Resources.VisitCronJobE(func(cron *batchv1.CronJob) error { for _, envVar := range e.EnvVars { envvar.SetVar(&container.Env, envVar) } - containers = &cron.Spec.JobTemplate.Spec.Template.Spec.Containers visited = true return nil }); err != nil { return err } - + e.addSourcesProperties() + if props, err := e.computeApplicationProperties(); err != nil { + return err + } else if props != nil { + e.Resources.Add(props) + } + t.configureResources(&container) + if knative || pointer.BoolDeref(t.Expose, false) { + t.configureService(e, &container, knative) + } + t.configureCapabilities(e) + t.configureSecurityContext(e, &container) if visited { *containers = append(*containers, container) } @@ -271,46 +259,42 @@ func (t *containerTrait) configureContainer(e *Environment) error { return nil } -func (t *containerTrait) configureService(e *Environment, container *corev1.Container) { - service := e.Resources.GetServiceForIntegration(e.Integration) - if service == nil { - return - } - +func (t *containerTrait) configureService(e *Environment, container *corev1.Container, isKnative bool) { name := t.PortName if name == "" { name = defaultContainerPortName } - containerPort := corev1.ContainerPort{ - Name: name, ContainerPort: int32(t.Port), Protocol: corev1.ProtocolTCP, } - - servicePort := corev1.ServicePort{ - Name: t.ServicePortName, - Port: int32(t.ServicePort), - Protocol: corev1.ProtocolTCP, - TargetPort: intstr.FromString(name), + if !isKnative { + // Knative does not want name=http + containerPort.Name = name + // The service is managed by Knative, so, we only take care of this when it's managed by us + service := e.Resources.GetServiceForIntegration(e.Integration) + if service != nil { + servicePort := corev1.ServicePort{ + Name: t.ServicePortName, + Port: int32(t.ServicePort), + Protocol: corev1.ProtocolTCP, + TargetPort: intstr.FromString(name), + } + e.Integration.Status.SetCondition( + v1.IntegrationConditionServiceAvailable, + corev1.ConditionTrue, + v1.IntegrationConditionServiceAvailableReason, + // service -> container + fmt.Sprintf("%s(%s/%d) -> %s(%s/%d)", + service.Name, servicePort.Name, servicePort.Port, + container.Name, containerPort.Name, containerPort.ContainerPort), + ) + service.Spec.Ports = append(service.Spec.Ports, servicePort) + // Mark the service as a user service + service.Labels["camel.apache.org/service.type"] = v1.ServiceTypeUser + } } - - e.Integration.Status.SetCondition( - v1.IntegrationConditionServiceAvailable, - corev1.ConditionTrue, - v1.IntegrationConditionServiceAvailableReason, - - // service -> container - fmt.Sprintf("%s(%s/%d) -> %s(%s/%d)", - service.Name, servicePort.Name, servicePort.Port, - container.Name, containerPort.Name, containerPort.ContainerPort), - ) - container.Ports = append(container.Ports, containerPort) - service.Spec.Ports = append(service.Spec.Ports, servicePort) - - // Mark the service as a user service - service.Labels["camel.apache.org/service.type"] = v1.ServiceTypeUser } func (t *containerTrait) configureResources(container *corev1.Container) { diff --git a/pkg/trait/container_test.go b/pkg/trait/container_test.go index 6d039cda8..176dd9794 100644 --- a/pkg/trait/container_test.go +++ b/pkg/trait/container_test.go @@ -528,3 +528,130 @@ func createEnvironment() *Environment { return environment } + +func TestDeploymentContainerPorts(t *testing.T) { + catalog, err := camel.DefaultCatalog() + require.NoError(t, err) + + client, _ := test.NewFakeClient() + traitCatalog := NewCatalog(nil) + + environment := Environment{ + Ctx: context.TODO(), + Client: client, + CamelCatalog: catalog, + Catalog: traitCatalog, + Integration: &v1.Integration{ + Spec: v1.IntegrationSpec{ + Profile: v1.TraitProfileKubernetes, + Traits: v1.Traits{ + Container: &traitv1.ContainerTrait{ + Port: 8081, + ServicePort: 8081, + }, + }, + Sources: []v1.SourceSpec{ + { + Language: v1.LanguageJavaSource, + DataSpec: v1.DataSpec{ + Name: "MyTest.java", + Content: ` + public class MyRouteBuilder extends RouteBuilder { + @Override + public void configure() throws Exception { + from("netty-http:http://0.0.0.0:8081/hello").log("Received message: ${body}"); + } + } + `, + }, + }, + }, + }, + }, + Platform: &v1.IntegrationPlatform{ + Spec: v1.IntegrationPlatformSpec{ + Build: v1.IntegrationPlatformBuildSpec{ + RuntimeVersion: catalog.Runtime.Version, + }, + }, + Status: v1.IntegrationPlatformStatus{ + Phase: v1.IntegrationPlatformPhaseReady, + }, + }, + Resources: kubernetes.NewCollection(), + } + environment.Integration.Status.Phase = v1.IntegrationPhaseDeploying + environment.Platform.ResyncStatusFullConfig() + + _, err = traitCatalog.apply(&environment) + require.NoError(t, err) + container := environment.GetIntegrationContainer() + assert.Len(t, container.Ports, 1) + assert.Equal(t, int32(8081), container.Ports[0].ContainerPort) + assert.Equal(t, "http", container.Ports[0].Name) + svc := environment.Resources.GetServiceForIntegration(environment.Integration) + assert.Len(t, svc.Spec.Ports, 1) + assert.Equal(t, int32(8081), svc.Spec.Ports[0].Port) +} + +func TestKnativeServiceContainerPorts(t *testing.T) { + catalog, err := camel.DefaultCatalog() + require.NoError(t, err) + + client, _ := test.NewFakeClient() + traitCatalog := NewCatalog(nil) + + environment := Environment{ + Ctx: context.TODO(), + Client: client, + CamelCatalog: catalog, + Catalog: traitCatalog, + Integration: &v1.Integration{ + Spec: v1.IntegrationSpec{ + Profile: v1.TraitProfileKnative, + Traits: v1.Traits{ + Container: &traitv1.ContainerTrait{ + Port: 8081, + ServicePort: 8081, + }, + }, + Sources: []v1.SourceSpec{ + { + Language: v1.LanguageJavaSource, + DataSpec: v1.DataSpec{ + Name: "MyTest.java", + Content: ` + public class MyRouteBuilder extends RouteBuilder { + @Override + public void configure() throws Exception { + from("netty-http:http://0.0.0.0:8081/hello").log("Received message: ${body}"); + } + } + `, + }, + }, + }, + }, + }, + Platform: &v1.IntegrationPlatform{ + Spec: v1.IntegrationPlatformSpec{ + Build: v1.IntegrationPlatformBuildSpec{ + RuntimeVersion: catalog.Runtime.Version, + }, + }, + Status: v1.IntegrationPlatformStatus{ + Phase: v1.IntegrationPlatformPhaseReady, + }, + }, + Resources: kubernetes.NewCollection(), + } + environment.Integration.Status.Phase = v1.IntegrationPhaseDeploying + environment.Platform.ResyncStatusFullConfig() + + _, err = traitCatalog.apply(&environment) + require.NoError(t, err) + container := environment.GetIntegrationContainer() + assert.Len(t, container.Ports, 1) + assert.Equal(t, int32(8081), container.Ports[0].ContainerPort) + assert.Equal(t, "", container.Ports[0].Name) +}