Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[CECO-1860][DatadogGenericResource] Add monitor support #1635

Open
wants to merge 6 commits into
base: tbavelier/levan-m/generic-resoource-refactor
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion api/datadoghq/v1alpha1/datadoggenericresource_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ type SupportedResourcesType string

// When adding a new type, make sure to update the kubebuilder validation enum marker
const (
Monitor SupportedResourcesType = "monitor"
Notebook SupportedResourcesType = "notebook"
SyntheticsAPITest SupportedResourcesType = "synthetics_api_test"
SyntheticsBrowserTest SupportedResourcesType = "synthetics_browser_test"
Expand All @@ -22,7 +23,7 @@ const (
// +k8s:openapi-gen=true
type DatadogGenericResourceSpec struct {
// Type is the type of the API object
// +kubebuilder:validation:Enum=notebook;synthetics_api_test;synthetics_browser_test
// +kubebuilder:validation:Enum=monitor;notebook;synthetics_api_test;synthetics_browser_test
Type SupportedResourcesType `json:"type"`
// JsonSpec is the specification of the API object
JsonSpec string `json:"jsonSpec"`
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,11 @@ import (
)

var allowedCustomResourcesEnumMap = map[SupportedResourcesType]string{
Monitor: "",
Notebook: "",
SyntheticsAPITest: "",
SyntheticsBrowserTest: "",
// mockSubresource is used to mock the subresource in tests
// mock_resource is used to mock the subresource in tests
"mock_resource": "",
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ spec:
type:
description: Type is the type of the API object
enum:
- monitor
- notebook
- synthetics_api_test
- synthetics_browser_test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
"type": {
"description": "Type is the type of the API object",
"enum": [
"monitor",
"notebook",
"synthetics_api_test",
"synthetics_browser_test"
Expand Down
21 changes: 10 additions & 11 deletions internal/controller/datadoggenericresource/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,24 +38,23 @@ type Reconciler struct {
client client.Client
datadogSyntheticsClient *datadogV1.SyntheticsApi
datadogNotebooksClient *datadogV1.NotebooksApi
// TODO: add other clients
datadogAuth context.Context
scheme *runtime.Scheme
log logr.Logger
recorder record.EventRecorder
datadogMonitorsClient *datadogV1.MonitorsApi
datadogAuth context.Context
scheme *runtime.Scheme
log logr.Logger
recorder record.EventRecorder
}

func NewReconciler(client client.Client, ddClient datadogclient.DatadogGenericClient, scheme *runtime.Scheme, log logr.Logger, recorder record.EventRecorder) *Reconciler {
return &Reconciler{
client: client,
datadogSyntheticsClient: ddClient.SyntheticsClient,
datadogNotebooksClient: ddClient.NotebooksClient,
// TODO: add other clients
// datadogOtherClient: ddClient.OtherClient,
datadogAuth: ddClient.Auth,
scheme: scheme,
log: log,
recorder: recorder,
datadogMonitorsClient: ddClient.MonitorsClient,
datadogAuth: ddClient.Auth,
scheme: scheme,
log: log,
recorder: recorder,
}
}

Expand Down
91 changes: 91 additions & 0 deletions internal/controller/datadoggenericresource/monitors.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
package datadoggenericresource

import (
"context"
"encoding/json"

"github.com/DataDog/datadog-operator/api/datadoghq/v1alpha1"
"github.com/go-logr/logr"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"

"github.com/DataDog/datadog-api-client-go/v2/api/datadogV1"
)

type MonitorHandler struct{}

func (h *MonitorHandler) createResourcefunc(r *Reconciler, logger logr.Logger, instance *v1alpha1.DatadogGenericResource, status *v1alpha1.DatadogGenericResourceStatus, now metav1.Time, hash string) error {
createdMonitor, err := createMonitor(r.datadogAuth, r.datadogMonitorsClient, instance)
if err != nil {
logger.Error(err, "error creating monitor")
updateErrStatus(status, now, v1alpha1.DatadogSyncStatusCreateError, "CreatingCustomResource", err)
return err
}
logger.Info("created a new monitor", "monitor Id", createdMonitor.GetId())
status.Id = resourceInt64ToStringID(createdMonitor.GetId())
createdTime := metav1.NewTime(*createdMonitor.Created)
status.Created = &createdTime
status.LastForceSyncTime = &createdTime
status.Creator = *createdMonitor.GetCreator().Handle
status.SyncStatus = v1alpha1.DatadogSyncStatusOK
status.CurrentHash = hash
return nil
}

func (h *MonitorHandler) getResourcefunc(r *Reconciler, instance *v1alpha1.DatadogGenericResource) error {
_, err := getMonitor(r.datadogAuth, r.datadogMonitorsClient, instance.Status.Id)
return err
}
func (h *MonitorHandler) updateResourcefunc(r *Reconciler, instance *v1alpha1.DatadogGenericResource) error {
_, err := updateMonitor(r.datadogAuth, r.datadogMonitorsClient, instance)
return err
}
func (h *MonitorHandler) deleteResourcefunc(r *Reconciler, instance *v1alpha1.DatadogGenericResource) error {
return deleteMonitor(r.datadogAuth, r.datadogMonitorsClient, instance.Status.Id)
}

func getMonitor(auth context.Context, client *datadogV1.MonitorsApi, monitorStringID string) (datadogV1.Monitor, error) {
monitorID, err := resourceStringToInt64ID(monitorStringID)
if err != nil {
return datadogV1.Monitor{}, err
}
monitor, _, err := client.GetMonitor(auth, monitorID)
if err != nil {
return datadogV1.Monitor{}, translateClientError(err, "error getting monitor")
}
return monitor, nil
}

func deleteMonitor(auth context.Context, client *datadogV1.MonitorsApi, monitorStringID string) error {
monitorID, err := resourceStringToInt64ID(monitorStringID)
if err != nil {
return err
}
if _, _, err := client.DeleteMonitor(auth, monitorID); err != nil {
return translateClientError(err, "error deleting monitor")
}
return nil
}

func createMonitor(auth context.Context, client *datadogV1.MonitorsApi, instance *v1alpha1.DatadogGenericResource) (datadogV1.Monitor, error) {
monitorBody := &datadogV1.Monitor{}
json.Unmarshal([]byte(instance.Spec.JsonSpec), monitorBody)
monitor, _, err := client.CreateMonitor(auth, *monitorBody)
if err != nil {
return datadogV1.Monitor{}, translateClientError(err, "error creating monitor")
}
return monitor, nil
}

func updateMonitor(auth context.Context, client *datadogV1.MonitorsApi, instance *v1alpha1.DatadogGenericResource) (datadogV1.Monitor, error) {
monitorUpdateData := &datadogV1.MonitorUpdateRequest{}
json.Unmarshal([]byte(instance.Spec.JsonSpec), monitorUpdateData)
monitorID, err := resourceStringToInt64ID(instance.Status.Id)
if err != nil {
return datadogV1.Monitor{}, err
}
monitorUpdated, _, err := client.UpdateMonitor(auth, monitorID, *monitorUpdateData)
if err != nil {
return datadogV1.Monitor{}, translateClientError(err, "error updating monitor")
}
return monitorUpdated, nil
}
2 changes: 2 additions & 0 deletions internal/controller/datadoggenericresource/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ func apiCreateAndUpdateStatus(r *Reconciler, logger logr.Logger, instance *v1alp

func getHandler(resourceType v1alpha1.SupportedResourcesType) ResourceHandler {
switch resourceType {
case v1alpha1.Monitor:
return &MonitorHandler{}
case v1alpha1.Notebook:
return &NotebookHandler{}
case v1alpha1.SyntheticsAPITest:
Expand Down
12 changes: 9 additions & 3 deletions pkg/datadogclient/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,8 +98,8 @@ func InitDatadogDashboardClient(logger logr.Logger, creds config.Creds) (Datadog
type DatadogGenericClient struct {
SyntheticsClient *datadogV1.SyntheticsApi
NotebooksClient *datadogV1.NotebooksApi
// TODO: other clients depending on the resource
Auth context.Context
MonitorsClient *datadogV1.MonitorsApi
Auth context.Context
}

// InitDatadogGenericClient initializes the Datadog Generic API Client and establishes credentials.
Expand All @@ -112,13 +112,19 @@ func InitDatadogGenericClient(logger logr.Logger, creds config.Creds) (DatadogGe
apiClient := datadogapi.NewAPIClient(configV1)
syntheticsClient := datadogV1.NewSyntheticsApi(apiClient)
notebooksClient := datadogV1.NewNotebooksApi(apiClient)
monitorsClient := datadogV1.NewMonitorsApi(apiClient)

authV1, err := setupAuth(logger, creds)
if err != nil {
return DatadogGenericClient{}, err
}

return DatadogGenericClient{SyntheticsClient: syntheticsClient, NotebooksClient: notebooksClient, Auth: authV1}, nil
return DatadogGenericClient{
SyntheticsClient: syntheticsClient,
NotebooksClient: notebooksClient,
MonitorsClient: monitorsClient,
Auth: authV1,
}, nil
}

func setupAuth(logger logr.Logger, creds config.Creds) (context.Context, error) {
Expand Down
Loading