1
0
Fork 0
mirror of https://github.com/arangodb/kube-arangodb.git synced 2024-12-14 11:57:37 +00:00

[Feature] Add Kubernetes Client logger (#1235)

This commit is contained in:
Adam Janikowski 2023-01-26 18:12:33 +01:00 committed by GitHub
parent c4899de084
commit c9d3827c5a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
25 changed files with 731 additions and 52 deletions

View file

@ -2,6 +2,7 @@
## [master](https://github.com/arangodb/kube-arangodb/tree/master) (N/A)
- (Feature) Add Generics & Drop policy/v1beta1 support
- (Feature) Add Kubernetes Client logger
## [1.2.24](https://github.com/arangodb/kube-arangodb/tree/1.2.24) (2023-01-25)
- (Bugfix) Fix deployment creation on ARM64

View file

@ -2,29 +2,31 @@
## List
| Name | Namespace | Group | Type | Description |
|:-------------------------------------------------------------------------------------------------------------------------------------:|:-----------------:|:------------:|:-------:|:--------------------------------------------------------------------------------------|
| [arangodb_operator_agency_errors](./arangodb_operator_agency_errors.md) | arangodb_operator | agency | Counter | Current count of agency cache fetch errors |
| [arangodb_operator_agency_fetches](./arangodb_operator_agency_fetches.md) | arangodb_operator | agency | Counter | Current count of agency cache fetches |
| [arangodb_operator_agency_index](./arangodb_operator_agency_index.md) | arangodb_operator | agency | Gauge | Current index of the agency cache |
| [arangodb_operator_agency_cache_health_present](./arangodb_operator_agency_cache_health_present.md) | arangodb_operator | agency_cache | Gauge | Determines if local agency cache health is present |
| [arangodb_operator_agency_cache_healthy](./arangodb_operator_agency_cache_healthy.md) | arangodb_operator | agency_cache | Gauge | Determines if agency is healthy |
| [arangodb_operator_agency_cache_leaders](./arangodb_operator_agency_cache_leaders.md) | arangodb_operator | agency_cache | Gauge | Determines agency leader vote count |
| [arangodb_operator_agency_cache_member_commit_offset](./arangodb_operator_agency_cache_member_commit_offset.md) | arangodb_operator | agency_cache | Gauge | Determines agency member commit offset |
| [arangodb_operator_agency_cache_member_serving](./arangodb_operator_agency_cache_member_serving.md) | arangodb_operator | agency_cache | Gauge | Determines if agency member is reachable |
| [arangodb_operator_agency_cache_present](./arangodb_operator_agency_cache_present.md) | arangodb_operator | agency_cache | Gauge | Determines if local agency cache is present |
| [arangodb_operator_agency_cache_serving](./arangodb_operator_agency_cache_serving.md) | arangodb_operator | agency_cache | Gauge | Determines if agency is serving |
| [arangodb_operator_engine_ops_alerts](./arangodb_operator_engine_ops_alerts.md) | arangodb_operator | engine | Counter | Counter for actions which requires ops attention |
| [arangodb_operator_engine_panics_recovered](./arangodb_operator_engine_panics_recovered.md) | arangodb_operator | engine | Counter | Number of Panics recovered inside Operator reconciliation loop |
| [arangodb_operator_members_unexpected_container_exit_codes](./arangodb_operator_members_unexpected_container_exit_codes.md) | arangodb_operator | members | Counter | Counter of unexpected restarts in pod (Containers/InitContainers/EphemeralContainers) |
| [arangodb_operator_rebalancer_enabled](./arangodb_operator_rebalancer_enabled.md) | arangodb_operator | rebalancer | Gauge | Determines if rebalancer is enabled |
| [arangodb_operator_rebalancer_moves_current](./arangodb_operator_rebalancer_moves_current.md) | arangodb_operator | rebalancer | Gauge | Define how many moves are currently in progress |
| [arangodb_operator_rebalancer_moves_failed](./arangodb_operator_rebalancer_moves_failed.md) | arangodb_operator | rebalancer | Counter | Define how many moves failed |
| [arangodb_operator_rebalancer_moves_generated](./arangodb_operator_rebalancer_moves_generated.md) | arangodb_operator | rebalancer | Counter | Define how many moves were generated |
| [arangodb_operator_rebalancer_moves_succeeded](./arangodb_operator_rebalancer_moves_succeeded.md) | arangodb_operator | rebalancer | Counter | Define how many moves succeeded |
| [arangodb_operator_resources_arangodeployment_accepted](./arangodb_operator_resources_arangodeployment_accepted.md) | arangodb_operator | resources | Gauge | Defines if ArangoDeployment has been accepted |
| [arangodb_operator_resources_arangodeployment_immutable_errors](./arangodb_operator_resources_arangodeployment_immutable_errors.md) | arangodb_operator | resources | Counter | Counter for deployment immutable errors |
| [arangodb_operator_resources_arangodeployment_propagated](./arangodb_operator_resources_arangodeployment_propagated.md) | arangodb_operator | resources | Gauge | Defines if ArangoDeployment Spec is propagated |
| [arangodb_operator_resources_arangodeployment_status_restores](./arangodb_operator_resources_arangodeployment_status_restores.md) | arangodb_operator | resources | Counter | Counter for deployment status restored |
| [arangodb_operator_resources_arangodeployment_uptodate](./arangodb_operator_resources_arangodeployment_uptodate.md) | arangodb_operator | resources | Gauge | Defines if ArangoDeployment is uptodate |
| [arangodb_operator_resources_arangodeployment_validation_errors](./arangodb_operator_resources_arangodeployment_validation_errors.md) | arangodb_operator | resources | Counter | Counter for deployment validation errors |
| Name | Namespace | Group | Type | Description |
|:-------------------------------------------------------------------------------------------------------------------------------------:|:-----------------:|:-----------------:|:-------:|:--------------------------------------------------------------------------------------|
| [arangodb_operator_agency_errors](./arangodb_operator_agency_errors.md) | arangodb_operator | agency | Counter | Current count of agency cache fetch errors |
| [arangodb_operator_agency_fetches](./arangodb_operator_agency_fetches.md) | arangodb_operator | agency | Counter | Current count of agency cache fetches |
| [arangodb_operator_agency_index](./arangodb_operator_agency_index.md) | arangodb_operator | agency | Gauge | Current index of the agency cache |
| [arangodb_operator_agency_cache_health_present](./arangodb_operator_agency_cache_health_present.md) | arangodb_operator | agency_cache | Gauge | Determines if local agency cache health is present |
| [arangodb_operator_agency_cache_healthy](./arangodb_operator_agency_cache_healthy.md) | arangodb_operator | agency_cache | Gauge | Determines if agency is healthy |
| [arangodb_operator_agency_cache_leaders](./arangodb_operator_agency_cache_leaders.md) | arangodb_operator | agency_cache | Gauge | Determines agency leader vote count |
| [arangodb_operator_agency_cache_member_commit_offset](./arangodb_operator_agency_cache_member_commit_offset.md) | arangodb_operator | agency_cache | Gauge | Determines agency member commit offset |
| [arangodb_operator_agency_cache_member_serving](./arangodb_operator_agency_cache_member_serving.md) | arangodb_operator | agency_cache | Gauge | Determines if agency member is reachable |
| [arangodb_operator_agency_cache_present](./arangodb_operator_agency_cache_present.md) | arangodb_operator | agency_cache | Gauge | Determines if local agency cache is present |
| [arangodb_operator_agency_cache_serving](./arangodb_operator_agency_cache_serving.md) | arangodb_operator | agency_cache | Gauge | Determines if agency is serving |
| [arangodb_operator_engine_ops_alerts](./arangodb_operator_engine_ops_alerts.md) | arangodb_operator | engine | Counter | Counter for actions which requires ops attention |
| [arangodb_operator_engine_panics_recovered](./arangodb_operator_engine_panics_recovered.md) | arangodb_operator | engine | Counter | Number of Panics recovered inside Operator reconciliation loop |
| [arangodb_operator_kubernetes_client_request_errors](./arangodb_operator_kubernetes_client_request_errors.md) | arangodb_operator | kubernetes_client | Counter | Number of Kubernetes Client request errors |
| [arangodb_operator_kubernetes_client_requests](./arangodb_operator_kubernetes_client_requests.md) | arangodb_operator | kubernetes_client | Counter | Number of Kubernetes Client requests |
| [arangodb_operator_members_unexpected_container_exit_codes](./arangodb_operator_members_unexpected_container_exit_codes.md) | arangodb_operator | members | Counter | Counter of unexpected restarts in pod (Containers/InitContainers/EphemeralContainers) |
| [arangodb_operator_rebalancer_enabled](./arangodb_operator_rebalancer_enabled.md) | arangodb_operator | rebalancer | Gauge | Determines if rebalancer is enabled |
| [arangodb_operator_rebalancer_moves_current](./arangodb_operator_rebalancer_moves_current.md) | arangodb_operator | rebalancer | Gauge | Define how many moves are currently in progress |
| [arangodb_operator_rebalancer_moves_failed](./arangodb_operator_rebalancer_moves_failed.md) | arangodb_operator | rebalancer | Counter | Define how many moves failed |
| [arangodb_operator_rebalancer_moves_generated](./arangodb_operator_rebalancer_moves_generated.md) | arangodb_operator | rebalancer | Counter | Define how many moves were generated |
| [arangodb_operator_rebalancer_moves_succeeded](./arangodb_operator_rebalancer_moves_succeeded.md) | arangodb_operator | rebalancer | Counter | Define how many moves succeeded |
| [arangodb_operator_resources_arangodeployment_accepted](./arangodb_operator_resources_arangodeployment_accepted.md) | arangodb_operator | resources | Gauge | Defines if ArangoDeployment has been accepted |
| [arangodb_operator_resources_arangodeployment_immutable_errors](./arangodb_operator_resources_arangodeployment_immutable_errors.md) | arangodb_operator | resources | Counter | Counter for deployment immutable errors |
| [arangodb_operator_resources_arangodeployment_propagated](./arangodb_operator_resources_arangodeployment_propagated.md) | arangodb_operator | resources | Gauge | Defines if ArangoDeployment Spec is propagated |
| [arangodb_operator_resources_arangodeployment_status_restores](./arangodb_operator_resources_arangodeployment_status_restores.md) | arangodb_operator | resources | Counter | Counter for deployment status restored |
| [arangodb_operator_resources_arangodeployment_uptodate](./arangodb_operator_resources_arangodeployment_uptodate.md) | arangodb_operator | resources | Gauge | Defines if ArangoDeployment is uptodate |
| [arangodb_operator_resources_arangodeployment_validation_errors](./arangodb_operator_resources_arangodeployment_validation_errors.md) | arangodb_operator | resources | Counter | Counter for deployment validation errors |

View file

@ -0,0 +1,12 @@
# arangodb_operator_kubernetes_client_request_errors (Counter)
## Description
Number of Kubernetes Client request errors
## Labels
| Label | Description |
|:---------:|:-------------------------------------------------------------|
| component | K8S Resource name |
| verb | Verb (create,update,update-status,patch,delete,force-delete) |

View file

@ -0,0 +1,12 @@
# arangodb_operator_kubernetes_client_requests (Counter)
## Description
Number of Kubernetes Client requests
## Labels
| Label | Description |
|:---------:|:-------------------------------------------------------------|
| component | K8S Resource name |
| verb | Verb (create,update,update-status,patch,delete,force-delete) |

View file

@ -243,5 +243,22 @@ namespaces:
- priority: Warning
query: irate(arangodb_operator_engine_ops_alerts[1m]) > 1
description: "Trigger an alert if OPS attention is needed"
kubernetes_client:
requests:
shortDescription: "Number of Kubernetes Client requests"
description: "Number of Kubernetes Client requests"
type: "Counter"
labels:
- key: component
description: "K8S Resource name"
- key: verb
description: "Verb (create,update,update-status,patch,delete,force-delete)"
request_errors:
shortDescription: "Number of Kubernetes Client request errors"
description: "Number of Kubernetes Client request errors"
type: "Counter"
labels:
- key: component
description: "K8S Resource name"
- key: verb
description: "Verb (create,update,update-status,patch,delete,force-delete)"

View file

@ -39,7 +39,7 @@ type arangoClusterSynchronizationMod struct {
}
func (p arangoClusterSynchronizationMod) V1() arangoclustersynchronizationv1.ModInterface {
return generic.NewModThrottle[*api.ArangoClusterSynchronization](definitions.ArangoClusterSynchronization, p.i.GetThrottles, p.clientv1)
return wrapMod[*api.ArangoClusterSynchronization](definitions.ArangoClusterSynchronization, p.i.GetThrottles, p.clientv1)
}
func (p arangoClusterSynchronizationMod) clientv1() generic.ModStatusClient[*api.ArangoClusterSynchronization] {

View file

@ -39,7 +39,7 @@ type arangoMemberMod struct {
}
func (p arangoMemberMod) V1() arangomemberv1.ModInterface {
return generic.NewModThrottle[*api.ArangoMember](definitions.ArangoMember, p.i.GetThrottles, p.clientv1)
return wrapMod[*api.ArangoMember](definitions.ArangoMember, p.i.GetThrottles, p.clientv1)
}
func (p arangoMemberMod) clientv1() generic.ModStatusClient[*api.ArangoMember] {

View file

@ -39,7 +39,7 @@ type arangoTaskMod struct {
}
func (p arangoTaskMod) V1() arangotaskv1.ModInterface {
return generic.NewModThrottle[*api.ArangoTask](definitions.ArangoTask, p.i.GetThrottles, p.clientv1)
return wrapMod[*api.ArangoTask](definitions.ArangoTask, p.i.GetThrottles, p.clientv1)
}
func (p arangoTaskMod) clientv1() generic.ModStatusClient[*api.ArangoTask] {

View file

@ -41,7 +41,7 @@ type endpointsMod struct {
}
func (p endpointsMod) V1() endpointsv1.ModInterface {
return generic.NewModThrottle[*core.Endpoints](definitions.Endpoints, p.i.GetThrottles, generic.WithModStatusGetter[*core.Endpoints](constants.EndpointsGKv1(), p.clientv1))
return wrapMod[*core.Endpoints](definitions.Endpoints, p.i.GetThrottles, generic.WithModStatusGetter[*core.Endpoints](constants.EndpointsGKv1(), p.clientv1))
}
func (p endpointsMod) clientv1() generic.ModClient[*core.Endpoints] {

View file

@ -1,7 +1,7 @@
//
// DISCLAIMER
//
// Copyright 2016-2022 ArangoDB GmbH, Cologne, Germany
// Copyright 2016-2023 ArangoDB GmbH, Cologne, Germany
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -61,12 +61,9 @@ const (
DefaultVersion = ""
)
func init() {
logging.Global().RegisterLogger("inspector", logging.Info)
}
var (
logger = logging.Global().Get("inspector")
logger = logging.Global().RegisterAndGetLogger("inspector", logging.Info)
clientLogger = logging.Global().RegisterAndGetLogger("k8s-client", logging.Info)
)
func (i inspectorLoaders) Get(name string) int {

View file

@ -0,0 +1,130 @@
//
// DISCLAIMER
//
// Copyright 2023 ArangoDB GmbH, Cologne, Germany
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Copyright holder is ArangoDB GmbH, Cologne, Germany
//
package inspector
import (
"reflect"
"sync"
meta "k8s.io/apimachinery/pkg/apis/meta/v1"
"github.com/arangodb/kube-arangodb/pkg/generated/metric_descriptions"
"github.com/arangodb/kube-arangodb/pkg/metrics/collector"
"github.com/arangodb/kube-arangodb/pkg/util/k8sutil/inspector/definitions"
"github.com/arangodb/kube-arangodb/pkg/util/metrics"
)
func init() {
collector.GetCollector().RegisterMetric(clientMetricsInstance)
}
var (
clientMetricsInstance = &clientMetrics{}
)
type clientMetricsFields struct {
calls int
errors int
}
type clientMetrics struct {
lock sync.Mutex
metrics map[definitions.Component]map[definitions.Verb]clientMetricsFields
}
func (c *clientMetrics) reset() {
c.lock.Lock()
defer c.lock.Unlock()
c.metrics = nil
}
func (c *clientMetrics) CollectMetrics(in metrics.PushMetric) {
c.lock.Lock()
defer c.lock.Unlock()
for component, verbs := range c.metrics {
for verb, fields := range verbs {
in.Push(
metric_descriptions.ArangodbOperatorKubernetesClientRequestsCounter(float64(fields.calls), string(component), string(verb)),
metric_descriptions.ArangodbOperatorKubernetesClientRequestErrorsCounter(float64(fields.errors), string(component), string(verb)),
)
}
}
}
func (c *clientMetrics) ObjectRequest(definition definitions.Component, verb definitions.Verb, object meta.Object, err error) {
if object == nil || (reflect.ValueOf(object).Kind() == reflect.Ptr && reflect.ValueOf(object).IsNil()) {
return
}
c.Request(definition, verb, object.GetName(), err)
}
func (c *clientMetrics) Request(definition definitions.Component, verb definitions.Verb, name string, err error) {
c.lock.Lock()
defer c.lock.Unlock()
if c.metrics == nil {
c.metrics = map[definitions.Component]map[definitions.Verb]clientMetricsFields{}
}
if _, ok := c.metrics[definition]; !ok {
c.metrics[definition] = map[definitions.Verb]clientMetricsFields{}
}
if _, ok := c.metrics[definition][verb]; !ok {
c.metrics[definition][verb] = clientMetricsFields{}
}
f := c.metrics[definition][verb]
f.calls++
if err != nil {
f.errors++
}
c.metrics[definition][verb] = f
// Logging
log := clientLogger.Str("name", name).Str("kind", string(definition)).Str("verb", string(verb)).Err(err)
if err == nil {
call := log.Debug
switch verb {
case definitions.Get:
call = log.Trace
case definitions.Update, definitions.UpdateStatus, definitions.Patch:
call = log.Debug
case definitions.Create, definitions.Delete:
call = log.Info
case definitions.ForceDelete:
call = log.Warn
}
call("Kubernetes request has been send")
} else {
log.Warn("Kubernetes request failed")
}
}

View file

@ -0,0 +1,80 @@
//
// DISCLAIMER
//
// Copyright 2023 ArangoDB GmbH, Cologne, Germany
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Copyright holder is ArangoDB GmbH, Cologne, Germany
//
package inspector
import (
"context"
meta "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
"github.com/arangodb/kube-arangodb/pkg/util/k8sutil/inspector/definitions"
"github.com/arangodb/kube-arangodb/pkg/util/k8sutil/inspector/generic"
)
func withMetrics[S meta.Object](definition definitions.Component, in generic.ClientStatusGetter[S]) generic.ClientStatusGetter[S] {
return func() generic.ModStatusClient[S] {
return statusClientMetrics[S]{
component: definition,
in: in(),
}
}
}
type statusClientMetrics[S meta.Object] struct {
component definitions.Component
in generic.ModStatusClient[S]
}
func (s statusClientMetrics[S]) Create(ctx context.Context, obj S, opts meta.CreateOptions) (S, error) {
r, err := s.in.Create(ctx, obj, opts)
clientMetricsInstance.ObjectRequest(s.component, definitions.Create, obj, err)
return r, err
}
func (s statusClientMetrics[S]) Update(ctx context.Context, obj S, opts meta.UpdateOptions) (S, error) {
r, err := s.in.Update(ctx, obj, opts)
clientMetricsInstance.ObjectRequest(s.component, definitions.Update, obj, err)
return r, err
}
func (s statusClientMetrics[S]) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts meta.PatchOptions, subresources ...string) (result S, err error) {
r, err := s.in.Patch(ctx, name, pt, data, opts, subresources...)
clientMetricsInstance.Request(s.component, definitions.Patch, name, err)
return r, err
}
func (s statusClientMetrics[S]) Delete(ctx context.Context, name string, opts meta.DeleteOptions) error {
verb := definitions.Delete
if g := opts.GracePeriodSeconds; g != nil && *g == 0 {
verb = definitions.ForceDelete
}
err := s.in.Delete(ctx, name, opts)
clientMetricsInstance.Request(s.component, verb, name, err)
return err
}
func (s statusClientMetrics[S]) UpdateStatus(ctx context.Context, obj S, opts meta.UpdateOptions) (S, error) {
r, err := s.in.UpdateStatus(ctx, obj, opts)
clientMetricsInstance.ObjectRequest(s.component, definitions.UpdateStatus, obj, err)
return r, err
}

View file

@ -0,0 +1,313 @@
//
// DISCLAIMER
//
// Copyright 2023 ArangoDB GmbH, Cologne, Germany
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Copyright holder is ArangoDB GmbH, Cologne, Germany
//
package inspector
import (
"context"
"testing"
monitoring "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1"
"github.com/stretchr/testify/require"
core "k8s.io/api/core/v1"
meta "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
api "github.com/arangodb/kube-arangodb/pkg/apis/deployment/v1"
"github.com/arangodb/kube-arangodb/pkg/deployment/patch"
"github.com/arangodb/kube-arangodb/pkg/util"
"github.com/arangodb/kube-arangodb/pkg/util/k8sutil/inspector/definitions"
"github.com/arangodb/kube-arangodb/pkg/util/k8sutil/inspector/generic"
"github.com/arangodb/kube-arangodb/pkg/util/k8sutil/inspector/throttle"
"github.com/arangodb/kube-arangodb/pkg/util/kclient"
)
func extractMetric(t *testing.T, definition definitions.Component, verb definitions.Verb) clientMetricsFields {
defer clientMetricsInstance.reset()
if m := clientMetricsInstance.metrics; m != nil {
if a, ok := m[definition]; ok {
if b, ok := a[verb]; ok {
return b
}
}
}
require.Fail(t, "Metric not found")
return clientMetricsFields{}
}
func testModClientMetrics[S meta.Object](t *testing.T, definition definitions.Component, in generic.ModClient[S], generator func(name string) S) {
t.Run("Create with collision", func(t *testing.T) {
obj := generator("test")
t.Run("Create", func(t *testing.T) {
_, err := in.Create(context.Background(), obj, meta.CreateOptions{})
require.NoError(t, err)
f := extractMetric(t, definition, definitions.Create)
require.Equal(t, 1, f.calls)
require.Equal(t, 0, f.errors)
})
t.Run("Recreate", func(t *testing.T) {
_, err := in.Create(context.Background(), obj, meta.CreateOptions{})
require.Error(t, err)
f := extractMetric(t, definition, definitions.Create)
require.Equal(t, 1, f.calls)
require.Equal(t, 1, f.errors)
})
t.Run("Update", func(t *testing.T) {
_, err := in.Update(context.Background(), obj, meta.UpdateOptions{})
require.NoError(t, err)
f := extractMetric(t, definition, definitions.Update)
require.Equal(t, 1, f.calls)
require.Equal(t, 0, f.errors)
})
t.Run("Update Missing", func(t *testing.T) {
obj := generator("test2")
_, err := in.Update(context.Background(), obj, meta.UpdateOptions{})
require.Error(t, err)
f := extractMetric(t, definition, definitions.Update)
require.Equal(t, 1, f.calls)
require.Equal(t, 1, f.errors)
})
if us, ok := in.(generic.ModStatusClient[S]); ok {
_, err := us.UpdateStatus(context.Background(), obj, meta.UpdateOptions{})
extractMetric(t, definition, definitions.UpdateStatus)
if err == nil {
t.Run("UpdateStatus", func(t *testing.T) {
_, err := us.UpdateStatus(context.Background(), obj, meta.UpdateOptions{})
require.NoError(t, err)
f := extractMetric(t, definition, definitions.UpdateStatus)
require.Equal(t, 1, f.calls)
require.Equal(t, 0, f.errors)
})
t.Run("UpdateStatus Missing", func(t *testing.T) {
obj := generator("test2")
_, err := us.UpdateStatus(context.Background(), obj, meta.UpdateOptions{})
require.Error(t, err)
f := extractMetric(t, definition, definitions.UpdateStatus)
require.Equal(t, 1, f.calls)
require.Equal(t, 1, f.errors)
})
}
}
t.Run("Patch", func(t *testing.T) {
p, err := patch.NewPatch(patch.ItemReplace(patch.NewPath("metadata", "labels"), map[string]string{})).Marshal()
require.NoError(t, err)
_, err = in.Patch(context.Background(), obj.GetName(), types.JSONPatchType, p, meta.PatchOptions{})
require.NoError(t, err)
f := extractMetric(t, definition, definitions.Patch)
require.Equal(t, 1, f.calls)
require.Equal(t, 0, f.errors)
})
t.Run("Patch Missing", func(t *testing.T) {
obj := generator("test2")
p, err := patch.NewPatch(patch.ItemReplace(patch.NewPath("metadata", "labels"), map[string]string{})).Marshal()
require.NoError(t, err)
_, err = in.Patch(context.Background(), obj.GetName(), types.JSONPatchType, p, meta.PatchOptions{})
require.Error(t, err)
f := extractMetric(t, definition, definitions.Patch)
require.Equal(t, 1, f.calls)
require.Equal(t, 1, f.errors)
})
t.Run("Delete", func(t *testing.T) {
err := in.Delete(context.Background(), obj.GetName(), meta.DeleteOptions{})
require.NoError(t, err)
f := extractMetric(t, definition, definitions.Delete)
require.Equal(t, 1, f.calls)
require.Equal(t, 0, f.errors)
})
t.Run("Delete - missing", func(t *testing.T) {
err := in.Delete(context.Background(), obj.GetName(), meta.DeleteOptions{})
require.Error(t, err)
f := extractMetric(t, definition, definitions.Delete)
require.Equal(t, 1, f.calls)
require.Equal(t, 1, f.errors)
})
t.Run("Create for deletion", func(t *testing.T) {
_, err := in.Create(context.Background(), obj, meta.CreateOptions{})
require.NoError(t, err)
f := extractMetric(t, definition, definitions.Create)
require.Equal(t, 1, f.calls)
require.Equal(t, 0, f.errors)
})
t.Run("ForceDelete", func(t *testing.T) {
err := in.Delete(context.Background(), obj.GetName(), meta.DeleteOptions{
GracePeriodSeconds: util.NewInt64(0),
})
require.NoError(t, err)
f := extractMetric(t, definition, definitions.ForceDelete)
require.Equal(t, 1, f.calls)
require.Equal(t, 0, f.errors)
})
t.Run("ForceDelete - missing", func(t *testing.T) {
err := in.Delete(context.Background(), obj.GetName(), meta.DeleteOptions{
GracePeriodSeconds: util.NewInt64(0),
})
require.Error(t, err)
f := extractMetric(t, definition, definitions.ForceDelete)
require.Equal(t, 1, f.calls)
require.Equal(t, 1, f.errors)
})
})
}
func Test_Metrics(t *testing.T) {
c := kclient.NewFakeClient()
q := NewInspector(throttle.NewAlwaysThrottleComponents(), c, "test", "test")
t.Run(string(definitions.ArangoMember), func(t *testing.T) {
testModClientMetrics[*api.ArangoMember](t, definitions.ArangoMember, q.ArangoMemberModInterface().V1(), func(name string) *api.ArangoMember {
return &api.ArangoMember{
ObjectMeta: meta.ObjectMeta{
Name: name,
Namespace: "test",
},
}
})
})
t.Run(string(definitions.ArangoTask), func(t *testing.T) {
testModClientMetrics[*api.ArangoTask](t, definitions.ArangoTask, q.ArangoTaskModInterface().V1(), func(name string) *api.ArangoTask {
return &api.ArangoTask{
ObjectMeta: meta.ObjectMeta{
Name: name,
Namespace: "test",
},
}
})
})
t.Run(string(definitions.ArangoClusterSynchronization), func(t *testing.T) {
testModClientMetrics[*api.ArangoClusterSynchronization](t, definitions.ArangoClusterSynchronization, q.ArangoClusterSynchronizationModInterface().V1(), func(name string) *api.ArangoClusterSynchronization {
return &api.ArangoClusterSynchronization{
ObjectMeta: meta.ObjectMeta{
Name: name,
Namespace: "test",
},
}
})
})
t.Run(string(definitions.Pod), func(t *testing.T) {
testModClientMetrics[*core.Pod](t, definitions.Pod, q.PodsModInterface().V1(), func(name string) *core.Pod {
return &core.Pod{
ObjectMeta: meta.ObjectMeta{
Name: name,
Namespace: "test",
},
}
})
})
t.Run(string(definitions.PersistentVolumeClaim), func(t *testing.T) {
testModClientMetrics[*core.PersistentVolumeClaim](t, definitions.PersistentVolumeClaim, q.PersistentVolumeClaimsModInterface().V1(), func(name string) *core.PersistentVolumeClaim {
return &core.PersistentVolumeClaim{
ObjectMeta: meta.ObjectMeta{
Name: name,
Namespace: "test",
},
}
})
})
t.Run(string(definitions.Secret), func(t *testing.T) {
testModClientMetrics[*core.Secret](t, definitions.Secret, q.SecretsModInterface().V1(), func(name string) *core.Secret {
return &core.Secret{
ObjectMeta: meta.ObjectMeta{
Name: name,
Namespace: "test",
},
}
})
})
t.Run(string(definitions.Service), func(t *testing.T) {
testModClientMetrics[*core.Service](t, definitions.Service, q.ServicesModInterface().V1(), func(name string) *core.Service {
return &core.Service{
ObjectMeta: meta.ObjectMeta{
Name: name,
Namespace: "test",
},
}
})
})
t.Run(string(definitions.ServiceAccount), func(t *testing.T) {
testModClientMetrics[*core.ServiceAccount](t, definitions.ServiceAccount, q.ServiceAccountsModInterface().V1(), func(name string) *core.ServiceAccount {
return &core.ServiceAccount{
ObjectMeta: meta.ObjectMeta{
Name: name,
Namespace: "test",
},
}
})
})
t.Run(string(definitions.Endpoints), func(t *testing.T) {
testModClientMetrics[*core.Endpoints](t, definitions.Endpoints, q.EndpointsModInterface().V1(), func(name string) *core.Endpoints {
return &core.Endpoints{
ObjectMeta: meta.ObjectMeta{
Name: name,
Namespace: "test",
},
}
})
})
t.Run(string(definitions.ServiceMonitor), func(t *testing.T) {
testModClientMetrics[*monitoring.ServiceMonitor](t, definitions.ServiceMonitor, q.ServiceMonitorsModInterface().V1(), func(name string) *monitoring.ServiceMonitor {
return &monitoring.ServiceMonitor{
ObjectMeta: meta.ObjectMeta{
Name: name,
Namespace: "test",
},
}
})
})
}

View file

@ -41,7 +41,7 @@ type podDisruptionBudgetsMod struct {
}
func (p podDisruptionBudgetsMod) V1() policyv1.ModInterface {
return generic.NewModThrottle[*policy.PodDisruptionBudget](definitions.PodDisruptionBudget, p.i.GetThrottles, generic.WithModStatusGetter[*policy.PodDisruptionBudget](constants.PodDisruptionBudgetGKv1(), p.clientv1))
return wrapMod[*policy.PodDisruptionBudget](definitions.PodDisruptionBudget, p.i.GetThrottles, generic.WithModStatusGetter[*policy.PodDisruptionBudget](constants.PodDisruptionBudgetGKv1(), p.clientv1))
}
func (p podDisruptionBudgetsMod) clientv1() generic.ModClient[*policy.PodDisruptionBudget] {

View file

@ -41,7 +41,7 @@ type podsMod struct {
}
func (p podsMod) V1() podv1.ModInterface {
return generic.NewModThrottle[*core.Pod](definitions.Endpoints, p.i.GetThrottles, generic.WithModStatusGetter[*core.Pod](constants.PodGKv1(), p.clientv1))
return wrapMod[*core.Pod](definitions.Pod, p.i.GetThrottles, generic.WithModStatusGetter[*core.Pod](constants.PodGKv1(), p.clientv1))
}
func (p podsMod) clientv1() generic.ModClient[*core.Pod] {

View file

@ -41,7 +41,7 @@ type persistentVolumeClaimsMod struct {
}
func (p persistentVolumeClaimsMod) V1() persistentvolumeclaimv1.ModInterface {
return generic.NewModThrottle[*core.PersistentVolumeClaim](definitions.Endpoints, p.i.GetThrottles, generic.WithModStatusGetter[*core.PersistentVolumeClaim](constants.PersistentVolumeClaimGKv1(), p.clientv1))
return wrapMod[*core.PersistentVolumeClaim](definitions.PersistentVolumeClaim, p.i.GetThrottles, generic.WithModStatusGetter[*core.PersistentVolumeClaim](constants.PersistentVolumeClaimGKv1(), p.clientv1))
}
func (p persistentVolumeClaimsMod) clientv1() generic.ModClient[*core.PersistentVolumeClaim] {

View file

@ -41,7 +41,7 @@ type serviceAccountsMod struct {
}
func (p serviceAccountsMod) V1() serviceaccountv1.ModInterface {
return generic.NewModThrottle[*core.ServiceAccount](definitions.Endpoints, p.i.GetThrottles, generic.WithModStatusGetter[*core.ServiceAccount](constants.ServiceAccountGKv1(), p.clientv1))
return wrapMod[*core.ServiceAccount](definitions.ServiceAccount, p.i.GetThrottles, generic.WithModStatusGetter[*core.ServiceAccount](constants.ServiceAccountGKv1(), p.clientv1))
}
func (p serviceAccountsMod) clientv1() generic.ModClient[*core.ServiceAccount] {

View file

@ -41,7 +41,7 @@ type secretsMod struct {
}
func (p secretsMod) V1() secretv1.ModInterface {
return generic.NewModThrottle[*core.Secret](definitions.Endpoints, p.i.GetThrottles, generic.WithModStatusGetter[*core.Secret](constants.SecretGKv1(), p.clientv1))
return wrapMod[*core.Secret](definitions.Secret, p.i.GetThrottles, generic.WithModStatusGetter[*core.Secret](constants.SecretGKv1(), p.clientv1))
}
func (p secretsMod) clientv1() generic.ModClient[*core.Secret] {

View file

@ -41,7 +41,7 @@ type servicesMod struct {
}
func (p servicesMod) V1() servicev1.ModInterface {
return generic.NewModThrottle[*core.Service](definitions.Endpoints, p.i.GetThrottles, generic.WithModStatusGetter[*core.Service](constants.ServiceGKv1(), p.clientv1))
return wrapMod[*core.Service](definitions.Service, p.i.GetThrottles, generic.WithModStatusGetter[*core.Service](constants.ServiceGKv1(), p.clientv1))
}
func (p servicesMod) clientv1() generic.ModClient[*core.Service] {

View file

@ -41,7 +41,7 @@ type serviceMonitorsMod struct {
}
func (p serviceMonitorsMod) V1() servicemonitorv1.ModInterface {
return generic.NewModThrottle[*monitoring.ServiceMonitor](definitions.ServiceMonitor, p.i.GetThrottles, generic.WithModStatusGetter[*monitoring.ServiceMonitor](constants.ServiceMonitorGKv1(), p.clientv1))
return wrapMod[*monitoring.ServiceMonitor](definitions.ServiceMonitor, p.i.GetThrottles, generic.WithModStatusGetter[*monitoring.ServiceMonitor](constants.ServiceMonitorGKv1(), p.clientv1))
}
func (p serviceMonitorsMod) clientv1() generic.ModClient[*monitoring.ServiceMonitor] {

View file

@ -0,0 +1,32 @@
//
// DISCLAIMER
//
// Copyright 2023 ArangoDB GmbH, Cologne, Germany
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Copyright holder is ArangoDB GmbH, Cologne, Germany
//
package inspector
import (
meta "k8s.io/apimachinery/pkg/apis/meta/v1"
"github.com/arangodb/kube-arangodb/pkg/util/k8sutil/inspector/definitions"
"github.com/arangodb/kube-arangodb/pkg/util/k8sutil/inspector/generic"
)
func wrapMod[S meta.Object](component definitions.Component, componentGetter generic.ThrottleGetter, clientStatus generic.ClientStatusGetter[S]) generic.ModStatusClient[S] {
return generic.NewModThrottle[S](component, componentGetter, withMetrics[S](component, clientStatus))
}

View file

@ -0,0 +1,39 @@
//
// DISCLAIMER
//
// Copyright 2016-2023 ArangoDB GmbH, Cologne, Germany
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Copyright holder is ArangoDB GmbH, Cologne, Germany
//
package metric_descriptions
import "github.com/arangodb/kube-arangodb/pkg/util/metrics"
var (
arangodbOperatorKubernetesClientRequestErrors = metrics.NewDescription("arangodb_operator_kubernetes_client_request_errors", "Number of Kubernetes Client request errors", []string{`component`, `verb`}, nil)
)
func init() {
registerDescription(arangodbOperatorKubernetesClientRequestErrors)
}
func ArangodbOperatorKubernetesClientRequestErrors() metrics.Description {
return arangodbOperatorKubernetesClientRequestErrors
}
func ArangodbOperatorKubernetesClientRequestErrorsCounter(value float64, component string, verb string) metrics.Metric {
return ArangodbOperatorKubernetesClientRequestErrors().Gauge(value, component, verb)
}

View file

@ -0,0 +1,39 @@
//
// DISCLAIMER
//
// Copyright 2016-2023 ArangoDB GmbH, Cologne, Germany
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Copyright holder is ArangoDB GmbH, Cologne, Germany
//
package metric_descriptions
import "github.com/arangodb/kube-arangodb/pkg/util/metrics"
var (
arangodbOperatorKubernetesClientRequests = metrics.NewDescription("arangodb_operator_kubernetes_client_requests", "Number of Kubernetes Client requests", []string{`component`, `verb`}, nil)
)
func init() {
registerDescription(arangodbOperatorKubernetesClientRequests)
}
func ArangodbOperatorKubernetesClientRequests() metrics.Description {
return arangodbOperatorKubernetesClientRequests
}
func ArangodbOperatorKubernetesClientRequestsCounter(value float64, component string, verb string) metrics.Metric {
return ArangodbOperatorKubernetesClientRequests().Gauge(value, component, verb)
}

View file

@ -1,7 +1,7 @@
//
// DISCLAIMER
//
// Copyright 2016-2022 ArangoDB GmbH, Cologne, Germany
// Copyright 2016-2023 ArangoDB GmbH, Cologne, Germany
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -356,6 +356,9 @@ func (c *chain) Interface(key string, i interface{}) Logger {
}
func (c *chain) Err(err error) Logger {
if err == nil {
return c
}
return c.Wrap(Err(err))
}

View file

@ -1,7 +1,7 @@
//
// DISCLAIMER
//
// Copyright 2016-2022 ArangoDB GmbH, Cologne, Germany
// Copyright 2016-2023 ArangoDB GmbH, Cologne, Germany
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -23,9 +23,11 @@ package definitions
type Verb string
const (
Create Verb = "create"
Delete Verb = "delete"
Get Verb = "get"
Patch Verb = "patch"
Update Verb = "update"
Create Verb = "create"
Delete Verb = "delete"
ForceDelete Verb = "force-delete"
Get Verb = "get"
Patch Verb = "patch"
Update Verb = "update"
UpdateStatus Verb = "update-status"
)