Skip to content

Commit 6baea77

Browse files
authored
Monitoring refactor (#149)
1 parent d50ced2 commit 6baea77

25 files changed

+2172
-10
lines changed

.dockerignore

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
bin/
2+
config/

.golangci.yml

+2-1
Original file line numberDiff line numberDiff line change
@@ -241,4 +241,5 @@ issues:
241241
linters:
242242
- unused
243243
- unparam
244-
244+
- text: 'shadow: declaration of "err" shadows declaration at'
245+
linters: [ govet ]

Makefile

+2
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@ manifests: controller-gen ## Generate WebhookConfiguration, ClusterRole and Cust
4949
$(CONTROLLER_GEN) $(CRD_OPTIONS) rbac:roleName=manager-role webhook paths="./..." output:crd:artifacts:config=config/crd/bases
5050
cp config/crd/bases/ydb.tech_storages.yaml deploy/ydb-operator/crds/storage.yaml
5151
cp config/crd/bases/ydb.tech_databases.yaml deploy/ydb-operator/crds/database.yaml
52+
cp config/crd/bases/ydb.tech_databasemonitorings.yaml deploy/ydb-operator/crds/databasemonitoring.yaml
53+
cp config/crd/bases/ydb.tech_storagemonitorings.yaml deploy/ydb-operator/crds/storagemonitoring.yaml
5254

5355
generate: controller-gen ## Generate code containing DeepCopy, DeepCopyInto, and DeepCopyObject method implementations.
5456
$(CONTROLLER_GEN) object:headerFile="build/hack/boilerplate.go.txt" paths="./..."

PROJECT

+28
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
# Code generated by tool. DO NOT EDIT.
2+
# This file is used to track the info used to scaffold your project
3+
# and allow the plugins properly work.
4+
# More info: https://book.kubebuilder.io/reference/project-config.html
15
domain: ydb.tech
26
layout:
37
- go.kubebuilder.io/v3
@@ -25,4 +29,28 @@ resources:
2529
kind: Storage
2630
path: github.com/ydb-platform/ydb-operator/api/v1alpha1
2731
version: v1alpha1
32+
- api:
33+
crdVersion: v1
34+
namespaced: true
35+
controller: true
36+
domain: ydb.tech
37+
group: ydb
38+
kind: DatabaseMonitoring
39+
path: github.com/ydb-platform/ydb-operator/api/v1alpha1
40+
version: v1alpha1
41+
webhooks:
42+
validation: true
43+
webhookVersion: v1
44+
- api:
45+
crdVersion: v1
46+
namespaced: true
47+
controller: true
48+
domain: ydb.tech
49+
group: ydb
50+
kind: StorageMonitoring
51+
path: github.com/ydb-platform/ydb-operator/api/v1alpha1
52+
version: v1alpha1
53+
webhooks:
54+
validation: true
55+
webhookVersion: v1
2856
version: "3"

api/v1alpha1/common_types.go

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package v1alpha1
2+
3+
// NamespacedRef TODO: replace StorageRef
4+
type NamespacedRef struct {
5+
// +kubebuilder:validation:Pattern:=[a-z0-9]([-a-z0-9]*[a-z0-9])?
6+
// +kubebuilder:validation:MaxLength:=63
7+
// +required
8+
Name string `json:"name"`
9+
10+
// +kubebuilder:validation:Pattern:=[a-z0-9]([-a-z0-9]*[a-z0-9])?
11+
// +kubebuilder:validation:MaxLength:=63
12+
// +optional
13+
Namespace string `json:"namespace"`
14+
}
+47
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
package v1alpha1
2+
3+
import (
4+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
5+
)
6+
7+
// DatabaseMonitoringSpec defines the desired state of DatabaseMonitoring
8+
type DatabaseMonitoringSpec struct {
9+
DatabaseClusterRef NamespacedRef `json:"databaseRef"`
10+
11+
// (Optional) Additional labels that will be added to the ServiceMonitor
12+
// +optional
13+
AdditionalLabels map[string]string `json:"additionalLabels,omitempty"`
14+
}
15+
16+
// DatabaseMonitoringStatus defines the observed state of DatabaseMonitoring
17+
type DatabaseMonitoringStatus struct {
18+
State string `json:"state"`
19+
Conditions []metav1.Condition `json:"conditions,omitempty"`
20+
}
21+
22+
//+kubebuilder:object:root=true
23+
//+kubebuilder:subresource:status
24+
//+kubebuilder:printcolumn:name="Status",type="string",JSONPath=".status.state",description="Monitoring status"
25+
//+kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp"
26+
27+
// DatabaseMonitoring is the Schema for the databasemonitorings API
28+
type DatabaseMonitoring struct {
29+
metav1.TypeMeta `json:",inline"`
30+
metav1.ObjectMeta `json:"metadata,omitempty"`
31+
32+
Spec DatabaseMonitoringSpec `json:"spec,omitempty"`
33+
Status DatabaseMonitoringStatus `json:"status,omitempty"`
34+
}
35+
36+
//+kubebuilder:object:root=true
37+
38+
// DatabaseMonitoringList contains a list of DatabaseMonitoring
39+
type DatabaseMonitoringList struct {
40+
metav1.TypeMeta `json:",inline"`
41+
metav1.ListMeta `json:"metadata,omitempty"`
42+
Items []DatabaseMonitoring `json:"items"`
43+
}
44+
45+
func init() {
46+
SchemeBuilder.Register(&DatabaseMonitoring{}, &DatabaseMonitoringList{})
47+
}

api/v1alpha1/monitoring_webhook.go

+117
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
package v1alpha1
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"strings"
7+
8+
"github.com/go-logr/logr"
9+
v1 "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1"
10+
"k8s.io/apimachinery/pkg/api/errors"
11+
"k8s.io/apimachinery/pkg/runtime"
12+
"k8s.io/apimachinery/pkg/runtime/schema"
13+
"k8s.io/apimachinery/pkg/types"
14+
ctrl "sigs.k8s.io/controller-runtime"
15+
"sigs.k8s.io/controller-runtime/pkg/client"
16+
"sigs.k8s.io/controller-runtime/pkg/client/apiutil"
17+
logf "sigs.k8s.io/controller-runtime/pkg/log"
18+
"sigs.k8s.io/controller-runtime/pkg/runtime/inject"
19+
"sigs.k8s.io/controller-runtime/pkg/webhook"
20+
"sigs.k8s.io/controller-runtime/pkg/webhook/admission"
21+
)
22+
23+
// generateValidatePath is a copy from controller-runtime
24+
func generateValidatePath(gvk schema.GroupVersionKind) string {
25+
return "/validate-" + strings.ReplaceAll(gvk.Group, ".", "-") + "-" +
26+
gvk.Version + "-" + strings.ToLower(gvk.Kind)
27+
}
28+
29+
//+kubebuilder:webhook:path=/validate-ydb-tech-v1alpha1-databasemonitoring,mutating=false,failurePolicy=fail,sideEffects=None,groups=ydb.tech,resources=databasemonitorings,verbs=create,versions=v1alpha1,name=vdatabasemonitoring.kb.io,admissionReviewVersions=v1
30+
//+kubebuilder:webhook:path=/validate-ydb-tech-v1alpha1-storagemonitoring,mutating=false,failurePolicy=fail,sideEffects=None,groups=ydb.tech,resources=storagemonitorings,verbs=create,versions=v1alpha1,name=vstoragemonitoring.kb.io,admissionReviewVersions=v1
31+
32+
func RegisterMonitoringValidatingWebhook(mgr ctrl.Manager, enableServiceMonitoring bool) error {
33+
// We are using low-level api here because we need pass client to handler
34+
35+
srv := mgr.GetWebhookServer()
36+
37+
registerWebHook := func(typ runtime.Object, logName string) error {
38+
gvk, err := apiutil.GVKForObject(typ, mgr.GetScheme())
39+
if err != nil {
40+
return err
41+
}
42+
43+
path := generateValidatePath(gvk)
44+
logf.Log.WithName("monitoring-webhooks").Info("Registering a validating webhook", "GVK", gvk, "path", path)
45+
srv.Register(path, &webhook.Admission{
46+
Handler: &monitoringValidationHandler{
47+
logger: logf.Log.WithName(logName),
48+
enableServiceMonitoring: enableServiceMonitoring,
49+
mgr: mgr,
50+
},
51+
})
52+
return nil
53+
}
54+
55+
if err := registerWebHook(&DatabaseMonitoring{}, "databasemonitoring-resource"); err != nil {
56+
return err
57+
}
58+
59+
return registerWebHook(&StorageMonitoring{}, "storagemonitoring-resource")
60+
}
61+
62+
func ensureNoServiceMonitor(ctx context.Context, client client.Client, namespace string, name string) error {
63+
found := &v1.ServiceMonitor{}
64+
err := client.Get(ctx, types.NamespacedName{Namespace: namespace, Name: name}, found)
65+
fmt.Printf("err = %v, namespace=%s, name=%s\n", err, namespace, name)
66+
if err == nil {
67+
return fmt.Errorf("service monitor with name %s already exists", name)
68+
}
69+
70+
if errors.IsNotFound(err) {
71+
return nil
72+
}
73+
74+
return err
75+
}
76+
77+
type monitoringValidationHandler struct {
78+
enableServiceMonitoring bool
79+
logger logr.Logger
80+
client client.Client
81+
mgr ctrl.Manager
82+
decoder *admission.Decoder
83+
}
84+
85+
var (
86+
_ inject.Client = &monitoringValidationHandler{}
87+
_ admission.Handler = &monitoringValidationHandler{}
88+
)
89+
90+
func (v *monitoringValidationHandler) Handle(ctx context.Context, req admission.Request) admission.Response {
91+
if !v.enableServiceMonitoring {
92+
return webhook.Denied("the ydb-operator is running without a service monitoring feature.")
93+
}
94+
95+
err := checkMonitoringCRD(v.mgr, v.logger, false)
96+
if err != nil {
97+
return webhook.Denied(err.Error())
98+
}
99+
100+
// Name can't be an empty string here because it's required in the schema
101+
err = ensureNoServiceMonitor(ctx, v.client, req.Namespace, req.Name)
102+
if err != nil {
103+
return webhook.Denied(err.Error())
104+
}
105+
106+
return admission.Allowed("")
107+
}
108+
109+
func (v *monitoringValidationHandler) InjectClient(c client.Client) error {
110+
v.client = c
111+
return nil
112+
}
113+
114+
func (v *monitoringValidationHandler) InjectDecoder(d *admission.Decoder) error {
115+
v.decoder = d
116+
return nil
117+
}
+47
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
package v1alpha1
2+
3+
import (
4+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
5+
)
6+
7+
// StorageMonitoringSpec defines the desired state of StorageMonitoring
8+
type StorageMonitoringSpec struct {
9+
StorageRef NamespacedRef `json:"storageRef"`
10+
11+
// (Optional) Additional labels that will be added to the ServiceMonitor
12+
// +optional
13+
AdditionalLabels map[string]string `json:"additionalLabels,omitempty"`
14+
}
15+
16+
// StorageMonitoringStatus defines the observed state of StorageMonitoring
17+
type StorageMonitoringStatus struct {
18+
State string `json:"state"`
19+
Conditions []metav1.Condition `json:"conditions,omitempty"`
20+
}
21+
22+
//+kubebuilder:object:root=true
23+
//+kubebuilder:subresource:status
24+
//+kubebuilder:printcolumn:name="Status",type="string",JSONPath=".status.state",description="Monitoring status"
25+
//+kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp"
26+
27+
// StorageMonitoring is the Schema for the storagemonitorings API
28+
type StorageMonitoring struct {
29+
metav1.TypeMeta `json:",inline"`
30+
metav1.ObjectMeta `json:"metadata,omitempty"`
31+
32+
Spec StorageMonitoringSpec `json:"spec,omitempty"`
33+
Status StorageMonitoringStatus `json:"status,omitempty"`
34+
}
35+
36+
//+kubebuilder:object:root=true
37+
38+
// StorageMonitoringList contains a list of StorageMonitoring
39+
type StorageMonitoringList struct {
40+
metav1.TypeMeta `json:",inline"`
41+
metav1.ListMeta `json:"metadata,omitempty"`
42+
Items []StorageMonitoring `json:"items"`
43+
}
44+
45+
func init() {
46+
SchemeBuilder.Register(&StorageMonitoring{}, &StorageMonitoringList{})
47+
}

0 commit comments

Comments
 (0)