You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by as...@apache.org on 2021/04/15 11:54:10 UTC
[camel-k] 02/05: feat(monitoring): Migrate to PodMonitor in
Prometheus trait
This is an automated email from the ASF dual-hosted git repository.
astefanutti pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/camel-k.git
commit c61f1400dc78617b9cee46270d62e5ade1572134
Author: Antonin Stefanutti <an...@stefanutti.fr>
AuthorDate: Tue Apr 13 18:47:31 2021 +0200
feat(monitoring): Migrate to PodMonitor in Prometheus trait
---
e2e/common/operator_metrics_test.go | 47 ++++++------
e2e/common/traits/prometheus_test.go | 36 ++++-----
pkg/cmd/run_test.go | 4 +-
pkg/trait/container.go | 43 ++++++-----
pkg/trait/prometheus.go | 139 ++++++++++++++---------------------
pkg/trait/prometheus_test.go | 82 ++++-----------------
pkg/trait/route.go | 2 +-
pkg/trait/route_test.go | 2 +-
pkg/trait/service.go | 5 +-
pkg/trait/trait_types.go | 24 ++++++
pkg/util/kubernetes/collection.go | 14 ++--
11 files changed, 167 insertions(+), 231 deletions(-)
diff --git a/e2e/common/operator_metrics_test.go b/e2e/common/operator_metrics_test.go
index 7814eef..fa10779 100644
--- a/e2e/common/operator_metrics_test.go
+++ b/e2e/common/operator_metrics_test.go
@@ -31,14 +31,15 @@ import (
. "github.com/onsi/gomega"
. "github.com/onsi/gomega/gstruct"
"github.com/onsi/gomega/types"
- v1 "k8s.io/api/core/v1"
+
+ corev1 "k8s.io/api/core/v1"
prometheus "github.com/prometheus/client_model/go"
"github.com/prometheus/common/expfmt"
. "github.com/apache/camel-k/e2e/support"
. "github.com/apache/camel-k/e2e/support/util"
- camelv1 "github.com/apache/camel-k/pkg/apis/camel/v1"
+ v1 "github.com/apache/camel-k/pkg/apis/camel/v1"
)
func TestMetrics(t *testing.T) {
@@ -47,15 +48,15 @@ func TestMetrics(t *testing.T) {
Expect(Kamel("install", "-n", ns).Execute()).To(Succeed())
Expect(Kamel("run", "-n", ns, "files/Java.java",
"-t", "prometheus.enabled=true",
- "-t", "prometheus.service-monitor=false").Execute()).To(Succeed())
- Eventually(IntegrationPodPhase(ns, name), TestTimeoutMedium).Should(Equal(v1.PodRunning))
- Eventually(IntegrationCondition(ns, name, camelv1.IntegrationConditionReady), TestTimeoutShort).Should(Equal(v1.ConditionTrue))
+ "-t", "prometheus.pod-monitor=false").Execute()).To(Succeed())
+ Eventually(IntegrationPodPhase(ns, name), TestTimeoutMedium).Should(Equal(corev1.PodRunning))
+ Eventually(IntegrationCondition(ns, name, v1.IntegrationConditionReady), TestTimeoutShort).Should(Equal(corev1.ConditionTrue))
Eventually(IntegrationLogs(ns, "java"), TestTimeoutShort).Should(ContainSubstring("Magicstring!"))
pod := OperatorPod(ns)()
Expect(pod).NotTo(BeNil())
- logs := StructuredLogs(ns, pod.Name, v1.PodLogOptions{})
+ logs := StructuredLogs(ns, pod.Name, corev1.PodLogOptions{})
Expect(logs).NotTo(BeEmpty())
response, err := TestClient().CoreV1().RESTClient().Get().
@@ -80,7 +81,7 @@ func TestMetrics(t *testing.T) {
AddStep(MatchFields(IgnoreExtras, Fields{
"LoggerName": Equal("camel-k.controller.build"),
"Message": Equal("Build state transition"),
- "Phase": Equal(string(camelv1.BuildPhasePending)),
+ "Phase": Equal(string(v1.BuildPhasePending)),
"RequestName": Equal(build.Name),
}), LogEntryNoop).
AddStep(MatchFields(IgnoreExtras, Fields{
@@ -188,8 +189,8 @@ func TestMetrics(t *testing.T) {
platformReconciled := getMetric(metrics["camel_k_reconciliation_duration_seconds"],
MatchFieldsP(IgnoreExtras, Fields{
"Label": ConsistOf(
- label("group", camelv1.SchemeGroupVersion.Group),
- label("version", camelv1.SchemeGroupVersion.Version),
+ label("group", v1.SchemeGroupVersion.Group),
+ label("version", v1.SchemeGroupVersion.Version),
label("kind", "IntegrationPlatform"),
label("namespace", ns),
label("result", "Reconciled"),
@@ -203,8 +204,8 @@ func TestMetrics(t *testing.T) {
platformRequeued := getMetric(metrics["camel_k_reconciliation_duration_seconds"],
MatchFieldsP(IgnoreExtras, Fields{
"Label": ConsistOf(
- label("group", camelv1.SchemeGroupVersion.Group),
- label("version", camelv1.SchemeGroupVersion.Version),
+ label("group", v1.SchemeGroupVersion.Group),
+ label("version", v1.SchemeGroupVersion.Version),
label("kind", "IntegrationPlatform"),
label("namespace", ns),
label("result", "Requeued"),
@@ -236,8 +237,8 @@ func TestMetrics(t *testing.T) {
"Type": EqualP(prometheus.MetricType_HISTOGRAM),
"Metric": ContainElement(MatchFieldsP(IgnoreExtras, Fields{
"Label": ConsistOf(
- label("group", camelv1.SchemeGroupVersion.Group),
- label("version", camelv1.SchemeGroupVersion.Version),
+ label("group", v1.SchemeGroupVersion.Group),
+ label("version", v1.SchemeGroupVersion.Version),
label("kind", "Integration"),
label("namespace", it.Namespace),
label("result", "Reconciled"),
@@ -268,8 +269,8 @@ func TestMetrics(t *testing.T) {
"Type": EqualP(prometheus.MetricType_HISTOGRAM),
"Metric": ContainElement(MatchFieldsP(IgnoreExtras, Fields{
"Label": ConsistOf(
- label("group", camelv1.SchemeGroupVersion.Group),
- label("version", camelv1.SchemeGroupVersion.Version),
+ label("group", v1.SchemeGroupVersion.Group),
+ label("version", v1.SchemeGroupVersion.Version),
label("kind", "IntegrationKit"),
label("namespace", it.Status.IntegrationKit.Namespace),
label("result", "Reconciled"),
@@ -295,8 +296,8 @@ func TestMetrics(t *testing.T) {
buildReconciled := getMetric(metrics["camel_k_reconciliation_duration_seconds"],
MatchFieldsP(IgnoreExtras, Fields{
"Label": ConsistOf(
- label("group", camelv1.SchemeGroupVersion.Group),
- label("version", camelv1.SchemeGroupVersion.Version),
+ label("group", v1.SchemeGroupVersion.Group),
+ label("version", v1.SchemeGroupVersion.Version),
label("kind", "Build"),
label("namespace", build.Namespace),
label("result", "Reconciled"),
@@ -310,8 +311,8 @@ func TestMetrics(t *testing.T) {
buildRequeued := getMetric(metrics["camel_k_reconciliation_duration_seconds"],
MatchFieldsP(IgnoreExtras, Fields{
"Label": ConsistOf(
- label("group", camelv1.SchemeGroupVersion.Group),
- label("version", camelv1.SchemeGroupVersion.Version),
+ label("group", v1.SchemeGroupVersion.Group),
+ label("version", v1.SchemeGroupVersion.Version),
label("kind", "Build"),
label("namespace", build.Namespace),
label("result", "Requeued"),
@@ -336,7 +337,7 @@ func TestMetrics(t *testing.T) {
AddStep(MatchFields(IgnoreExtras, Fields{
"LoggerName": Equal("camel-k.controller.build"),
"Message": Equal("Build state transition"),
- "Phase": Equal(string(camelv1.BuildPhasePending)),
+ "Phase": Equal(string(v1.BuildPhasePending)),
"RequestName": Equal(build.Name),
}), func(l *LogEntry) { ts2 = l.Timestamp.Time }).
Walk()
@@ -385,7 +386,7 @@ func TestMetrics(t *testing.T) {
ts1 = it.Status.InitializationTimestamp.Time
Expect(ts1).NotTo(BeZero())
// The end time is reported into the ready condition first truthy time
- ts2 = it.Status.GetCondition(camelv1.IntegrationConditionReady).FirstTruthyTime.Time
+ ts2 = it.Status.GetCondition(v1.IntegrationConditionReady).FirstTruthyTime.Time
Expect(ts2).NotTo(BeZero())
duration := ts2.Sub(ts1)
@@ -396,8 +397,8 @@ func TestMetrics(t *testing.T) {
"LoggerName": Equal("camel-k.controller.integration"),
"Message": Equal("Reconciling Integration"),
"RequestName": Equal(it.Name),
- "PhaseFrom": Equal(string(camelv1.IntegrationPhaseInitialization)),
- "PhaseTo": Equal(string(camelv1.IntegrationPhaseBuildingKit)),
+ "PhaseFrom": Equal(string(v1.IntegrationPhaseInitialization)),
+ "PhaseTo": Equal(string(v1.IntegrationPhaseBuildingKit)),
}), func(l *LogEntry) { ts1 = l.Timestamp.Time }).
AddStep(MatchFields(IgnoreExtras, Fields{
"LoggerName": Equal("camel-k.controller.integration"),
diff --git a/e2e/common/traits/prometheus_test.go b/e2e/common/traits/prometheus_test.go
index e3204ca..91ce909 100644
--- a/e2e/common/traits/prometheus_test.go
+++ b/e2e/common/traits/prometheus_test.go
@@ -29,9 +29,9 @@ import (
"github.com/stretchr/testify/assert"
v1 "k8s.io/api/core/v1"
- k8serrors "k8s.io/apimachinery/pkg/api/errors"
+ "k8s.io/apimachinery/pkg/api/errors"
- k8sclient "sigs.k8s.io/controller-runtime/pkg/client"
+ ctrl "sigs.k8s.io/controller-runtime/pkg/client"
monitoringv1 "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1"
@@ -45,14 +45,14 @@ func TestPrometheusTrait(t *testing.T) {
ocp, err := openshift.IsOpenShift(TestClient())
assert.Nil(t, err)
- // suppress Service Monitor for the time being as CI test runs on OCP 3.11
- createServiceMonitor := false
+ // Do not create PodMonitor for the time being as CI test runs on OCP 3.11
+ createPodMonitor := false
Expect(Kamel("install", "-n", ns).Execute()).To(Succeed())
Expect(Kamel("run", "-n", ns, "files/Java.java",
"-t", "prometheus.enabled=true",
- "-t", fmt.Sprintf("prometheus.service-monitor=%v", createServiceMonitor)).Execute()).To(Succeed())
+ "-t", fmt.Sprintf("prometheus.pod-monitor=%v", createPodMonitor)).Execute()).To(Succeed())
Eventually(IntegrationPodPhase(ns, "java"), TestTimeoutLong).Should(Equal(v1.PodRunning))
Eventually(IntegrationCondition(ns, "java", camelv1.IntegrationConditionReady), TestTimeoutShort).Should(Equal(v1.ConditionTrue))
Eventually(IntegrationLogs(ns, "java"), TestTimeoutShort).Should(ContainSubstring("Magicstring!"))
@@ -67,15 +67,9 @@ func TestPrometheusTrait(t *testing.T) {
assert.Contains(t, string(response), "camel.route.exchanges.total")
})
- t.Run("Service is created", func(t *testing.T) {
- // service name is "<integration name>-prometheus"
- service := Service(ns, "java-prometheus")
- Eventually(service, TestTimeoutShort).ShouldNot(BeNil())
- })
-
- if ocp && createServiceMonitor {
- t.Run("Service Monitor is created on OpenShift", func(t *testing.T) {
- sm := serviceMonitor(ns, "java")
+ if ocp && createPodMonitor {
+ t.Run("PodMonitor is created", func(t *testing.T) {
+ sm := podMonitor(ns, "java")
Eventually(sm, TestTimeoutShort).ShouldNot(BeNil())
})
}
@@ -84,19 +78,19 @@ func TestPrometheusTrait(t *testing.T) {
})
}
-func serviceMonitor(ns string, name string) func() *monitoringv1.ServiceMonitor {
- return func() *monitoringv1.ServiceMonitor {
- sm := monitoringv1.ServiceMonitor{}
- key := k8sclient.ObjectKey{
+func podMonitor(ns string, name string) func() *monitoringv1.PodMonitor {
+ return func() *monitoringv1.PodMonitor {
+ pm := monitoringv1.PodMonitor{}
+ key := ctrl.ObjectKey{
Namespace: ns,
Name: name,
}
- err := TestClient().Get(TestContext, key, &sm)
- if err != nil && k8serrors.IsNotFound(err) {
+ err := TestClient().Get(TestContext, key, &pm)
+ if err != nil && errors.IsNotFound(err) {
return nil
} else if err != nil {
panic(err)
}
- return &sm
+ return &pm
}
}
diff --git a/pkg/cmd/run_test.go b/pkg/cmd/run_test.go
index eddb32f..212765b 100644
--- a/pkg/cmd/run_test.go
+++ b/pkg/cmd/run_test.go
@@ -353,7 +353,7 @@ func TestConfigureTraits(t *testing.T) {
"--trait", "container.probes-enabled=false",
"--trait", "environment.container-meta=false",
"--trait", "jvm.print-command=false",
- "--trait", "prometheus.service-monitor=false",
+ "--trait", "prometheus.pod-monitor=false",
"example.js")
if err != nil {
t.Error(err)
@@ -372,7 +372,7 @@ func TestConfigureTraits(t *testing.T) {
assertTraitConfiguration(t, traits, "container", `{"probesEnabled":false}`)
assertTraitConfiguration(t, traits, "environment", `{"containerMeta":false}`)
assertTraitConfiguration(t, traits, "jvm", `{"printCommand":false}`)
- assertTraitConfiguration(t, traits, "prometheus", `{"serviceMonitor":false}`)
+ assertTraitConfiguration(t, traits, "prometheus", `{"podMonitor":false}`)
}
func assertTraitConfiguration(t *testing.T, traits map[string]v1.TraitSpec, trait string, expected string) {
diff --git a/pkg/trait/container.go b/pkg/trait/container.go
index 238a827..11dcb61 100644
--- a/pkg/trait/container.go
+++ b/pkg/trait/container.go
@@ -36,11 +36,12 @@ import (
)
const (
- defaultContainerName = "integration"
- defaultContainerPort = 8080
- defaultServicePort = 80
- defaultProbePath = "/health"
- containerTraitID = "container"
+ defaultContainerName = "integration"
+ defaultContainerPort = 8080
+ defaultContainerPortName = "http"
+ defaultServicePort = 80
+ defaultProbePath = "/health"
+ containerTraitID = "container"
)
// The Container trait can be used to configure properties of the container where the integration will run.
@@ -111,9 +112,8 @@ func newContainerTrait() Trait {
return &containerTrait{
BaseTrait: NewBaseTrait(containerTraitID, 1600),
Port: defaultContainerPort,
- PortName: httpPortName,
ServicePort: defaultServicePort,
- ServicePortName: httpPortName,
+ ServicePortName: defaultContainerPortName,
Name: defaultContainerName,
ProbesEnabled: util.BoolP(false),
ProbePath: defaultProbePath,
@@ -205,11 +205,13 @@ func (t *containerTrait) configureContainer(e *Environment) error {
return err
}
- //
+ portName := t.PortName
+ if portName == "" {
+ portName = defaultContainerPortName
+ }
// Deployment
- //
if err := e.Resources.VisitDeploymentE(func(deployment *appsv1.Deployment) error {
- if util.IsTrue(t.ProbesEnabled) && t.PortName == httpPortName {
+ if util.IsTrue(t.ProbesEnabled) && portName == defaultContainerPortName {
if err := t.configureProbes(e, &container, t.Port, t.ProbePath); err != nil {
return err
}
@@ -234,11 +236,9 @@ func (t *containerTrait) configureContainer(e *Environment) error {
return err
}
- //
// Knative Service
- //
if err := e.Resources.VisitKnativeServiceE(func(service *serving.Service) error {
- if util.IsTrue(t.ProbesEnabled) && t.PortName == httpPortName {
+ if util.IsTrue(t.ProbesEnabled) && portName == defaultContainerPortName {
// don't set the port on Knative service as it is not allowed.
if err := t.configureProbes(e, &container, 0, t.ProbePath); err != nil {
return err
@@ -275,11 +275,9 @@ func (t *containerTrait) configureContainer(e *Environment) error {
return err
}
- //
// CronJob
- //
if err := e.Resources.VisitCronJobE(func(cron *v1beta1.CronJob) error {
- if util.IsTrue(t.ProbesEnabled) && t.PortName == httpPortName {
+ if util.IsTrue(t.ProbesEnabled) && portName == defaultContainerPortName {
if err := t.configureProbes(e, &container, t.Port, t.ProbePath); err != nil {
return err
}
@@ -313,8 +311,13 @@ func (t *containerTrait) configureService(e *Environment, container *corev1.Cont
return
}
+ name := t.PortName
+ if name == "" {
+ name = defaultContainerPortName
+ }
+
containerPort := corev1.ContainerPort{
- Name: t.PortName,
+ Name: name,
ContainerPort: int32(t.Port),
Protocol: corev1.ProtocolTCP,
}
@@ -323,7 +326,7 @@ func (t *containerTrait) configureService(e *Environment, container *corev1.Cont
Name: t.ServicePortName,
Port: int32(t.ServicePort),
Protocol: corev1.ProtocolTCP,
- TargetPort: intstr.FromString(t.PortName),
+ TargetPort: intstr.FromString(name),
}
e.Integration.Status.SetCondition(
@@ -345,9 +348,7 @@ func (t *containerTrait) configureService(e *Environment, container *corev1.Cont
}
func (t *containerTrait) configureResources(_ *Environment, container *corev1.Container) {
- //
// Requests
- //
if container.Resources.Requests == nil {
container.Resources.Requests = make(corev1.ResourceList)
}
@@ -369,9 +370,7 @@ func (t *containerTrait) configureResources(_ *Environment, container *corev1.Co
}
}
- //
// Limits
- //
if container.Resources.Limits == nil {
container.Resources.Limits = make(corev1.ResourceList)
}
diff --git a/pkg/trait/prometheus.go b/pkg/trait/prometheus.go
index 7a5a87d..8ef81b5 100644
--- a/pkg/trait/prometheus.go
+++ b/pkg/trait/prometheus.go
@@ -22,7 +22,6 @@ import (
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
- "k8s.io/apimachinery/pkg/util/intstr"
monitoringv1 "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1"
@@ -30,35 +29,30 @@ import (
"github.com/apache/camel-k/pkg/util"
)
-// The Prometheus trait configures a Prometheus-compatible endpoint. This trait also exposes the integration with
-// `Service` and `ServiceMonitor` resources, so that the endpoint can be scraped automatically, when using the
-// Prometheus Operator.
+// The Prometheus trait configures a Prometheus-compatible endpoint. It also creates a `PodMonitor` resource,
+// so that the endpoint can be scraped automatically, when using the Prometheus operator.
//
// The metrics are exposed using MicroProfile Metrics.
//
-// WARNING: The creation of the `ServiceMonitor` resource requires the https://github.com/coreos/prometheus-operator[Prometheus Operator]
+// WARNING: The creation of the `PodMonitor` resource requires the https://github.com/coreos/prometheus-operator[Prometheus Operator]
// custom resource definition to be installed.
-// You can set `service-monitor` to `false` for the Prometheus trait to work without the Prometheus Operator.
+// You can set `pod-monitor` to `false` for the Prometheus trait to work without the Prometheus Operator.
//
// The Prometheus trait is disabled by default.
//
// +camel-k:trait=prometheus
type prometheusTrait struct {
BaseTrait `property:",squash"`
- // The Prometheus endpoint port (default `9779`, or `8080` with Quarkus).
- Port *int `property:"port" json:"port,omitempty"`
- // Whether a `ServiceMonitor` resource is created (default `true`).
- ServiceMonitor *bool `property:"service-monitor" json:"serviceMonitor,omitempty"`
- // The `ServiceMonitor` resource labels, applicable when `service-monitor` is `true`.
- ServiceMonitorLabels []string `property:"service-monitor-labels" json:"serviceMonitorLabels,omitempty"`
+ // Whether a `PodMonitor` resource is created (default `true`).
+ PodMonitor *bool `property:"pod-monitor" json:"podMonitor,omitempty"`
+ // The `PodMonitor` resource labels, applicable when `pod-monitor` is `true`.
+ PodMonitorLabels []string `property:"pod-monitor-labels" json:"podMonitorLabels,omitempty"`
}
-const prometheusPortName = "prometheus"
-
func newPrometheusTrait() Trait {
return &prometheusTrait{
- BaseTrait: NewBaseTrait("prometheus", 1900),
- ServiceMonitor: util.BoolP(true),
+ BaseTrait: NewBaseTrait("prometheus", 1900),
+ PodMonitor: util.BoolP(true),
}
}
@@ -70,7 +64,7 @@ func (t *prometheusTrait) Configure(e *Environment) (bool, error) {
), nil
}
-func (t *prometheusTrait) Apply(e *Environment) error {
+func (t *prometheusTrait) Apply(e *Environment) (err error) {
if e.IntegrationInPhase(v1.IntegrationPhaseInitialization) {
// Add the Camel Quarkus MP Metrics extension
util.StringSliceUniqueAdd(&e.Integration.Status.Dependencies, "mvn:org.apache.camel.quarkus:camel-quarkus-microprofile-metrics")
@@ -94,60 +88,38 @@ func (t *prometheusTrait) Apply(e *Environment) error {
Reason: v1.IntegrationConditionPrometheusAvailableReason,
}
- port := 8080
- if t.Port == nil {
- t.Port = &port
- }
-
- // Configure the Prometheus container port
- containerPort := t.getContainerPort()
controller, err := e.DetermineControllerStrategy()
if err != nil {
return err
}
- // Skip declaring the Prometheus port when Knative is enabled, as only one container port is supported
- if controller != ControllerStrategyKnativeService {
+
+ containerPort := e.getIntegrationContainerPort()
+ if containerPort == nil {
+ containerPort = t.getContainerPort(e, controller)
container.Ports = append(container.Ports, *containerPort)
}
+
condition.Message = fmt.Sprintf("%s(%d)", container.Name, containerPort.ContainerPort)
- // Retrieve the service or create a new one if the service trait is enabled
- serviceEnabled := false
- service := e.Resources.GetServiceForIntegration(e.Integration)
- if service == nil {
- trait := e.Catalog.GetTrait(serviceTraitID)
- if serviceTrait, ok := trait.(*serviceTrait); ok {
- serviceEnabled = serviceTrait.isEnabled()
- }
- if serviceEnabled {
- // Add a new service if not already created
- service = getServiceFor(e)
- // Override the service name if none exists.
- // This is required for Knative Serving, that checks no standard eponymous service exist
- service.Name += "-prometheus"
- e.Resources.Add(service)
+ // Add the PodMonitor resource
+ if util.IsTrue(t.PodMonitor) {
+ portName := containerPort.Name
+ // Knative defaults to naming the userland container port "user-port".
+ // Let's rely on that default, granted it is not officially part of the Knative
+ // runtime contract.
+ // See https://github.com/knative/specs/blob/main/specs/serving/runtime-contract.md
+ if portName == "" && controller == ControllerStrategyKnativeService {
+ portName = "user-port"
}
- } else {
- serviceEnabled = true
- }
- // Add the service port and service monitor resource
- if serviceEnabled {
- servicePort := t.getServicePort()
- service.Spec.Ports = append(service.Spec.Ports, *servicePort)
- condition.Message = fmt.Sprintf("%s(%s/%d) -> ", service.Name, servicePort.Name, servicePort.Port) + condition.Message
-
- // Add the ServiceMonitor resource
- if util.IsNilOrTrue(t.ServiceMonitor) {
- smt, err := t.getServiceMonitorFor(e)
- if err != nil {
- return err
- }
- e.Resources.Add(smt)
+ podMonitor, err := t.getPodMonitorFor(e, portName)
+ if err != nil {
+ return err
}
+ e.Resources.Add(podMonitor)
+ condition.Message = fmt.Sprintf("PodMonitor (%s) -> ", podMonitor.Name) + condition.Message
} else {
- condition.Status = corev1.ConditionFalse
- condition.Reason = v1.IntegrationConditionServiceNotAvailableReason
+ condition.Message = "ContainerPort " + condition.Message
}
e.Integration.Status.SetConditions(condition)
@@ -155,55 +127,58 @@ func (t *prometheusTrait) Apply(e *Environment) error {
return nil
}
-func (t *prometheusTrait) getContainerPort() *corev1.ContainerPort {
- containerPort := corev1.ContainerPort{
- ContainerPort: int32(*t.Port),
- Protocol: corev1.ProtocolTCP,
+func (t *prometheusTrait) getContainerPort(e *Environment, controller ControllerStrategy) *corev1.ContainerPort {
+ var name string
+ var port int
+
+ if t := e.Catalog.GetTrait(containerTraitID); t != nil {
+ name = t.(*containerTrait).PortName
+ port = t.(*containerTrait).Port
}
- return &containerPort
-}
-func (t *prometheusTrait) getServicePort() *corev1.ServicePort {
- servicePort := corev1.ServicePort{
- Name: prometheusPortName,
- Port: int32(*t.Port),
- Protocol: corev1.ProtocolTCP,
- // Avoid relying on named port, as Knative enforces specific values used for content negotiation
- TargetPort: intstr.FromInt(*t.Port),
+ // Let's rely on Knative default HTTP negotiation
+ if name == "" && controller != ControllerStrategyKnativeService {
+ name = defaultContainerPortName
+ }
+
+ return &corev1.ContainerPort{
+ Name: name,
+ ContainerPort: int32(port),
+ Protocol: corev1.ProtocolTCP,
}
- return &servicePort
}
-func (t *prometheusTrait) getServiceMonitorFor(e *Environment) (*monitoringv1.ServiceMonitor, error) {
- labels, err := keyValuePairArrayAsStringMap(t.ServiceMonitorLabels)
+func (t *prometheusTrait) getPodMonitorFor(e *Environment, portName string) (*monitoringv1.PodMonitor, error) {
+ labels, err := keyValuePairArrayAsStringMap(t.PodMonitorLabels)
if err != nil {
return nil, err
}
labels[v1.IntegrationLabel] = e.Integration.Name
- smt := monitoringv1.ServiceMonitor{
+ podMonitor := monitoringv1.PodMonitor{
TypeMeta: metav1.TypeMeta{
- Kind: "ServiceMonitor",
- APIVersion: "monitoring.coreos.com/v1",
+ Kind: "PodMonitor",
+ APIVersion: monitoringv1.SchemeGroupVersion.String(),
},
ObjectMeta: metav1.ObjectMeta{
Name: e.Integration.Name,
Namespace: e.Integration.Namespace,
Labels: labels,
},
- Spec: monitoringv1.ServiceMonitorSpec{
+ Spec: monitoringv1.PodMonitorSpec{
Selector: metav1.LabelSelector{
MatchLabels: map[string]string{
v1.IntegrationLabel: e.Integration.Name,
},
},
- Endpoints: []monitoringv1.Endpoint{
+ PodMetricsEndpoints: []monitoringv1.PodMetricsEndpoint{
{
+ Port: portName,
Path: "/q/metrics",
- Port: prometheusPortName,
},
},
},
}
- return &smt, nil
+
+ return &podMonitor, nil
}
diff --git a/pkg/trait/prometheus_test.go b/pkg/trait/prometheus_test.go
index 1bf8d65..670a911 100644
--- a/pkg/trait/prometheus_test.go
+++ b/pkg/trait/prometheus_test.go
@@ -70,16 +70,10 @@ func TestApplyNominalPrometheusTraitDoesSucceed(t *testing.T) {
assert.Equal(t, int32(8080), ports[0].ContainerPort)
assert.Equal(t, corev1.ProtocolTCP, ports[0].Protocol)
- service := environment.Resources.GetService(func(service *corev1.Service) bool {
- return service.Name == "integration-name-prometheus"
+ podMonitor := environment.Resources.GetPodMonitor(func(pm *monitoringv1.PodMonitor) bool {
+ return pm.Name == "integration-name"
})
- assert.NotNil(t, service)
- assert.Len(t, service.Spec.Ports, 1)
-
- serviceMonitor := environment.Resources.GetServiceMonitor(func(service *monitoringv1.ServiceMonitor) bool {
- return service.Name == "integration-name"
- })
- assert.NotNil(t, serviceMonitor)
+ assert.NotNil(t, podMonitor)
assert.Len(t, environment.Integration.Status.Conditions, 1)
condition := environment.Integration.Status.Conditions[0]
@@ -101,70 +95,22 @@ func TestApplyPrometheusTraitWithoutContainerDoesNotSucceed(t *testing.T) {
assert.Equal(t, corev1.ConditionFalse, condition.Status)
}
-func TestApplyPrometheusTraitWithServiceDoesSucceed(t *testing.T) {
- trait, environment := createNominalPrometheusTest()
- environment.Resources = kubernetes.NewCollection(
- &appsv1.Deployment{
- Spec: appsv1.DeploymentSpec{
- Template: corev1.PodTemplateSpec{
- Spec: corev1.PodSpec{
- Containers: []corev1.Container{
- {
- Name: defaultContainerName,
- },
- },
- },
- },
- },
- },
- &corev1.Service{
- TypeMeta: metav1.TypeMeta{
- Kind: "Service",
- APIVersion: "v1",
- },
- ObjectMeta: metav1.ObjectMeta{
- Name: "service-name",
- Namespace: "namespace",
- Labels: map[string]string{
- v1.IntegrationLabel: "integration-name",
- "camel.apache.org/service.type": v1.ServiceTypeUser,
- },
- },
- Spec: corev1.ServiceSpec{
- Ports: []corev1.ServicePort{},
- Selector: map[string]string{
- v1.IntegrationLabel: "integration-name",
- },
- },
- })
-
- err := trait.Apply(environment)
-
- assert.Nil(t, err)
-
- assert.Len(t, environment.Integration.Status.Conditions, 1)
- condition := environment.Integration.Status.Conditions[0]
- assert.Equal(t, v1.IntegrationConditionPrometheusAvailableReason, condition.Reason)
- assert.Equal(t, corev1.ConditionTrue, condition.Status)
-}
-
-func TestPrometheusTraitGetServiceMonitor(t *testing.T) {
+func TestPrometheusTraitGetPodMonitor(t *testing.T) {
trait, environment := createNominalPrometheusTest()
- serviceMonitor, err := trait.getServiceMonitorFor(environment)
+ podMonitor, err := trait.getPodMonitorFor(environment, defaultContainerPortName)
assert.Nil(t, err)
- assert.NotNil(t, serviceMonitor)
- assert.Equal(t, "ServiceMonitor", serviceMonitor.Kind)
- assert.Equal(t, "monitoring.coreos.com/v1", serviceMonitor.APIVersion)
- assert.Equal(t, "integration-name", serviceMonitor.Name)
- assert.Equal(t, "integration-namespace", serviceMonitor.Namespace)
- assert.Equal(t, "integration-name", serviceMonitor.Labels[v1.IntegrationLabel])
- assert.Equal(t, "integration-name", serviceMonitor.Spec.Selector.MatchLabels[v1.IntegrationLabel])
- assert.Len(t, serviceMonitor.Spec.Endpoints, 1)
- assert.Equal(t, "prometheus", serviceMonitor.Spec.Endpoints[0].Port)
- assert.Equal(t, "/q/metrics", serviceMonitor.Spec.Endpoints[0].Path)
+ assert.NotNil(t, podMonitor)
+ assert.Equal(t, "PodMonitor", podMonitor.Kind)
+ assert.Equal(t, "monitoring.coreos.com/v1", podMonitor.APIVersion)
+ assert.Equal(t, "integration-name", podMonitor.Name)
+ assert.Equal(t, "integration-namespace", podMonitor.Namespace)
+ assert.Equal(t, "integration-name", podMonitor.Labels["camel.apache.org/integration"])
+ assert.Equal(t, "integration-name", podMonitor.Spec.Selector.MatchLabels["camel.apache.org/integration"])
+ assert.Len(t, podMonitor.Spec.PodMetricsEndpoints, 1)
+ assert.Equal(t, defaultContainerPortName, podMonitor.Spec.PodMetricsEndpoints[0].Port)
}
func createNominalPrometheusTest() (*prometheusTrait, *Environment) {
diff --git a/pkg/trait/route.go b/pkg/trait/route.go
index cd830d6..4cc05f6 100644
--- a/pkg/trait/route.go
+++ b/pkg/trait/route.go
@@ -112,7 +112,7 @@ func (t *routeTrait) Configure(e *Environment) (bool, error) {
}
func (t *routeTrait) Apply(e *Environment) error {
- servicePortName := httpPortName
+ servicePortName := defaultContainerPortName
dt := e.Catalog.GetTrait(containerTraitID)
if dt != nil {
servicePortName = dt.(*containerTrait).ServicePortName
diff --git a/pkg/trait/route_test.go b/pkg/trait/route_test.go
index a2c85a4..11b7eea 100644
--- a/pkg/trait/route_test.go
+++ b/pkg/trait/route_test.go
@@ -114,7 +114,7 @@ func TestRoute_Default(t *testing.T) {
assert.NotNil(t, route)
assert.Nil(t, route.Spec.TLS)
assert.NotNil(t, route.Spec.Port)
- assert.Equal(t, httpPortName, route.Spec.Port.TargetPort.StrVal)
+ assert.Equal(t, defaultContainerPortName, route.Spec.Port.TargetPort.StrVal)
}
func TestRoute_Disabled(t *testing.T) {
diff --git a/pkg/trait/service.go b/pkg/trait/service.go
index 2ece2fd..61cf4a9 100644
--- a/pkg/trait/service.go
+++ b/pkg/trait/service.go
@@ -40,10 +40,7 @@ type serviceTrait struct {
NodePort *bool `property:"node-port" json:"nodePort,omitempty"`
}
-const (
- serviceTraitID = "service"
- httpPortName = "http"
-)
+const serviceTraitID = "service"
func newServiceTrait() Trait {
return &serviceTrait{
diff --git a/pkg/trait/trait_types.go b/pkg/trait/trait_types.go
index b3cd991..2ca1095 100644
--- a/pkg/trait/trait_types.go
+++ b/pkg/trait/trait_types.go
@@ -801,6 +801,30 @@ func (e *Environment) getIntegrationContainer() *corev1.Container {
return e.Resources.GetContainerByName(containerName)
}
+func (e *Environment) getIntegrationContainerPort() *corev1.ContainerPort {
+ container := e.getIntegrationContainer()
+ if container == nil {
+ return nil
+ }
+
+ portName := ""
+ t := e.Catalog.GetTrait(containerTraitID)
+ if t != nil {
+ portName = t.(*containerTrait).PortName
+ }
+ if portName == "" {
+ portName = defaultContainerPortName
+ }
+
+ for i, port := range container.Ports {
+ if port.Name == portName {
+ return &container.Ports[i]
+ }
+ }
+
+ return nil
+}
+
func (e *Environment) getAllInterceptors() []string {
res := make([]string, 0)
util.StringSliceUniqueConcat(&res, e.Interceptors)
diff --git a/pkg/util/kubernetes/collection.go b/pkg/util/kubernetes/collection.go
index 008bb66..c5d75dc 100644
--- a/pkg/util/kubernetes/collection.go
+++ b/pkg/util/kubernetes/collection.go
@@ -476,19 +476,19 @@ func (c *Collection) Remove(selector func(runtime.Object) bool) runtime.Object {
return nil
}
-func (c *Collection) VisitServiceMonitor(visitor func(*monitoringv1.ServiceMonitor)) {
+func (c *Collection) VisitPodMonitor(visitor func(*monitoringv1.PodMonitor)) {
c.Visit(func(res runtime.Object) {
- if conv, ok := res.(*monitoringv1.ServiceMonitor); ok {
+ if conv, ok := res.(*monitoringv1.PodMonitor); ok {
visitor(conv)
}
})
}
-func (c *Collection) GetServiceMonitor(filter func(*monitoringv1.ServiceMonitor) bool) *monitoringv1.ServiceMonitor {
- var retValue *monitoringv1.ServiceMonitor
- c.VisitServiceMonitor(func(serviceMonitor *monitoringv1.ServiceMonitor) {
- if filter(serviceMonitor) {
- retValue = serviceMonitor
+func (c *Collection) GetPodMonitor(filter func(*monitoringv1.PodMonitor) bool) *monitoringv1.PodMonitor {
+ var retValue *monitoringv1.PodMonitor
+ c.VisitPodMonitor(func(podMonitor *monitoringv1.PodMonitor) {
+ if filter(podMonitor) {
+ retValue = podMonitor
}
})
return retValue