Skip to content

Commit 24de754

Browse files
authored
[CECO-1763] Controller for generic custom resource (#1534)
* working browser tests and notebooks * clean up a bit * Use helper function * Start refactoring - not tested yet * spec -> jsonSpec refactor * refactor & validation - working version (browser, notebook) * revert devcontainer name + crd->cr reference * remove redundant conversion * Add validation that jsonSpec is not empty + unit test validation * kustomize datadoggenericcr * unit test finalizer - need to mock API to go further * finalizer test * utils unit test * controller unit test * notebook utils unit tedt * more unit tests and support synthetics_api_test * re-order alphabetically * resolve conflict before merging main * resolve kustomization conflict * empty * datadoggenericcr to datadoggenericresource 1 * datadoggenericcr to datadoggenericresource 2 * datadoggenericcr to datadoggenericresource 3 * datadoggenericcr to datadoggenericresource 4 * re-generate rbac * fix main.go * add comment on kubebuilder marker
1 parent db00883 commit 24de754

28 files changed

+2347
-31
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
// Unless explicitly stated otherwise all files in this repository are licensed
2+
// under the Apache License Version 2.0.
3+
// This product includes software developed at Datadog (https://www.datadoghq.com/).
4+
// Copyright 2016-present Datadog, Inc.
5+
6+
package v1alpha1
7+
8+
import (
9+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
10+
)
11+
12+
type SupportedResourcesType string
13+
14+
// When adding a new type, make sure to update the kubebuilder validation enum marker
15+
const (
16+
Notebook SupportedResourcesType = "notebook"
17+
SyntheticsAPITest SupportedResourcesType = "synthetics_api_test"
18+
SyntheticsBrowserTest SupportedResourcesType = "synthetics_browser_test"
19+
)
20+
21+
// DatadogGenericResourceSpec defines the desired state of DatadogGenericResource
22+
// +k8s:openapi-gen=true
23+
type DatadogGenericResourceSpec struct {
24+
// Type is the type of the API object
25+
// +kubebuilder:validation:Enum=notebook;synthetics_api_test;synthetics_browser_test
26+
Type SupportedResourcesType `json:"type"`
27+
// JsonSpec is the specification of the API object
28+
JsonSpec string `json:"jsonSpec"`
29+
}
30+
31+
// DatadogGenericResourceStatus defines the observed state of DatadogGenericResource
32+
// +k8s:openapi-gen=true
33+
type DatadogGenericResourceStatus struct {
34+
// Conditions represents the latest available observations of the state of a DatadogGenericResource.
35+
// +listType=map
36+
// +listMapKey=type
37+
Conditions []metav1.Condition `json:"conditions,omitempty"`
38+
// Id is the object unique identifier generated in Datadog.
39+
Id string `json:"id,omitempty"`
40+
// Creator is the identity of the creator.
41+
Creator string `json:"creator,omitempty"`
42+
// Created is the time the object was created.
43+
Created *metav1.Time `json:"created,omitempty"`
44+
// SyncStatus shows the health of syncing the object state to Datadog.
45+
SyncStatus DatadogSyncStatus `json:"syncStatus,omitempty"`
46+
// CurrentHash tracks the hash of the current DatadogGenericResourceSpec to know
47+
// if the JsonSpec has changed and needs an update.
48+
CurrentHash string `json:"currentHash,omitempty"`
49+
// LastForceSyncTime is the last time the API object was last force synced with the custom resource
50+
LastForceSyncTime *metav1.Time `json:"lastForceSyncTime,omitempty"`
51+
}
52+
53+
type DatadogSyncStatus string
54+
55+
const (
56+
// DatadogSyncStatusOK means syncing is OK.
57+
DatadogSyncStatusOK DatadogSyncStatus = "OK"
58+
// DatadogSyncStatusValidateError means there is an object validation error.
59+
DatadogSyncStatusValidateError DatadogSyncStatus = "error validating object"
60+
// DatadogSyncStatusUpdateError means there is an object update error.
61+
DatadogSyncStatusUpdateError DatadogSyncStatus = "error updating object"
62+
// DatadogSyncStatusCreateError means there is an error getting the object.
63+
DatadogSyncStatusCreateError DatadogSyncStatus = "error creating object"
64+
// DatadogSyncStatusGetError means there is an error getting the object.
65+
DatadogSyncStatusGetError DatadogSyncStatus = "error getting object"
66+
)
67+
68+
// DatadogGenericResource is the Schema for the DatadogGenericResources API
69+
// +kubebuilder:object:root=true
70+
// +kubebuilder:subresource:status
71+
// +kubebuilder:resource:path=datadoggenericresources,scope=Namespaced,shortName=ddgr
72+
// +kubebuilder:printcolumn:name="id",type="string",JSONPath=".status.id"
73+
// +kubebuilder:printcolumn:name="sync status",type="string",JSONPath=".status.syncStatus"
74+
// +kubebuilder:printcolumn:name="age",type="date",JSONPath=".metadata.creationTimestamp"
75+
// +k8s:openapi-gen=true
76+
// +genclient
77+
type DatadogGenericResource struct {
78+
metav1.TypeMeta `json:",inline"`
79+
metav1.ObjectMeta `json:"metadata,omitempty"`
80+
81+
Spec DatadogGenericResourceSpec `json:"spec,omitempty"`
82+
Status DatadogGenericResourceStatus `json:"status,omitempty"`
83+
}
84+
85+
// DatadogGenericResourceList contains a list of DatadogGenericResource
86+
// +kubebuilder:object:root=true
87+
type DatadogGenericResourceList struct {
88+
metav1.TypeMeta `json:",inline"`
89+
metav1.ListMeta `json:"metadata,omitempty"`
90+
Items []DatadogGenericResource `json:"items"`
91+
}
92+
93+
func init() {
94+
SchemeBuilder.Register(&DatadogGenericResource{}, &DatadogGenericResourceList{})
95+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// Unless explicitly stated otherwise all files in this repository are licensed
2+
// under the Apache License Version 2.0.
3+
// This product includes software developed at Datadog (https://www.datadoghq.com/).
4+
// Copyright 2016-present Datadog, Inc.
5+
6+
package v1alpha1
7+
8+
import (
9+
"fmt"
10+
11+
utilserrors "k8s.io/apimachinery/pkg/util/errors"
12+
)
13+
14+
var allowedCustomResourcesEnumMap = map[SupportedResourcesType]string{
15+
Notebook: "",
16+
SyntheticsAPITest: "",
17+
SyntheticsBrowserTest: "",
18+
// mockSubresource is used to mock the subresource in tests
19+
"mock_resource": "",
20+
}
21+
22+
func IsValidDatadogGenericResource(spec *DatadogGenericResourceSpec) error {
23+
var errs []error
24+
if _, ok := allowedCustomResourcesEnumMap[spec.Type]; !ok {
25+
errs = append(errs, fmt.Errorf("spec.Type must be a supported resource type"))
26+
}
27+
28+
if spec.JsonSpec == "" {
29+
errs = append(errs, fmt.Errorf("spec.JsonSpec must be defined"))
30+
}
31+
32+
return utilserrors.NewAggregate(errs)
33+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
// Unless explicitly stated otherwise all files in this repository are licensed
2+
// under the Apache License Version 2.0.
3+
// This product includes software developed at Datadog (https://www.datadoghq.com/).
4+
// Copyright 2016-present Datadog, Inc.
5+
6+
package v1alpha1
7+
8+
import (
9+
"testing"
10+
11+
"github.com/stretchr/testify/assert"
12+
)
13+
14+
func Test_IsValidDatadogGenericResource(t *testing.T) {
15+
tests := []struct {
16+
name string
17+
spec *DatadogGenericResourceSpec
18+
wantErr string
19+
}{
20+
{
21+
name: "supported resource type and non empty json spec",
22+
spec: &DatadogGenericResourceSpec{
23+
Type: SyntheticsBrowserTest,
24+
// N.B. This is a valid JSON string but not valid for the API (not a model payload).
25+
// This is just for testing purposes.
26+
JsonSpec: "{\"foo\": \"bar\"}",
27+
},
28+
wantErr: "",
29+
},
30+
{
31+
name: "unsupported resource type",
32+
spec: &DatadogGenericResourceSpec{
33+
Type: "foo",
34+
JsonSpec: "{\"foo\": \"bar\"}",
35+
},
36+
wantErr: "spec.Type must be a supported resource type",
37+
},
38+
{
39+
name: "empty json spec",
40+
spec: &DatadogGenericResourceSpec{
41+
Type: Notebook,
42+
JsonSpec: "",
43+
},
44+
wantErr: "spec.JsonSpec must be defined",
45+
},
46+
}
47+
for _, test := range tests {
48+
t.Run(test.name, func(t *testing.T) {
49+
err := IsValidDatadogGenericResource(test.spec)
50+
if test.wantErr != "" {
51+
assert.EqualError(t, err, test.wantErr)
52+
} else {
53+
assert.NoError(t, err)
54+
}
55+
})
56+
}
57+
}

api/datadoghq/v1alpha1/zz_generated.deepcopy.go

+104
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)