Skip to content

Commit

Permalink
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
add monitor to supported generic resource controller
Browse files Browse the repository at this point in the history
tbavelier committed Jan 20, 2025
1 parent 7920f22 commit 73fcd2d
Showing 8 changed files with 118 additions and 16 deletions.
3 changes: 2 additions & 1 deletion api/datadoghq/v1alpha1/datadoggenericresource_types.go
Original file line number Diff line number Diff line change
@@ -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"
@@ -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"`
3 changes: 2 additions & 1 deletion api/datadoghq/v1alpha1/datadoggenericresource_validation.go
Original file line number Diff line number Diff line change
@@ -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": "",
}

Original file line number Diff line number Diff line change
@@ -57,6 +57,7 @@ spec:
type:
description: Type is the type of the API object
enum:
- monitor
- notebook
- synthetics_api_test
- synthetics_browser_test
Original file line number Diff line number Diff line change
@@ -24,6 +24,7 @@
"type": {
"description": "Type is the type of the API object",
"enum": [
"monitor",
"notebook",
"synthetics_api_test",
"synthetics_browser_test"
21 changes: 10 additions & 11 deletions internal/controller/datadoggenericresource/controller.go
Original file line number Diff line number Diff line change
@@ -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,
}
}

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
@@ -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:
12 changes: 9 additions & 3 deletions pkg/datadogclient/client.go
Original file line number Diff line number Diff line change
@@ -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.
@@ -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) {

0 comments on commit 73fcd2d

Please sign in to comment.