Skip to content

Commit 97d1ef0

Browse files
authored
Merge pull request #1630 from bacherfl/poc/keptn-provider
feat: implement a Keptn metrics provider
2 parents adc6059 + ce976e2 commit 97d1ef0

File tree

13 files changed

+742
-9
lines changed

13 files changed

+742
-9
lines changed

artifacts/flagger/crd.yaml

+1
Original file line numberDiff line numberDiff line change
@@ -1298,6 +1298,7 @@ spec:
12981298
- newrelic
12991299
- graphite
13001300
- dynatrace
1301+
- keptn
13011302
address:
13021303
description: API address of this provider
13031304
type: string

charts/flagger/crds/crd.yaml

+1
Original file line numberDiff line numberDiff line change
@@ -1298,6 +1298,7 @@ spec:
12981298
- newrelic
12991299
- graphite
13001300
- dynatrace
1301+
- keptn
13011302
address:
13021303
description: API address of this provider
13031304
type: string

charts/flagger/templates/rbac.yaml

+13
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,19 @@ rules:
259259
- update
260260
- patch
261261
- delete
262+
- apiGroups:
263+
- metrics.keptn.sh
264+
resources:
265+
- keptnmetrics
266+
- analyses
267+
verbs:
268+
- get
269+
- list
270+
- watch
271+
- create
272+
- update
273+
- patch
274+
- delete
262275
- nonResourceURLs:
263276
- /version
264277
verbs:

cmd/flagger/main.go

+1
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,7 @@ func main() {
253253
fromEnv("EVENT_WEBHOOK_URL", eventWebhook),
254254
clusterName,
255255
noCrossNamespaceRefs,
256+
cfg,
256257
)
257258

258259
// leader election context

docs/gitbook/usage/metrics.md

+62
Original file line numberDiff line numberDiff line change
@@ -668,3 +668,65 @@ Reference the template in the canary analysis:
668668
max: 1000
669669
interval: 1m
670670
```
671+
672+
## Keptn
673+
674+
You can create custom metric checks using the Keptn provider.
675+
This Provider allows to verify either the value of a single [KeptnMetric](https://keptn.sh/stable/docs/reference/crd-reference/metric/),
676+
representing the value of a single metric,
677+
or of a [Keptn Analysis](https://keptn.sh/stable/docs/reference/crd-reference/analysis/),
678+
which provides a flexible grading logic for analysing and prioritising a number of different
679+
metric values coming from different data sources.
680+
681+
This provider requires [Keptn](https://keptn.sh/stable/docs/installation/) to be installed in the cluster.
682+
683+
Example for a Keptn metric template:
684+
685+
```yaml
686+
apiVersion: flagger.app/v1beta1
687+
kind: MetricTemplate
688+
metadata:
689+
name: response-time
690+
namespace: istio-system
691+
spec:
692+
provider:
693+
type: keptn
694+
query: keptnmetric/my-namespace/response-time/2m/reporter=destination
695+
```
696+
697+
This will reference the `KeptnMetric` with the name `response-time` in
698+
the namespace `my-namespace`, which could look like the following:
699+
700+
```yaml
701+
apiVersion: metrics.keptn.sh/v1beta1
702+
kind: KeptnMetric
703+
metadata:
704+
name: response-time
705+
namespace: my-namespace
706+
spec:
707+
fetchIntervalSeconds: 10
708+
provider:
709+
name: my-prometheus-keptn-provider
710+
query: histogram_quantile(0.8, sum by(le) (rate(http_server_request_latency_seconds_bucket{status_code='200',
711+
job='simple-go-backend'}[5m[])))
712+
```
713+
714+
The `query` contains the following components, which are divided by `/` characters:
715+
716+
```
717+
<type>/<namespace>/<resource-name>/<timeframe>/<arguments>
718+
```
719+
720+
* **type (required)**: Must be either `keptnmetric` or `analysis`.
721+
* **namespace (required)**: The namespace of the referenced `KeptnMetric`/`AnalysisDefinition`.
722+
* **resource-name (required):** The name of the referenced `KeptnMetric`/`AnalysisDefinition`.
723+
* **timeframe (optional)**: The timeframe used for the Analysis.
724+
This will usually be set to the same value as the analysis interval of a `Canary`.
725+
Only relevant if the `type` is set to `analysis`.
726+
* **arguments (optional)**: Arguments to be passed to an `Analysis`.
727+
Arguments are passed as a list of key value pairs, separated by `;` characters,
728+
e.g. `foo=bar;bar=foo`.
729+
Only relevant if the `type` is set to `analysis`.
730+
731+
For the type `analysis`, the value returned by the provider is either `0`
732+
(if the analysis failed), or `1` (analysis passed).

go.mod

+2-2
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,14 @@ require (
99
github.com/davecgh/go-spew v1.1.1
1010
github.com/go-logr/zapr v1.3.0
1111
github.com/google/go-cmp v0.6.0
12+
github.com/google/uuid v1.6.0
1213
github.com/googleapis/gax-go/v2 v2.12.4
1314
github.com/hashicorp/go-retryablehttp v0.7.7
1415
github.com/influxdata/influxdb-client-go/v2 v2.13.0
1516
github.com/prometheus/client_golang v1.19.1
1617
github.com/stretchr/testify v1.9.0
1718
go.uber.org/zap v1.27.0
19+
golang.org/x/sync v0.7.0
1820
google.golang.org/api v0.182.0
1921
google.golang.org/genproto v0.0.0-20240528184218-531527333157
2022
google.golang.org/grpc v1.64.0
@@ -47,7 +49,6 @@ require (
4749
github.com/google/gnostic-models v0.6.8 // indirect
4850
github.com/google/gofuzz v1.2.0 // indirect
4951
github.com/google/s2a-go v0.1.7 // indirect
50-
github.com/google/uuid v1.6.0 // indirect
5152
github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect
5253
github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542 // indirect
5354
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
@@ -77,7 +78,6 @@ require (
7778
golang.org/x/mod v0.15.0 // indirect
7879
golang.org/x/net v0.25.0 // indirect
7980
golang.org/x/oauth2 v0.20.0 // indirect
80-
golang.org/x/sync v0.7.0 // indirect
8181
golang.org/x/sys v0.20.0 // indirect
8282
golang.org/x/term v0.20.0 // indirect
8383
golang.org/x/text v0.15.0 // indirect

kustomize/base/flagger/crd.yaml

+1
Original file line numberDiff line numberDiff line change
@@ -1298,6 +1298,7 @@ spec:
12981298
- newrelic
12991299
- graphite
13001300
- dynatrace
1301+
- keptn
13011302
address:
13021303
description: API address of this provider
13031304
type: string

kustomize/base/flagger/rbac.yaml

+13
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,19 @@ rules:
241241
- update
242242
- patch
243243
- delete
244+
- apiGroups:
245+
- metrics.keptn.sh
246+
resources:
247+
- keptnmetrics
248+
- analyses
249+
verbs:
250+
- get
251+
- list
252+
- watch
253+
- create
254+
- update
255+
- patch
256+
- delete
244257
- nonResourceURLs:
245258
- /version
246259
verbs:

pkg/controller/controller.go

+5
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ import (
2121
"sync"
2222
"time"
2323

24+
"k8s.io/client-go/rest"
25+
2426
"github.com/google/go-cmp/cmp"
2527
"go.uber.org/zap"
2628
corev1 "k8s.io/api/core/v1"
@@ -49,6 +51,7 @@ const controllerAgentName = "flagger"
4951

5052
// Controller is managing the canary objects and schedules canary deployments
5153
type Controller struct {
54+
kubeConfig *rest.Config
5255
kubeClient kubernetes.Interface
5356
flaggerClient clientset.Interface
5457
flaggerInformers Informers
@@ -91,6 +94,7 @@ func NewController(
9194
eventWebhook string,
9295
clusterName string,
9396
noCrossNamespaceRefs bool,
97+
kubeConfig *rest.Config,
9498
) *Controller {
9599
logger.Debug("Creating event broadcaster")
96100
flaggerscheme.AddToScheme(scheme.Scheme)
@@ -105,6 +109,7 @@ func NewController(
105109
recorder.SetInfo(version, meshProvider)
106110

107111
ctrl := &Controller{
112+
kubeConfig: kubeConfig,
108113
kubeClient: kubeClient,
109114
flaggerClient: flaggerClient,
110115
flaggerInformers: flaggerInformers,

pkg/controller/scheduler_metrics.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ func (c *Controller) checkMetricProviderAvailability(canary *flaggerv1.Canary) e
7474
}
7575

7676
factory := providers.Factory{}
77-
provider, err := factory.Provider(metric.Interval, template.Spec.Provider, credentials)
77+
provider, err := factory.Provider(metric.Interval, template.Spec.Provider, credentials, c.kubeConfig)
7878
if err != nil {
7979
return fmt.Errorf("metric template %s.%s provider %s error: %v",
8080
metric.TemplateRef.Name, namespace, template.Spec.Provider.Type, err)
@@ -260,7 +260,7 @@ func (c *Controller) runMetricChecks(canary *flaggerv1.Canary) bool {
260260
}
261261

262262
factory := providers.Factory{}
263-
provider, err := factory.Provider(metric.Interval, template.Spec.Provider, credentials)
263+
provider, err := factory.Provider(metric.Interval, template.Spec.Provider, credentials, c.kubeConfig)
264264
if err != nil {
265265
c.recordEventErrorf(canary, "Metric template %s.%s provider %s error: %v",
266266
metric.TemplateRef.Name, namespace, template.Spec.Provider.Type, err)

pkg/metrics/providers/factory.go

+4-5
Original file line numberDiff line numberDiff line change
@@ -18,15 +18,12 @@ package providers
1818

1919
import (
2020
flaggerv1 "github.com/fluxcd/flagger/pkg/apis/flagger/v1beta1"
21+
rest "k8s.io/client-go/rest"
2122
)
2223

2324
type Factory struct{}
2425

25-
func (factory Factory) Provider(
26-
metricInterval string,
27-
provider flaggerv1.MetricTemplateProvider,
28-
credentials map[string][]byte,
29-
) (Interface, error) {
26+
func (factory Factory) Provider(metricInterval string, provider flaggerv1.MetricTemplateProvider, credentials map[string][]byte, config *rest.Config) (Interface, error) {
3027
switch provider.Type {
3128
case "prometheus":
3229
return NewPrometheusProvider(provider, credentials)
@@ -44,6 +41,8 @@ func (factory Factory) Provider(
4441
return NewInfluxdbProvider(provider, credentials)
4542
case "dynatrace":
4643
return NewDynatraceProvider(metricInterval, provider, credentials)
44+
case "keptn":
45+
return NewKeptnProvider(config)
4746
default:
4847
return NewPrometheusProvider(provider, credentials)
4948
}

0 commit comments

Comments
 (0)