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 2020/11/10 10:20:19 UTC
[camel-k] 19/25: feat: Add time to first integration readiness
metric
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 4cca10c96fc34961278eb6405c23a90b92badfaf
Author: Antonin Stefanutti <an...@stefanutti.fr>
AuthorDate: Tue Oct 27 12:22:28 2020 +0100
feat: Add time to first integration readiness metric
---
deploy/crd-integration.yaml | 9 ++++
.../integrations.camel.apache.org.crd.yaml | 9 ++++
helm/camel-k/crds/crd-integration.yaml | 9 ++++
pkg/apis/camel/v1/integration_types.go | 4 ++
pkg/apis/camel/v1/integration_types_support.go | 52 +++++++++++++---------
pkg/apis/camel/v1/zz_generated.deepcopy.go | 8 ++++
pkg/controller/integration/error.go | 1 +
pkg/controller/integration/initialize.go | 6 +++
pkg/controller/integration/metrics.go | 47 +++++++++++++++++++
pkg/controller/integration/monitor.go | 18 ++++++--
10 files changed, 139 insertions(+), 24 deletions(-)
diff --git a/deploy/crd-integration.yaml b/deploy/crd-integration.yaml
index 73753c7..a6ebe04 100644
--- a/deploy/crd-integration.yaml
+++ b/deploy/crd-integration.yaml
@@ -194,6 +194,10 @@ spec:
description: IntegrationCondition describes the state of a resource
at a certain point.
properties:
+ firstTruthyTime:
+ description: First time the condition status transitioned to True.
+ format: date-time
+ type: string
lastTransitionTime:
description: Last time the condition transitioned from one status
to another.
@@ -331,6 +335,11 @@ spec:
type: string
kit:
type: string
+ lastInitTimestamp:
+ description: The timestamp representing the last time when this integration
+ was initialized.
+ format: date-time
+ type: string
phase:
description: IntegrationPhase --
type: string
diff --git a/deploy/olm-catalog/camel-k-dev/1.3.0-snapshot/integrations.camel.apache.org.crd.yaml b/deploy/olm-catalog/camel-k-dev/1.3.0-snapshot/integrations.camel.apache.org.crd.yaml
index 73753c7..a6ebe04 100644
--- a/deploy/olm-catalog/camel-k-dev/1.3.0-snapshot/integrations.camel.apache.org.crd.yaml
+++ b/deploy/olm-catalog/camel-k-dev/1.3.0-snapshot/integrations.camel.apache.org.crd.yaml
@@ -194,6 +194,10 @@ spec:
description: IntegrationCondition describes the state of a resource
at a certain point.
properties:
+ firstTruthyTime:
+ description: First time the condition status transitioned to True.
+ format: date-time
+ type: string
lastTransitionTime:
description: Last time the condition transitioned from one status
to another.
@@ -331,6 +335,11 @@ spec:
type: string
kit:
type: string
+ lastInitTimestamp:
+ description: The timestamp representing the last time when this integration
+ was initialized.
+ format: date-time
+ type: string
phase:
description: IntegrationPhase --
type: string
diff --git a/helm/camel-k/crds/crd-integration.yaml b/helm/camel-k/crds/crd-integration.yaml
index 73753c7..a6ebe04 100644
--- a/helm/camel-k/crds/crd-integration.yaml
+++ b/helm/camel-k/crds/crd-integration.yaml
@@ -194,6 +194,10 @@ spec:
description: IntegrationCondition describes the state of a resource
at a certain point.
properties:
+ firstTruthyTime:
+ description: First time the condition status transitioned to True.
+ format: date-time
+ type: string
lastTransitionTime:
description: Last time the condition transitioned from one status
to another.
@@ -331,6 +335,11 @@ spec:
type: string
kit:
type: string
+ lastInitTimestamp:
+ description: The timestamp representing the last time when this integration
+ was initialized.
+ format: date-time
+ type: string
phase:
description: IntegrationPhase --
type: string
diff --git a/pkg/apis/camel/v1/integration_types.go b/pkg/apis/camel/v1/integration_types.go
index 91d8c57..b5a57cd 100644
--- a/pkg/apis/camel/v1/integration_types.go
+++ b/pkg/apis/camel/v1/integration_types.go
@@ -60,6 +60,8 @@ type IntegrationStatus struct {
Replicas *int32 `json:"replicas,omitempty"`
Selector string `json:"selector,omitempty"`
Capabilities []string `json:"capabilities,omitempty"`
+ // The timestamp representing the last time when this integration was initialized.
+ InitializationTimestamp *metav1.Time `json:"lastInitTimestamp,omitempty"`
}
// +genclient
@@ -274,6 +276,8 @@ type IntegrationCondition struct {
LastUpdateTime metav1.Time `json:"lastUpdateTime,omitempty"`
// Last time the condition transitioned from one status to another.
LastTransitionTime metav1.Time `json:"lastTransitionTime,omitempty"`
+ // First time the condition status transitioned to True.
+ FirstTruthyTime *metav1.Time `json:"firstTruthyTime,omitempty"`
// The reason for the condition's last transition.
Reason string `json:"reason,omitempty"`
// A human readable message indicating details about the transition.
diff --git a/pkg/apis/camel/v1/integration_types_support.go b/pkg/apis/camel/v1/integration_types_support.go
index 2e807d3..591afda 100644
--- a/pkg/apis/camel/v1/integration_types_support.go
+++ b/pkg/apis/camel/v1/integration_types_support.go
@@ -282,24 +282,20 @@ func (in *IntegrationStatus) GetCondition(condType IntegrationConditionType) *In
// SetCondition --
func (in *IntegrationStatus) SetCondition(condType IntegrationConditionType, status corev1.ConditionStatus, reason string, message string) {
in.SetConditions(IntegrationCondition{
- Type: condType,
- Status: status,
- LastUpdateTime: metav1.Now(),
- LastTransitionTime: metav1.Now(),
- Reason: reason,
- Message: message,
+ Type: condType,
+ Status: status,
+ Reason: reason,
+ Message: message,
})
}
// SetErrorCondition --
func (in *IntegrationStatus) SetErrorCondition(condType IntegrationConditionType, reason string, err error) {
in.SetConditions(IntegrationCondition{
- Type: condType,
- Status: corev1.ConditionFalse,
- LastUpdateTime: metav1.Now(),
- LastTransitionTime: metav1.Now(),
- Reason: reason,
- Message: err.Error(),
+ Type: condType,
+ Status: corev1.ConditionFalse,
+ Reason: reason,
+ Message: err.Error(),
})
}
@@ -308,22 +304,36 @@ func (in *IntegrationStatus) SetErrorCondition(condType IntegrationConditionType
// If a condition that we are about to add already exists and has the same status and
// reason then we are not going to update.
func (in *IntegrationStatus) SetConditions(conditions ...IntegrationCondition) {
+ now := metav1.Now()
for _, condition := range conditions {
+ currentCond := in.GetCondition(condition.Type)
+
+ if currentCond != nil && currentCond.Status == condition.Status && currentCond.Reason == condition.Reason {
+ return
+ }
+
if condition.LastUpdateTime.IsZero() {
- condition.LastUpdateTime = metav1.Now()
+ condition.LastUpdateTime = now
}
+
if condition.LastTransitionTime.IsZero() {
- condition.LastTransitionTime = metav1.Now()
+ // We may want not to set it when the current condition is nil
+ condition.LastTransitionTime = now
}
- currentCond := in.GetCondition(condition.Type)
-
- if currentCond != nil && currentCond.Status == condition.Status && currentCond.Reason == condition.Reason {
- return
+ if (condition.FirstTruthyTime == nil || condition.FirstTruthyTime.IsZero()) && condition.Status == corev1.ConditionTrue {
+ condition.FirstTruthyTime = &now
}
- // Do not update lastTransitionTime if the status of the condition doesn't change.
- if currentCond != nil && currentCond.Status == condition.Status {
- condition.LastTransitionTime = currentCond.LastTransitionTime
+
+ if currentCond != nil {
+ if currentCond.Status == condition.Status {
+ // Do not update LastTransitionTime if the status of the condition doesn't change
+ condition.LastTransitionTime = currentCond.LastTransitionTime
+ }
+ if !(currentCond.FirstTruthyTime != nil || currentCond.FirstTruthyTime.IsZero()) {
+ // Preserve FirstTruthyTime
+ condition.FirstTruthyTime = currentCond.FirstTruthyTime.DeepCopy()
+ }
}
in.RemoveCondition(condition.Type)
diff --git a/pkg/apis/camel/v1/zz_generated.deepcopy.go b/pkg/apis/camel/v1/zz_generated.deepcopy.go
index e734bde..a38ad74 100644
--- a/pkg/apis/camel/v1/zz_generated.deepcopy.go
+++ b/pkg/apis/camel/v1/zz_generated.deepcopy.go
@@ -663,6 +663,10 @@ func (in *IntegrationCondition) DeepCopyInto(out *IntegrationCondition) {
*out = *in
in.LastUpdateTime.DeepCopyInto(&out.LastUpdateTime)
in.LastTransitionTime.DeepCopyInto(&out.LastTransitionTime)
+ if in.FirstTruthyTime != nil {
+ in, out := &in.FirstTruthyTime, &out.FirstTruthyTime
+ *out = (*in).DeepCopy()
+ }
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IntegrationCondition.
@@ -1152,6 +1156,10 @@ func (in *IntegrationStatus) DeepCopyInto(out *IntegrationStatus) {
*out = make([]string, len(*in))
copy(*out, *in)
}
+ if in.InitializationTimestamp != nil {
+ in, out := &in.InitializationTimestamp, &out.InitializationTimestamp
+ *out = (*in).DeepCopy()
+ }
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IntegrationStatus.
diff --git a/pkg/controller/integration/error.go b/pkg/controller/integration/error.go
index 0e18538..9e3ad90 100644
--- a/pkg/controller/integration/error.go
+++ b/pkg/controller/integration/error.go
@@ -52,6 +52,7 @@ func (action *errorAction) Handle(ctx context.Context, integration *v1.Integrati
integration.Status.Digest = hash
integration.Status.Phase = v1.IntegrationPhaseInitialization
+ integration.Status.InitializationTimestamp = nil
return integration, nil
}
diff --git a/pkg/controller/integration/initialize.go b/pkg/controller/integration/initialize.go
index ed98d88..4698b71 100644
--- a/pkg/controller/integration/initialize.go
+++ b/pkg/controller/integration/initialize.go
@@ -20,6 +20,8 @@ package integration
import (
"context"
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+
v1 "github.com/apache/camel-k/pkg/apis/camel/v1"
"github.com/apache/camel-k/pkg/trait"
"github.com/apache/camel-k/pkg/util/defaults"
@@ -55,6 +57,10 @@ func (action *initializeAction) Handle(ctx context.Context, integration *v1.Inte
integration.Status.Phase = v1.IntegrationPhaseBuildingKit
integration.SetIntegrationKit(&kit)
integration.Status.Version = defaults.Version
+ if timestamp := integration.Status.InitializationTimestamp; timestamp == nil || timestamp.IsZero() {
+ now := metav1.Now()
+ integration.Status.InitializationTimestamp = &now
+ }
return integration, nil
}
diff --git a/pkg/controller/integration/metrics.go b/pkg/controller/integration/metrics.go
new file mode 100644
index 0000000..fb6fff3
--- /dev/null
+++ b/pkg/controller/integration/metrics.go
@@ -0,0 +1,47 @@
+/*
+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 integration
+
+import (
+ "time"
+
+ "sigs.k8s.io/controller-runtime/pkg/metrics"
+
+ "github.com/prometheus/client_golang/prometheus"
+)
+
+var (
+ timeToFirstReadiness = prometheus.NewHistogram(
+ prometheus.HistogramOpts{
+ Name: "camel_k_integration_first_readiness_seconds",
+ Help: "Camel K integration time to first readiness",
+ Buckets: []float64{
+ 5 * time.Second.Seconds(),
+ 10 * time.Second.Seconds(),
+ 30 * time.Second.Seconds(),
+ 1 * time.Minute.Seconds(),
+ 2 * time.Minute.Seconds(),
+ },
+ },
+ )
+)
+
+func init() {
+ // Register custom metrics with the global prometheus registry
+ metrics.Registry.MustRegister(timeToFirstReadiness)
+}
diff --git a/pkg/controller/integration/monitor.go b/pkg/controller/integration/monitor.go
index 2b55f59..654d78b 100644
--- a/pkg/controller/integration/monitor.go
+++ b/pkg/controller/integration/monitor.go
@@ -21,6 +21,7 @@ import (
"context"
appsv1 "k8s.io/api/apps/v1"
+ corev1 "k8s.io/api/core/v1"
k8sclient "sigs.k8s.io/controller-runtime/pkg/client"
v1 "github.com/apache/camel-k/pkg/apis/camel/v1"
@@ -62,6 +63,7 @@ func (action *monitorAction) Handle(ctx context.Context, integration *v1.Integra
integration.Status.Profile = integration.Spec.Profile
}
integration.Status.Version = defaults.Version
+ integration.Status.InitializationTimestamp = nil
return integration, nil
}
@@ -72,8 +74,9 @@ func (action *monitorAction) Handle(ctx context.Context, integration *v1.Integra
return nil, err
}
- // Enforce the scale sub-resource label selector
- // It is used by the HPA that queries the scale sub-resource endpoint to list the pods owned by the integration
+ // Enforce the scale sub-resource label selector.
+ // It is used by the HPA that queries the scale sub-resource endpoint,
+ // to list the pods owned by the integration.
integration.Status.Selector = v1.IntegrationLabel + "=" + integration.Name
// Check replicas
@@ -96,9 +99,18 @@ func (action *monitorAction) Handle(ctx context.Context, integration *v1.Integra
}
}
- // Mirror ready condition from the sub resource (e.g.ReplicaSet, Deployment, CronJob, ...) to the integration
+ // Mirror ready condition from the owned resource (e.g.ReplicaSet, Deployment, CronJob, ...)
+ // into the owning integration
+ previous := integration.Status.GetCondition(v1.IntegrationConditionReady)
kubernetes.MirrorReadyCondition(ctx, action.client, integration)
+ if next := integration.Status.GetCondition(v1.IntegrationConditionReady);
+ (previous == nil || previous.FirstTruthyTime == nil || previous.FirstTruthyTime.IsZero()) &&
+ next != nil && next.Status == corev1.ConditionTrue && !(next.FirstTruthyTime == nil || next.FirstTruthyTime.IsZero()) {
+ // Observe the time to first readiness metric
+ timeToFirstReadiness.Observe(next.FirstTruthyTime.Time.Sub(integration.Status.InitializationTimestamp.Time).Seconds())
+ }
+
return integration, nil
}