Skip to content

Commit

Permalink
feat: implemented datadog provider with httpclient instead of dd-go-c…
Browse files Browse the repository at this point in the history
…lient library due to its limitation

Signed-off-by: Sudipto Baral <[email protected]>
  • Loading branch information
sudiptob2 committed Mar 4, 2023
1 parent bd49357 commit d08e4e5
Show file tree
Hide file tree
Showing 6 changed files with 124 additions and 0 deletions.
1 change: 1 addition & 0 deletions metrics-operator/controllers/common/providers/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ package providers
const DynatraceProviderName = "dynatrace"
const DynatraceDQLProviderName = "dql"
const PrometheusProviderName = "prometheus"
const DataDogProviderName = "datadog"
31 changes: 31 additions & 0 deletions metrics-operator/controllers/common/providers/datadog/common.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package datadog

import (
"context"
"errors"
"fmt"

metricsapi "github.com/keptn/lifecycle-toolkit/metrics-operator/api/v1alpha2"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/types"
"sigs.k8s.io/controller-runtime/pkg/client"
)

var ErrSecretKeyRefNotDefined = errors.New("the SecretKeyRef property with the DataDog API Key is missing")

func getDDSecret(ctx context.Context, provider metricsapi.KeptnMetricsProvider, k8sClient client.Client) (string, error) {
if !provider.HasSecretDefined() {
return "", ErrSecretKeyRefNotDefined
}
ddCredsSecret := &corev1.Secret{}
if err := k8sClient.Get(ctx, types.NamespacedName{Name: provider.Spec.SecretKeyRef.Name, Namespace: provider.Namespace}, ddCredsSecret); err != nil {
return "", err
}
fmt.Println(provider.Spec.SecretKeyRef.Key)

apiKey := ddCredsSecret.Data[provider.Spec.SecretKeyRef.Key]
if len(apiKey) == 0 {
return "", fmt.Errorf("secret contains invalid key %s", provider.Spec.SecretKeyRef.Key)
}
return string(apiKey), nil
}
80 changes: 80 additions & 0 deletions metrics-operator/controllers/common/providers/datadog/datadog.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
package datadog

import (
"context"
"encoding/json"
"fmt"
"github.com/DataDog/datadog-api-client-go/v2/api/datadogV1"
"github.com/go-logr/logr"
metricsapi "github.com/keptn/lifecycle-toolkit/metrics-operator/api/v1alpha2"
"io"
"net/url"
"strconv"
"time"

//nolint:gci
"net/http" //nolint:gci
"sigs.k8s.io/controller-runtime/pkg/client"
)

type KeptnDataDogProvider struct {
Log logr.Logger
HttpClient http.Client
K8sClient client.Client
}

// EvaluateQuery fetches the SLI values from datadog provider
func (d *KeptnDataDogProvider) EvaluateQuery(ctx context.Context, metric metricsapi.KeptnMetric, provider metricsapi.KeptnMetricsProvider) (string, []byte, error) {
ctx, cancel := context.WithTimeout(ctx, 20*time.Second)
defer cancel()

// Assumed default metric duration as 1 day(s)
// Think a better way to handle this
fromTime := time.Now().AddDate(0, 0, -1).Unix()
toTime := time.Now().Unix()
qURL := provider.Spec.TargetServer + "/api/v1/query?from=" + strconv.Itoa(int(fromTime)) + "&to=" + strconv.Itoa(int(toTime)) + "&query=" + url.QueryEscape(metric.Spec.Query)
req, err := http.NewRequestWithContext(ctx, "GET", qURL, nil)
if err != nil {
d.Log.Error(err, "Error while creating request")
return "", nil, err
}

apiKey, err := getDDSecret(ctx, provider, d.K8sClient)
if err != nil {
return "", nil, err
}
appKey := "appkey" // TODO: retrieve this from kubernetes secret

req.Header.Set("Accept", "application/json")
req.Header.Set("Dd-Api-Key", apiKey)
req.Header.Set("Dd-Application-Key", appKey)

res, err := d.HttpClient.Do(req)
if err != nil {
d.Log.Error(err, "Error while creating request")
return "", nil, err
}
defer func() {
err := res.Body.Close()
if err != nil {
d.Log.Error(err, "Could not close request body")
}
}()

b, _ := io.ReadAll(res.Body)
result := datadogV1.MetricsQueryResponse{}
err = json.Unmarshal(b, &result)
if err != nil {
d.Log.Error(err, "Error while parsing response")
return "", nil, err
}

if len(result.Series) == 0 {
d.Log.Info("No values in query result")
return "", nil, fmt.Errorf("no values in query result")
}

points := (result.Series)[0].Pointlist
value := strconv.FormatFloat(*points[len(points)-1][1], 'g', 5, 64)
return value, b, nil
}
6 changes: 6 additions & 0 deletions metrics-operator/controllers/common/providers/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (

"github.com/go-logr/logr"
metricsapi "github.com/keptn/lifecycle-toolkit/metrics-operator/api/v1alpha2"
"github.com/keptn/lifecycle-toolkit/metrics-operator/controllers/common/providers/datadog"
"github.com/keptn/lifecycle-toolkit/metrics-operator/controllers/common/providers/dynatrace"
"github.com/keptn/lifecycle-toolkit/metrics-operator/controllers/common/providers/prometheus"
"sigs.k8s.io/controller-runtime/pkg/client"
Expand Down Expand Up @@ -37,6 +38,11 @@ func NewProvider(provider string, log logr.Logger, k8sClient client.Client) (Kep
k8sClient,
dynatrace.WithLogger(log),
), nil
case DataDogProviderName:
return &datadog.KeptnDataDogProvider{
Log: log,
HttpClient: http.Client{},
}, nil
default:
return nil, fmt.Errorf("provider %s not supported", provider)
}
Expand Down
2 changes: 2 additions & 0 deletions metrics-operator/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ module github.com/keptn/lifecycle-toolkit/metrics-operator
go 1.18

require (
github.com/DataDog/datadog-api-client-go/v2 v2.9.0
github.com/benbjohnson/clock v1.3.0
github.com/go-logr/logr v1.2.3
github.com/gorilla/mux v1.8.0
Expand All @@ -27,6 +28,7 @@ require (

require (
cloud.google.com/go/compute/metadata v0.2.3 // indirect
github.com/DataDog/zstd v1.5.0 // indirect
github.com/NYTimes/gziphandler v1.1.1 // indirect
github.com/antlr/antlr4/runtime/Go/antlr v1.4.10 // indirect
github.com/beorn7/perks v1.0.1 // indirect
Expand Down
4 changes: 4 additions & 0 deletions metrics-operator/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@ dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/DataDog/datadog-api-client-go/v2 v2.9.0 h1:1Cz3mqj95iqnQPykEovq2p52rrU26XvLC2Fz6hPE+TU=
github.com/DataDog/datadog-api-client-go/v2 v2.9.0/go.mod h1:sHt3EuVMN8PSYJu065qwp3pZxCwR3RZP4sJnYwj/ZQY=
github.com/DataDog/zstd v1.5.0 h1:+K/VEwIAaPcHiMtQvpLD4lqW7f0Gk3xdYZmI1hD+CXo=
github.com/DataDog/zstd v1.5.0/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw=
github.com/NYTimes/gziphandler v1.1.1 h1:ZUDjpQae29j0ryrS0u/B8HZfJBtBQHjqw2rQ2cqUQ3I=
github.com/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMomdKFjzJNB0c=
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
Expand Down

0 comments on commit d08e4e5

Please sign in to comment.