Skip to content

Commit e769e79

Browse files
committed
[Feature] Merge ArangoDB Usage Metrics
1 parent bc0c654 commit e769e79

13 files changed

+217
-47
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
- (Bugfix) Fix Image Error Propagation
99
- (Feature) JobScheduler Coverage
1010
- (Feature) JobScheduler Volumes, Probes, Lifecycle and Ports integration
11+
- (Feature) Merge ArangoDB Usage Metrics
1112

1213
## [1.2.38](https://github.com/arangodb/kube-arangodb/tree/1.2.38) (2024-02-22)
1314
- (Feature) Extract GRPC Server

cmd/exporter.go

+13-8
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
//
22
// DISCLAIMER
33
//
4-
// Copyright 2016-2022 ArangoDB GmbH, Cologne, Germany
4+
// Copyright 2016-2024 ArangoDB GmbH, Cologne, Germany
55
//
66
// Licensed under the Apache License, Version 2.0 (the "License");
77
// you may not use this file except in compliance with the License.
@@ -32,6 +32,7 @@ import (
3232

3333
"github.com/arangodb/kube-arangodb/pkg/exporter"
3434
"github.com/arangodb/kube-arangodb/pkg/util"
35+
"github.com/arangodb/kube-arangodb/pkg/util/errors"
3536
)
3637

3738
var (
@@ -43,9 +44,9 @@ var (
4344
exporterInput struct {
4445
listenAddress string
4546

46-
endpoint string
47-
jwtFile string
48-
timeout time.Duration
47+
endpoints []string
48+
jwtFile string
49+
timeout time.Duration
4950

5051
keyfile string
5152
}
@@ -57,7 +58,7 @@ func init() {
5758
f.StringVar(&exporterInput.listenAddress, "server.address", ":9101", "Address the exporter will listen on (IP:port)")
5859
f.StringVar(&exporterInput.keyfile, "ssl.keyfile", "", "File containing TLS certificate used for the metrics server. Format equal to ArangoDB keyfiles")
5960

60-
f.StringVar(&exporterInput.endpoint, "arangodb.endpoint", "http://127.0.0.1:8529", "Endpoint used to reach the ArangoDB server")
61+
f.StringSliceVar(&exporterInput.endpoints, "arangodb.endpoint", []string{"http://127.0.0.1:8529"}, "Endpoints used to reach the ArangoDB server")
6162
f.StringVar(&exporterInput.jwtFile, "arangodb.jwt-file", "", "File containing the JWT for authentication with ArangoDB server")
6263
f.DurationVar(&exporterInput.timeout, "arangodb.timeout", time.Second*15, "Timeout of statistics requests for ArangoDB")
6364

@@ -83,7 +84,11 @@ func onSigterm(f func()) {
8384
}
8485

8586
func cmdExporterCheckE() error {
86-
p, err := exporter.NewPassthru(exporterInput.endpoint, func() (string, error) {
87+
if len(exporterInput.endpoints) < 1 {
88+
return errors.Errorf("Requires at least one ArangoDB Endpoint to be present")
89+
}
90+
91+
p, err := exporter.NewPassthru(func() (string, error) {
8792
if exporterInput.jwtFile == "" {
8893
return "", nil
8994
}
@@ -94,12 +99,12 @@ func cmdExporterCheckE() error {
9499
}
95100

96101
return string(data), nil
97-
}, false, 15*time.Second)
102+
}, false, 15*time.Second, exporterInput.endpoints...)
98103
if err != nil {
99104
return err
100105
}
101106

102-
mon := exporter.NewMonitor(exporterInput.endpoint, func() (string, error) {
107+
mon := exporter.NewMonitor(exporterInput.endpoints[0], func() (string, error) {
103108
if exporterInput.jwtFile == "" {
104109
return "", nil
105110
}

pkg/apis/deployment/v1/deployment_metrics_spec.go

+11
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,9 @@ type MetricsSpec struct {
105105
ServiceMonitor *MetricsServiceMonitorSpec `json:"serviceMonitor,omitempty"`
106106

107107
Port *uint16 `json:"port,omitempty"`
108+
109+
// Extensions keeps the information about Metrics Extensions
110+
Extensions *MetricsSpecExtensions `json:"extensions,omitempty"`
108111
}
109112

110113
func (s *MetricsSpec) IsTLS() bool {
@@ -123,6 +126,14 @@ func (s *MetricsSpec) GetPort() uint16 {
123126
return *s.Port
124127
}
125128

129+
func (s *MetricsSpec) GetExtensions() *MetricsSpecExtensions {
130+
if s == nil || s.Extensions == nil {
131+
return nil
132+
}
133+
134+
return s.Extensions
135+
}
136+
126137
// IsEnabled returns whether metrics are enabled or not
127138
func (s *MetricsSpec) IsEnabled() bool {
128139
return util.TypeOrDefault[bool](s.Enabled, false)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
//
2+
// DISCLAIMER
3+
//
4+
// Copyright 2024 ArangoDB GmbH, Cologne, Germany
5+
//
6+
// Licensed under the Apache License, Version 2.0 (the "License");
7+
// you may not use this file except in compliance with the License.
8+
// You may obtain a copy of the License at
9+
//
10+
// http://www.apache.org/licenses/LICENSE-2.0
11+
//
12+
// Unless required by applicable law or agreed to in writing, software
13+
// distributed under the License is distributed on an "AS IS" BASIS,
14+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
// See the License for the specific language governing permissions and
16+
// limitations under the License.
17+
//
18+
// Copyright holder is ArangoDB GmbH, Cologne, Germany
19+
//
20+
21+
package v1
22+
23+
// MetricsSpecExtensions defines enabled extensions for MetricsExporter
24+
type MetricsSpecExtensions struct {
25+
// UsageMetrics enables ArangoDB Usage metrics scrape. Affects only DBServers in the Cluster mode.
26+
// +doc/default: false
27+
// +doc/link: Documentation:https://docs.arangodb.com/devel/develop/http-api/monitoring/metrics/#get-usage-metrics
28+
UsageMetrics *bool `json:"usageMetrics,omitempty"`
29+
}
30+
31+
func (m *MetricsSpecExtensions) GetUsageMetrics() bool {
32+
if m == nil || m.UsageMetrics == nil {
33+
return false
34+
}
35+
36+
return *m.UsageMetrics
37+
}

pkg/apis/deployment/v1/zz_generated.deepcopy.go

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

pkg/apis/shared/constants.go

+1
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ const (
3131
ArangoExporterClusterHealthEndpoint = "/_admin/cluster/health"
3232
ArangoExporterInternalEndpoint = "/_admin/metrics"
3333
ArangoExporterInternalEndpointV2 = "/_admin/metrics/v2"
34+
ArangoExporterUsageEndpoint = "/_admin/usage-metrics"
3435
ArangoExporterDefaultEndpoint = "/metrics"
3536

3637
ArangoSyncStatusEndpoint = "/_api/version"

pkg/deployment/resources/exporter.go

+8-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
//
2-
// Copyright 2016-2023 ArangoDB GmbH, Cologne, Germany
2+
// Copyright 2016-2024 ArangoDB GmbH, Cologne, Germany
33
//
44
// Licensed under the Apache License, Version 2.0 (the "License");
55
// you may not use this file except in compliance with the License.
@@ -30,7 +30,7 @@ import (
3030
"github.com/arangodb/kube-arangodb/pkg/util/k8sutil/probes"
3131
)
3232

33-
func createInternalExporterArgs(spec api.DeploymentSpec, groupSpec api.ServerGroupSpec, version driver.Version) []string {
33+
func createInternalExporterArgs(spec api.DeploymentSpec, group api.ServerGroup, groupSpec api.ServerGroupSpec, version driver.Version) []string {
3434
tokenpath := filepath.Join(shared.ExporterJWTVolumeMountDir, constants.SecretKeyToken)
3535
options := k8sutil.CreateOptionPairs(64)
3636

@@ -46,8 +46,14 @@ func createInternalExporterArgs(spec api.DeploymentSpec, groupSpec api.ServerGro
4646
scheme = "https"
4747
}
4848
options.Addf("--arangodb.endpoint", "%s://localhost:%d%s", scheme, groupSpec.GetPort(), path)
49+
if spec.Metrics.GetExtensions().GetUsageMetrics() && group == api.ServerGroupDBServers {
50+
options.Addf("--arangodb.endpoint", "%s://localhost:%d%s", scheme, groupSpec.GetPort(), shared.ArangoExporterUsageEndpoint)
51+
}
4952
} else {
5053
options.Addf("--arangodb.endpoint", "http://localhost:%d%s", *port, path)
54+
if spec.Metrics.GetExtensions().GetUsageMetrics() && group == api.ServerGroupDBServers {
55+
options.Addf("--arangodb.endpoint", "http://localhost:%d%s", groupSpec.GetPort(), shared.ArangoExporterUsageEndpoint)
56+
}
5157
}
5258

5359
keyPath := filepath.Join(shared.TLSKeyfileVolumeMountDir, constants.SecretTLSKeyfile)

pkg/deployment/resources/internal_exporter.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
//
2-
// Copyright 2016-2023 ArangoDB GmbH, Cologne, Germany
2+
// Copyright 2016-2024 ArangoDB GmbH, Cologne, Germany
33
//
44
// Licensed under the Apache License, Version 2.0 (the "License");
55
// you may not use this file except in compliance with the License.
@@ -50,7 +50,7 @@ func ArangodbInternalExporterContainer(image string, args []string, livenessProb
5050
Command: append([]string{exePath, "exporter"}, args...),
5151
Ports: []core.ContainerPort{
5252
{
53-
Name: "exporter",
53+
Name: shared.ExporterContainerName,
5454
ContainerPort: int32(port),
5555
Protocol: core.ProtocolTCP,
5656
},

pkg/deployment/resources/pod_creator_arangod.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -561,7 +561,7 @@ func (m *MemberArangoDPod) GetRestartPolicy() core.RestartPolicy {
561561
func (m *MemberArangoDPod) createMetricsExporterSidecarInternalExporter() (*core.Container, error) {
562562
image := m.GetContainerCreator().GetImage()
563563

564-
args := createInternalExporterArgs(m.spec, m.groupSpec, m.imageInfo.ArangoDBVersion)
564+
args := createInternalExporterArgs(m.spec, m.group, m.groupSpec, m.imageInfo.ArangoDBVersion)
565565

566566
c, err := ArangodbInternalExporterContainer(image, args,
567567
createExporterLivenessProbe(m.spec.IsSecure() && m.spec.Metrics.IsTLS()), m.spec.Metrics.Resources,

pkg/deployment/resources/secrets.go

+14-2
Original file line numberDiff line numberDiff line change
@@ -426,8 +426,11 @@ var (
426426
token.ClaimISS: token.ClaimISSValue,
427427
"server_id": "exporter",
428428
"allowed_paths": []interface{}{"/_admin/statistics", "/_admin/statistics-description",
429-
shared.ArangoExporterInternalEndpoint, shared.ArangoExporterInternalEndpointV2,
430-
shared.ArangoExporterStatusEndpoint, shared.ArangoExporterClusterHealthEndpoint},
429+
shared.ArangoExporterInternalEndpoint,
430+
shared.ArangoExporterInternalEndpointV2,
431+
shared.ArangoExporterUsageEndpoint,
432+
shared.ArangoExporterStatusEndpoint,
433+
shared.ArangoExporterClusterHealthEndpoint},
431434
}
432435
)
433436

@@ -449,6 +452,15 @@ func (r *Resources) ensureExporterTokenSecret(ctx context.Context, cachedStatus
449452
// Failed to create secret
450453
return errors.WithStack(err)
451454
}
455+
} else {
456+
err = k8sutil.UpdateJWTFromSecret(ctx, cachedStatus.Secret().V1().Read(), secrets, tokenSecretName, secretSecretName, exporterTokenClaims)
457+
if kerrors.IsAlreadyExists(err) {
458+
// Secret added while we tried it also
459+
return nil
460+
} else if err != nil {
461+
// Failed to create secret
462+
return errors.WithStack(err)
463+
}
452464
}
453465

454466
return errors.Reconcile()

pkg/exporter/monitor.go

+6-4
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ import (
4242
)
4343

4444
const (
45-
monitorMetricTemplate = "arangodb_member_health{role=\"%s\",id=\"%s\"} %d \n"
45+
monitorMetricTemplate = "arangodb_member_health{role=\"%s\",id=\"%s\"} %d\n"
4646
successRefreshInterval = time.Second * 120
4747
failRefreshInterval = time.Second * 15
4848
)
@@ -59,14 +59,16 @@ func NewMonitor(arangodbEndpoint string, auth Authentication, sslVerify bool, ti
5959
}
6060

6161
return &monitor{
62-
factory: newHttpClientFactory(arangodbEndpoint, auth, sslVerify, timeout),
62+
factory: newHttpClientFactory(auth, sslVerify, timeout),
63+
endpoint: arangodbEndpoint,
6364
healthURI: uri,
6465
}
6566
}
6667

6768
type monitor struct {
6869
factory httpClientFactory
6970
healthURI *url.URL
71+
endpoint string
7072
}
7173

7274
// UpdateMonitorStatus load monitor metrics for current cluster into currentMembersStatus
@@ -102,7 +104,7 @@ func (m monitor) UpdateMonitorStatus(ctx context.Context) {
102104

103105
// GetClusterHealth returns current ArangoDeployment cluster health status
104106
func (m monitor) GetClusterHealth() (*driver.ClusterHealth, error) {
105-
c, req, err := m.factory()
107+
c, req, err := m.factory(m.endpoint)
106108
if err != nil {
107109
return nil, err
108110
}
@@ -130,7 +132,7 @@ func (m monitor) GetClusterHealth() (*driver.ClusterHealth, error) {
130132
func (m monitor) GetMemberStatus(id driver.ServerID, member driver.ServerHealth) (string, error) {
131133
result := fmt.Sprintf(monitorMetricTemplate, member.Role, id, 0)
132134

133-
c, req, err := m.factory()
135+
c, req, err := m.factory(m.endpoint)
134136
if err != nil {
135137
return result, err
136138
}

0 commit comments

Comments
 (0)