Skip to content

Commit

Permalink
docs: document how to write create new keptnmetricsprovider (keptn#2939)
Browse files Browse the repository at this point in the history
Signed-off-by: Geoffrey Israel <[email protected]>
Signed-off-by: odubajDT <[email protected]>
Co-authored-by: Meg McRoberts <[email protected]>
Co-authored-by: RealAnna <[email protected]>
Co-authored-by: odubajDT <[email protected]>
  • Loading branch information
4 people authored Feb 20, 2024
1 parent cf0c170 commit c4359ba
Show file tree
Hide file tree
Showing 4 changed files with 183 additions and 0 deletions.
124 changes: 124 additions & 0 deletions docs/docs/contribute/software/add-new-metric-provider.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
---
comments: true
---

# Add a metrics provider

The
[KeptnMetric](../../guides/evaluatemetrics.md)
feature works with almost any data platform
but Keptn requires that a metrics provider be defined
for any data platform it uses as a data source.
This guide gives instructions for creating a new metrics provider.
For these instructions,
we define a sample provider called `placeholder`.
The steps to create your own metrics provider are:
<!-- markdownlint-disable MD007 -->

1. **Fork and clone** the
[Keptn repository](https://github.com/keptn/lifecycle-toolkit).
For more information, see
[Fork and clone the repository](https://keptn.sh/stable/docs/contribute/general/git/fork-clone/).

2. **Define the Provider Type:** In the `metrics-operator/controllers/common/providers/common.go` file,
define the constant `KeptnPlaceholderProviderType`.
In our example we use `"placeholder"`.

```go
const KeptnPlaceholderProviderType = "placeholder"
```

3. **Implement the Provider:** Create a new folder inside the
[metrics-operator/controllers/common/providers](<https://github.com/keptn/lifecycle-toolkit/tree/main/metrics-operator/controllers/common/providers>).
Use the provider name as the name of the folder.
This name defines the string used to identify this provider
in the `spec.type` field of the
[KeptnMetricsProvider](../../reference/crd-reference/metricsprovider.md)
resource.
In this example, the folder is named `placeholder`.
Create a new Go package for the placeholder provider in that folder.
This package should contain a `struct` that implements the `KeptnSLIProvider` interface.
To fully implement the `KeptnSLIProvider` interface, it's necessary to implement the following functions.

* `EvaluateQuery`(Fetches metric values from the provider)
* This function fetches metric values based on the provided
metric query from the provider.
It evaluates the query and returns the metric values
along with any additional data if required.
* It takes as input a [KeptnMetric](../../reference/crd-reference/metric.md)
and [KeptnMetricsProvider](../../reference/crd-reference/metricsprovider.md)
* `EvaluateQueryForStep`(Fetches metric values with step interval from the provider)
* This function fetches metric values with a specified step interval from the placeholder provider.
It takes into account the metric query and the step interval provided, executes the query,
and returns the metric values along with any additional data if required.
* It takes as input a [KeptnMetric](../../reference/crd-reference/metric.md)
and [KeptnMetricsProvider](../../reference/crd-reference/metricsprovider.md)
* `FetchAnalysisValue`(Fetches analysis values from the provider) functions.
* This function fetches analysis values based on the provided query and time range from the
provider.
It evaluates the query within the specified time range and returns the analysis
values along with any additional data if required.
* It takes as input an [Analysis](../../reference/crd-reference/analysis.md),
resource that contains a `query` and a
[KeptnMetricsProvider](../../reference/crd-reference/metricsprovider.md) resource.

You can follow other existing implementations,
such as [prometheus.go](https://github.com/keptn/lifecycle-toolkit/blob/main/metrics-operator/controllers/common/providers/prometheus/prometheus.go),
as an example.

Each of the three functions expects a string containing a float value in it.
But for example purposes we returned some of the data accessible in the function.

Below is an example of a placeholder provider implementation.

```go
{% include "./assets/example-code/placeholder-code-example.go" %}
```

> **Note** Refer to the documentation of the
> [KeptnMetric](../../reference/crd-reference/metric.md)
> and
> [Analysis](../../reference/crd-reference/analysis.md)
> resources
> to understand what data should be retrieved from the methods inputs to compute accurate results.

4. **Instantiate the Provider** in the `providers.NewProvider` function
in the `metrics-operator/controllers/common/providers/provider.go` file.
add a case for the `KeptnPlaceholderProviderType`.
Instantiate the placeholder provider struct and return it.

```go
{% include "./assets/example-code/new-provider-function.go" %}
```

5. **Update the validation webhook and crd config:** To update the validation webhook and crd config of the metrics operator.
Add the provider name next to last providers on this
[line](https://github.com/keptn/lifecycle-toolkit/blob/main/metrics-operator/api/v1beta1/keptnmetricsprovider_types.go#L29)
to look like this

`// +kubebuilder:validation:Pattern:=prometheus|dynatrace|datadog|dql|placeholder`.

In the metric-operator directory run `make generate manifests` to update the metrics-operator crd config
Then modify the helm chart and the helm chart crd validation to match the update in the metrics-operator crd config

6. **Add Test Cases:**
* Write a unit test to validate your implementation at the function level.
Unit tests ensure that individual
functions behave as expected and meet their functional requirements.

* Include a Chainsaw test to validate the behavior of Kubernetes resources managed by your code.
Chainsaw tests simulate real-world scenarios and interactions within a Kubernetes cluster, ensuring
the correctness of your Kubernetes configurations and deployments.

Below are the steps for adding an integration test.

* In the directory `test/chainsaw/testmetrics`, create a folder `metrics-provider-placeholder` in our case.
* Within the `keptn-metrics-placeholder` folder, create YAML file `00-install.yaml`.
* `00-install.yaml` contains a sample configuration that installs a valid `KeptnMetricsProvider`
in our case `placeholder` and it also defines a sample `KeptnMetric` configuration
representing a valid use case, while.
* Create a file named `chainsaw-test.yaml` and define the steps for the integration test in chainsaw-test.yaml.

> For more information checkout [an already existing integration test](https://github.com/keptn/lifecycle-toolkit/tree/main/test/chainsaw/testmetrics/metrics-provider)

<!-- markdownlint-enable MD007 -->
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// Inside the providers package

// NewProvider function
func NewProvider(providerType string, log logr.Logger, k8sClient client.Client) (KeptnSLIProvider, error) {
switch strings.ToLower(providerType) {
case KeptnPlaceholderProviderType:
return &placeholder.KeptnPlaceholderProvider{
Log: log,
HttpClient: http.Client{},
}, nil
// Other cases...
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package placeholder

import (
"context"
"fmt"
"net/http"
"time"

"github.com/go-logr/logr"
metricsapi "github.com/keptn/lifecycle-toolkit/metrics-operator/api/v1beta1"
)

type KeptnPlaceholderProvider struct {
Log logr.Logger
HttpClient http.Client
}

func (d *KeptnPlaceholderProvider) FetchAnalysisValue(ctx context.Context, query string, analysis metricsapi.Analysis, provider *metricsapi.KeptnMetricsProvider) (string, error) {
return fmt.Sprintf("placeholder provider FetchAnalysisValue was called with query %s from %d to %d", query, analysis.GetFrom().Unix(), analysis.GetTo().Unix()), nil
}

func (d *KeptnPlaceholderProvider) EvaluateQuery(ctx context.Context, metric metricsapi.KeptnMetric, provider metricsapi.KeptnMetricsProvider) (string, []byte, error) {
return fmt.Sprintf("placeholder provider EvaluateQuery was called with query %s", metric.Spec.Query), nil, nil
}

func (d *KeptnPlaceholderProvider) EvaluateQueryForStep(ctx context.Context, metric metricsapi.KeptnMetric, provider metricsapi.KeptnMetricsProvider) ([]string, []byte, error) {
fromTime, toTime, stepInterval, err := getTimeRangeForStep(metric)
if err != nil {
return nil, nil, err
}
result := fmt.Sprintf("placeholder provider EvaluateQueryForStep was called with query %s from %d to %d at an interval %d", metric.Spec.Query, fromTime, toTime, stepInterval)
return []string{result}, nil, nil
}

func getTimeRangeForStep(metric metricsapi.KeptnMetric) (int64, int64, int64, error) {
intervalDuration, err := time.ParseDuration(metric.Spec.Range.Interval)
if err != nil {
return 0, 0, 0, err
}
stepDuration, err := time.ParseDuration(metric.Spec.Range.Step)
if err != nil {
return 0, 0, 0, err
}
return time.Now().Add(-intervalDuration).Unix(), time.Now().Unix(), stepDuration.Milliseconds(), nil
}
1 change: 1 addition & 0 deletions mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,7 @@ nav:
- Software contributions:
- docs/contribute/software/index.md
- Software development environment: docs/contribute/software/dev-environ.md
- Add a metrics provider: docs/contribute/software/add-new-metric-provider.md
- Documentation contributions:
- docs/contribute/docs/index.md
- Contribution guidelines for documentation: docs/contribute/docs/contrib-guidelines-docs.md
Expand Down

0 comments on commit c4359ba

Please sign in to comment.