Skip to content

Commit

Permalink
feat: add dataplane metrics label
Browse files Browse the repository at this point in the history
  • Loading branch information
pmalek committed Feb 9, 2023
1 parent 3cb4067 commit 5b5e0be
Show file tree
Hide file tree
Showing 7 changed files with 297 additions and 178 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,11 @@ Adding a new version? You'll need three changes:
which accepts a namespaced name of headless kong admin service which should have
Admin API endpoints exposed under a named port called `admin`
[#3421](https://github.com/Kong/kubernetes-ingress-controller/pull/3421)
- Added `dataplane` metrics label for `ingress_controller_configuration_push_count`
and `ingress_controller_configuration_push_duration_milliseconds`. This means
that all time series for those metrics will get a new label designating the
address of the dataplane that the configuration push has been targeted for.
[#3521](https://github.com/Kong/kubernetes-ingress-controller/pull/3521)

### Fixed

Expand Down
47 changes: 47 additions & 0 deletions internal/dataplane/deckerrors/conflict.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package deckerrors

import (
"errors"
"net/http"

deckutils "github.com/kong/deck/utils"
"github.com/kong/go-kong/kong"
)

// ConfigConflictError is an error used to wrap deck config conflict errors
// returned from deck functions transforming KongRawState to KongState
// (e.g. state.Get, dump.Get).
type ConfigConflictError struct {
Err error
}

func (e ConfigConflictError) Error() string {
return e.Err.Error()
}

func (e ConfigConflictError) Is(err error) bool {
return errors.Is(err, ConfigConflictError{})
}

func (e ConfigConflictError) Unwrap() error {
return e.Err
}

func IsConflictErr(err error) bool {
var apiErr *kong.APIError
if errors.As(err, &apiErr) && apiErr.Code() == http.StatusConflict ||
errors.Is(err, ConfigConflictError{}) {
return true
}

var deckErrArray deckutils.ErrArray
if errors.As(err, &deckErrArray) {
for _, err := range deckErrArray.Errors {
if IsConflictErr(err) {
return true
}
}
}

return false
}
9 changes: 2 additions & 7 deletions internal/dataplane/kong_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import (

"github.com/kong/deck/file"
"github.com/kong/go-kong/kong"
"github.com/prometheus/client_golang/prometheus"
"github.com/samber/lo"
"github.com/sirupsen/logrus"
"github.com/sourcegraph/conc/iter"
Expand Down Expand Up @@ -430,15 +429,11 @@ func (c *KongClient) Update(ctx context.Context) error {
// parse the Kubernetes objects from the storer into Kong configuration
kongstate, translationFailures := p.Build()
if failuresCount := len(translationFailures); failuresCount > 0 {
c.prometheusMetrics.TranslationCount.With(prometheus.Labels{
metrics.SuccessKey: metrics.SuccessFalse,
}).Inc()
c.prometheusMetrics.RecordTranslationFailure()
c.recordResourceFailureEvents(translationFailures, KongConfigurationTranslationFailedEventReason)
c.logger.Debugf("%d translation failures have occurred when building data-plane configuration", failuresCount)
} else {
c.prometheusMetrics.TranslationCount.With(prometheus.Labels{
metrics.SuccessKey: metrics.SuccessTrue,
}).Inc()
c.prometheusMetrics.RecordTranslationSuccess()
c.logger.Debug("successfully built data-plane configuration")
}

Expand Down
83 changes: 6 additions & 77 deletions internal/dataplane/sendconfig/sendconfig.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,8 @@ import (
"context"
"encoding/hex"
"encoding/json"
"errors"
"fmt"
"io"
"net"
"net/http"
"sync"
"time"

Expand All @@ -20,10 +17,10 @@ import (
"github.com/kong/deck/state"
deckutils "github.com/kong/deck/utils"
"github.com/kong/go-kong/kong"
"github.com/prometheus/client_golang/prometheus"
"github.com/sirupsen/logrus"

"github.com/kong/kubernetes-ingress-controller/v2/internal/adminapi"
"github.com/kong/kubernetes-ingress-controller/v2/internal/dataplane/deckerrors"
"github.com/kong/kubernetes-ingress-controller/v2/internal/dataplane/deckgen"
"github.com/kong/kubernetes-ingress-controller/v2/internal/metrics"
)
Expand Down Expand Up @@ -58,7 +55,7 @@ func PerformUpdate(ctx context.Context,
}
}

var metricsProtocol string
var metricsProtocol metrics.Protocol
timeStart := time.Now()
if config.InMemory {
metricsProtocol = metrics.ProtocolDBLess
Expand All @@ -68,30 +65,14 @@ func PerformUpdate(ctx context.Context,
dumpConfig := dump.Config{SelectorTags: config.FilterTags, SkipCACerts: config.SkipCACertificates}
err = onUpdateDBMode(ctx, targetContent, client, dumpConfig, config)
}
timeEnd := time.Now()
duration := time.Since(timeStart)

if err != nil {
promMetrics.ConfigPushCount.With(prometheus.Labels{
metrics.SuccessKey: metrics.SuccessFalse,
metrics.ProtocolKey: metricsProtocol,
metrics.FailureReasonKey: pushFailureReason(err),
}).Inc()
promMetrics.ConfigPushDuration.With(prometheus.Labels{
metrics.SuccessKey: metrics.SuccessFalse,
metrics.ProtocolKey: metricsProtocol,
}).Observe(float64(timeEnd.Sub(timeStart).Milliseconds()))
promMetrics.RecordPushFailure(metricsProtocol, duration, client.BaseRootURL(), err)
return nil, err
}

promMetrics.ConfigPushCount.With(prometheus.Labels{
metrics.SuccessKey: metrics.SuccessTrue,
metrics.ProtocolKey: metricsProtocol,
metrics.FailureReasonKey: "",
}).Inc()
promMetrics.ConfigPushDuration.With(prometheus.Labels{
metrics.SuccessKey: metrics.SuccessTrue,
metrics.ProtocolKey: metricsProtocol,
}).Observe(float64(timeEnd.Sub(timeStart).Milliseconds()))
promMetrics.RecordPushSuccess(metricsProtocol, duration, client.BaseRootURL())
log.Info("successfully synced configuration to kong.")
return newSHA, nil
}
Expand Down Expand Up @@ -143,7 +124,7 @@ func onUpdateDBMode(

ts, err := targetState(ctx, targetContent, cs, config.Version, client, dumpConfig)
if err != nil {
return deckConfigConflictError{err}
return deckerrors.ConfigConflictError{Err: err}
}

syncer, err := diff.NewSyncer(diff.SyncerOpts{
Expand Down Expand Up @@ -218,58 +199,6 @@ func hasSHAUpdateAlreadyBeenReported(latestUpdateSHA []byte) bool {
return false
}

// deckConfigConflictError is an error used to wrap deck config conflict errors returned from deck functions
// transforming KongRawState to KongState (e.g. state.Get, dump.Get).
type deckConfigConflictError struct {
err error
}

func (e deckConfigConflictError) Error() string {
return e.err.Error()
}

func (e deckConfigConflictError) Is(target error) bool {
_, ok := target.(deckConfigConflictError)
return ok
}

func (e deckConfigConflictError) Unwrap() error {
return e.err
}

// pushFailureReason extracts config push failure reason from an error returned from onUpdateInMemoryMode or onUpdateDBMode.
func pushFailureReason(err error) string {
var netErr net.Error
if errors.As(err, &netErr) {
return metrics.FailureReasonNetwork
}

if isConflictErr(err) {
return metrics.FailureReasonConflict
}

return metrics.FailureReasonOther
}

func isConflictErr(err error) bool {
var apiErr *kong.APIError
if errors.As(err, &apiErr) && apiErr.Code() == http.StatusConflict ||
errors.Is(err, deckConfigConflictError{}) {
return true
}

var deckErrArray deckutils.ErrArray
if errors.As(err, &deckErrArray) {
for _, err := range deckErrArray.Errors {
if isConflictErr(err) {
return true
}
}
}

return false
}

type KonnectAwareClient interface {
IsKonnect() bool
}
Expand Down
85 changes: 0 additions & 85 deletions internal/dataplane/sendconfig/sendconfig_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,12 @@ package sendconfig
import (
"context"
"errors"
"fmt"
"net"
"net/http"
"testing"

deckutils "github.com/kong/deck/utils"
"github.com/kong/go-kong/kong"
"github.com/sirupsen/logrus"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"

"github.com/kong/kubernetes-ingress-controller/v2/internal/metrics"
)

func TestUpdateReportingUtilities(t *testing.T) {
Expand All @@ -28,84 +22,6 @@ func TestUpdateReportingUtilities(t *testing.T) {
assert.True(t, hasSHAUpdateAlreadyBeenReported([]byte("yet-another-fake-sha")))
}

func TestPushFailureReason(t *testing.T) {
apiConflictErr := kong.NewAPIError(http.StatusConflict, "conflict api error")
networkErr := net.UnknownNetworkError("network error")
genericError := errors.New("generic error")

testCases := []struct {
name string
err error
expectedReason string
}{
{
name: "generic_error",
err: genericError,
expectedReason: metrics.FailureReasonOther,
},
{
name: "api_conflict_error",
err: apiConflictErr,
expectedReason: metrics.FailureReasonConflict,
},
{
name: "api_conflict_error_wrapped",
err: fmt.Errorf("wrapped conflict api err: %w", apiConflictErr),
expectedReason: metrics.FailureReasonConflict,
},
{
name: "deck_config_conflict_error_empty",
err: deckConfigConflictError{},
expectedReason: metrics.FailureReasonConflict,
},
{
name: "deck_config_conflict_error_with_generic_error",
err: deckConfigConflictError{genericError},
expectedReason: metrics.FailureReasonConflict,
},
{
name: "deck_err_array_with_api_conflict_error",
err: deckutils.ErrArray{Errors: []error{apiConflictErr}},
expectedReason: metrics.FailureReasonConflict,
},
{
name: "wrapped_deck_err_array_with_api_conflict_error",
err: fmt.Errorf("wrapped: %w", deckutils.ErrArray{Errors: []error{apiConflictErr}}),
expectedReason: metrics.FailureReasonConflict,
},
{
name: "deck_err_array_with_generic_error",
err: deckutils.ErrArray{Errors: []error{genericError}},
expectedReason: metrics.FailureReasonOther,
},
{
name: "deck_err_array_empty",
err: deckutils.ErrArray{Errors: []error{genericError}},
expectedReason: metrics.FailureReasonOther,
},
{
name: "network_error",
err: networkErr,
expectedReason: metrics.FailureReasonNetwork,
},
{
name: "network_error_wrapped_in_deck_config_conflict_error",
err: deckConfigConflictError{networkErr},
expectedReason: metrics.FailureReasonNetwork,
},
}

for _, tc := range testCases {
tc := tc
t.Run(tc.name, func(t *testing.T) {
t.Parallel()

reason := pushFailureReason(tc.err)
require.Equal(t, tc.expectedReason, reason)
})
}
}

type konnectAwareClientMock struct {
expected bool
}
Expand Down Expand Up @@ -204,5 +120,4 @@ func TestHasConfigurationChanged(t *testing.T) {
require.Equal(t, tc.expectedResult, result)
})
}

}

0 comments on commit 5b5e0be

Please sign in to comment.