Skip to content

Commit ea3e1c9

Browse files
committed
Add API for metrics collection via OTel.
1 parent 37ea0c3 commit ea3e1c9

File tree

6 files changed

+400
-0
lines changed

6 files changed

+400
-0
lines changed

config/crd/bases/postgres-operator.crunchydata.com_pgadmins.yaml

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2042,6 +2042,71 @@ spec:
20422042
- message: must be at least one hour
20432043
rule: duration("1h") <= self && self <= duration("8760h")
20442044
type: object
2045+
metrics:
2046+
description: Metrics is the place for users to configure metrics
2047+
collection.
2048+
properties:
2049+
customQueries:
2050+
description: |-
2051+
Where users can turn off built-in metrics and also provide their own
2052+
custom queries.
2053+
properties:
2054+
add:
2055+
description: User defined queries and metrics.
2056+
items:
2057+
properties:
2058+
collectionInterval:
2059+
default: 5s
2060+
description: How often the queries should be run.
2061+
format: duration
2062+
maxLength: 20
2063+
minLength: 1
2064+
pattern: ^((PT)?( *[0-9]+ *(?i:(ms|s|m)|(milli|sec|min)s?))+|0)$
2065+
type: string
2066+
x-kubernetes-validations:
2067+
- rule: duration("0") <= self && self <= duration("60m")
2068+
name:
2069+
description: The name of this batch of queries.
2070+
type: string
2071+
queries:
2072+
description: A ConfigMap holding the yaml file that
2073+
contains the queries.
2074+
properties:
2075+
key:
2076+
description: Name of the data field within the
2077+
ConfigMap.
2078+
maxLength: 253
2079+
minLength: 1
2080+
pattern: ^[-._a-zA-Z0-9]+$
2081+
type: string
2082+
x-kubernetes-validations:
2083+
- message: cannot be "." or start with ".."
2084+
rule: self != "." && !self.startsWith("..")
2085+
name:
2086+
description: Name of the ConfigMap.
2087+
maxLength: 253
2088+
minLength: 1
2089+
pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?([.][a-z0-9]([-a-z0-9]*[a-z0-9])?)*$
2090+
type: string
2091+
required:
2092+
- key
2093+
- name
2094+
type: object
2095+
x-kubernetes-map-type: atomic
2096+
required:
2097+
- name
2098+
- queries
2099+
type: object
2100+
type: array
2101+
remote:
2102+
description: |-
2103+
A list of built-in queries that should be removed. If all queries for a
2104+
given SQL statement are removed, the SQL statement will no longer be run.
2105+
items:
2106+
type: string
2107+
type: array
2108+
type: object
2109+
type: object
20452110
resources:
20462111
description: Resources holds the resource requirements for the
20472112
collector container.

config/crd/bases/postgres-operator.crunchydata.com_postgresclusters.yaml

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11698,6 +11698,71 @@ spec:
1169811698
- message: must be at least one hour
1169911699
rule: duration("1h") <= self && self <= duration("8760h")
1170011700
type: object
11701+
metrics:
11702+
description: Metrics is the place for users to configure metrics
11703+
collection.
11704+
properties:
11705+
customQueries:
11706+
description: |-
11707+
Where users can turn off built-in metrics and also provide their own
11708+
custom queries.
11709+
properties:
11710+
add:
11711+
description: User defined queries and metrics.
11712+
items:
11713+
properties:
11714+
collectionInterval:
11715+
default: 5s
11716+
description: How often the queries should be run.
11717+
format: duration
11718+
maxLength: 20
11719+
minLength: 1
11720+
pattern: ^((PT)?( *[0-9]+ *(?i:(ms|s|m)|(milli|sec|min)s?))+|0)$
11721+
type: string
11722+
x-kubernetes-validations:
11723+
- rule: duration("0") <= self && self <= duration("60m")
11724+
name:
11725+
description: The name of this batch of queries.
11726+
type: string
11727+
queries:
11728+
description: A ConfigMap holding the yaml file that
11729+
contains the queries.
11730+
properties:
11731+
key:
11732+
description: Name of the data field within the
11733+
ConfigMap.
11734+
maxLength: 253
11735+
minLength: 1
11736+
pattern: ^[-._a-zA-Z0-9]+$
11737+
type: string
11738+
x-kubernetes-validations:
11739+
- message: cannot be "." or start with ".."
11740+
rule: self != "." && !self.startsWith("..")
11741+
name:
11742+
description: Name of the ConfigMap.
11743+
maxLength: 253
11744+
minLength: 1
11745+
pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?([.][a-z0-9]([-a-z0-9]*[a-z0-9])?)*$
11746+
type: string
11747+
required:
11748+
- key
11749+
- name
11750+
type: object
11751+
x-kubernetes-map-type: atomic
11752+
required:
11753+
- name
11754+
- queries
11755+
type: object
11756+
type: array
11757+
remote:
11758+
description: |-
11759+
A list of built-in queries that should be removed. If all queries for a
11760+
given SQL statement are removed, the SQL statement will no longer be run.
11761+
items:
11762+
type: string
11763+
type: array
11764+
type: object
11765+
type: object
1170111766
resources:
1170211767
description: Resources holds the resource requirements for the
1170311768
collector container.

pkg/apis/postgres-operator.crunchydata.com/v1beta1/config_types.go

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,49 @@ import (
88
corev1 "k8s.io/api/core/v1"
99
)
1010

11+
// +structType=atomic
12+
type OptionalConfigMapKeyRef struct {
13+
ConfigMapKeyRef `json:",inline"`
14+
15+
// Whether or not the ConfigMap or its data must be defined. Defaults to false.
16+
// +optional
17+
Optional *bool `json:"optional,omitempty"`
18+
}
19+
20+
// AsProjection returns a copy of this as a [corev1.ConfigMapProjection].
21+
func (in *OptionalConfigMapKeyRef) AsProjection(path string) corev1.ConfigMapProjection {
22+
out := in.ConfigMapKeyRef.AsProjection(path)
23+
if in.Optional != nil {
24+
v := *in.Optional
25+
out.Optional = &v
26+
}
27+
return out
28+
}
29+
30+
// +structType=atomic
31+
type ConfigMapKeyRef struct {
32+
// Name of the ConfigMap.
33+
// ---
34+
// https://pkg.go.dev/k8s.io/kubernetes/pkg/apis/core/validation#ValidateConfigMapName
35+
// +required
36+
Name DNS1123Subdomain `json:"name"`
37+
38+
// Name of the data field within the ConfigMap.
39+
// ---
40+
// https://github.com/kubernetes/kubernetes/blob/v1.32.0/pkg/apis/core/validation/validation.go#L2849
41+
// https://pkg.go.dev/k8s.io/apimachinery/pkg/util/validation#IsConfigMapKey
42+
// +required
43+
Key ConfigDataKey `json:"key"`
44+
}
45+
46+
// AsProjection returns a copy of this as a [corev1.ConfigMapProjection].
47+
func (in *ConfigMapKeyRef) AsProjection(path string) corev1.ConfigMapProjection {
48+
var out corev1.ConfigMapProjection
49+
out.Name = in.Name
50+
out.Items = []corev1.KeyToPath{{Key: in.Key, Path: path}}
51+
return out
52+
}
53+
1154
// +structType=atomic
1255
type OptionalSecretKeyRef struct {
1356
SecretKeyRef `json:",inline"`

pkg/apis/postgres-operator.crunchydata.com/v1beta1/config_types_test.go

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,71 @@ import (
1414
"github.com/crunchydata/postgres-operator/pkg/apis/postgres-operator.crunchydata.com/v1beta1"
1515
)
1616

17+
func TestOptionalConfigMapKeyRefAsProjection(t *testing.T) {
18+
t.Run("Null", func(t *testing.T) {
19+
in := v1beta1.OptionalConfigMapKeyRef{}
20+
in.Name, in.Key = "one", "two"
21+
22+
out := in.AsProjection("three")
23+
b, err := yaml.Marshal(out)
24+
assert.NilError(t, err)
25+
assert.DeepEqual(t, string(b), strings.TrimSpace(`
26+
items:
27+
- key: two
28+
path: three
29+
name: one
30+
`)+"\n")
31+
})
32+
33+
t.Run("True", func(t *testing.T) {
34+
True := true
35+
in := v1beta1.OptionalConfigMapKeyRef{Optional: &True}
36+
in.Name, in.Key = "one", "two"
37+
38+
out := in.AsProjection("three")
39+
b, err := yaml.Marshal(out)
40+
assert.NilError(t, err)
41+
assert.DeepEqual(t, string(b), strings.TrimSpace(`
42+
items:
43+
- key: two
44+
path: three
45+
name: one
46+
optional: true
47+
`)+"\n")
48+
})
49+
50+
t.Run("False", func(t *testing.T) {
51+
False := false
52+
in := v1beta1.OptionalConfigMapKeyRef{Optional: &False}
53+
in.Name, in.Key = "one", "two"
54+
55+
out := in.AsProjection("three")
56+
b, err := yaml.Marshal(out)
57+
assert.NilError(t, err)
58+
assert.DeepEqual(t, string(b), strings.TrimSpace(`
59+
items:
60+
- key: two
61+
path: three
62+
name: one
63+
optional: false
64+
`)+"\n")
65+
})
66+
}
67+
68+
func TestConfigMapKeyRefAsProjection(t *testing.T) {
69+
in := v1beta1.ConfigMapKeyRef{Name: "asdf", Key: "foobar"}
70+
out := in.AsProjection("some-path")
71+
72+
b, err := yaml.Marshal(out)
73+
assert.NilError(t, err)
74+
assert.DeepEqual(t, string(b), strings.TrimSpace(`
75+
items:
76+
- key: foobar
77+
path: some-path
78+
name: asdf
79+
`)+"\n")
80+
}
81+
1782
func TestOptionalSecretKeyRefAsProjection(t *testing.T) {
1883
t.Run("Null", func(t *testing.T) {
1984
in := v1beta1.OptionalSecretKeyRef{}

pkg/apis/postgres-operator.crunchydata.com/v1beta1/instrumentation_types.go

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,10 @@ type InstrumentationSpec struct {
2525
// Logs is the place for users to configure the log collection.
2626
// +optional
2727
Logs *InstrumentationLogsSpec `json:"logs,omitempty"`
28+
29+
// Metrics is the place for users to configure metrics collection.
30+
// +optional
31+
Metrics *InstrumentationMetricsSpec `json:"metrics,omitempty"`
2832
}
2933

3034
// InstrumentationConfigSpec allows users to configure their own exporters,
@@ -91,6 +95,55 @@ type InstrumentationLogsSpec struct {
9195
RetentionPeriod *Duration `json:"retentionPeriod,omitempty"`
9296
}
9397

98+
type InstrumentationMetricsSpec struct {
99+
// Where users can turn off built-in metrics and also provide their own
100+
// custom queries.
101+
// +optional
102+
CustomQueries *InstrumentationCustomQueriesSpec `json:"customQueries,omitempty"`
103+
}
104+
105+
type InstrumentationCustomQueriesSpec struct {
106+
// User defined queries and metrics.
107+
// +optional
108+
Add []InstrumentationCustomQueries `json:"add,omitempty"`
109+
110+
// A list of built-in queries that should be removed. If all queries for a
111+
// given SQL statement are removed, the SQL statement will no longer be run.
112+
//
113+
// +optional
114+
Remove []string `json:"remote,omitempty"`
115+
}
116+
117+
type InstrumentationCustomQueries struct {
118+
// The name of this batch of queries.
119+
//
120+
// +required
121+
Name string `json:"name"`
122+
123+
// A ConfigMap holding the yaml file that contains the queries.
124+
//
125+
// +required
126+
Queries ConfigMapKeyRef `json:"queries"`
127+
128+
// How often the queries should be run.
129+
// ---
130+
// Kubernetes ensures the value is in the "duration" format, but go ahead
131+
// and loosely validate the format to show some acceptable units.
132+
// NOTE: This rejects fractional numbers: https://github.com/kubernetes/kube-openapi/issues/523
133+
// +kubebuilder:validation:Pattern=`^((PT)?( *[0-9]+ *(?i:(ms|s|m)|(milli|sec|min)s?))+|0)$`
134+
//
135+
// `controller-gen` needs to know "Type=string" to allow a "Pattern".
136+
// +kubebuilder:validation:Type=string
137+
//
138+
// Set a max length to keep rule costs low.
139+
// +kubebuilder:validation:MaxLength=20
140+
// +kubebuilder:validation:XValidation:rule=`duration("0") <= self && self <= duration("60m")`
141+
//
142+
// +default="5s"
143+
// +optional
144+
CollectionInterval *Duration `json:"collectionInterval,omitempty"`
145+
}
146+
94147
// ---
95148
// Configuration for the OpenTelemetry Batch Processor
96149
// https://pkg.go.dev/go.opentelemetry.io/collector/processor/batchprocessor#section-readme

0 commit comments

Comments
 (0)