-
Notifications
You must be signed in to change notification settings - Fork 595
/
Copy pathconfig_change_detector.go
104 lines (86 loc) · 3.04 KB
/
config_change_detector.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
package sendconfig
import (
"bytes"
"context"
"fmt"
"github.com/go-logr/logr"
"github.com/kong/go-database-reconciler/pkg/file"
"github.com/kong/go-kong/kong"
"github.com/kong/kubernetes-ingress-controller/v3/internal/dataplane/deckgen"
)
const (
// WellKnownInitialHash is the hash of an empty configuration.
WellKnownInitialHash = "00000000000000000000000000000000"
)
type ConfigurationChangeDetector interface {
// HasConfigurationChanged verifies whether configuration has changed by comparing
// old and new config's SHAs.
// In case the SHAs are equal, it still can return true if a client is considered
// crashed or just booted up based on its status.
// In case the status indicates an empty config and the desired config is also empty
// this will return false to prevent continuously sending empty configuration to Gateway.
HasConfigurationChanged(
ctx context.Context,
oldSHA, newSHA []byte,
targetConfig *file.Content,
client KonnectAwareClient,
statusClient StatusClient,
) (bool, error)
}
type KonnectAwareClient interface {
IsKonnect() bool
}
type StatusClient interface {
Status(context.Context) (*kong.Status, error)
}
type DefaultConfigurationChangeDetector struct {
logger logr.Logger
}
func NewDefaultConfigurationChangeDetector(logger logr.Logger) *DefaultConfigurationChangeDetector {
return &DefaultConfigurationChangeDetector{logger: logger}
}
func (d *DefaultConfigurationChangeDetector) HasConfigurationChanged(
ctx context.Context,
oldSHA, newSHA []byte,
targetConfig *file.Content,
client KonnectAwareClient,
statusClient StatusClient,
) (bool, error) {
if !bytes.Equal(oldSHA, newSHA) {
return true, nil
}
// In case of Konnect, we skip further steps that are meant to detect Kong instances crash/reset
// that are not relevant for Konnect.
// We're sure that if oldSHA and newSHA are equal, we are safe to skip the update.
if client.IsKonnect() {
return false, nil
}
// Check if a Kong instance has no configuration yet (could mean it crashed, was rebooted, etc.).
hasNoConfiguration, err := kongHasNoConfiguration(ctx, statusClient)
if err != nil {
return false, fmt.Errorf("failed to verify kong readiness: %w", err)
}
// Kong instance has no configuration, we should push despite the oldSHA and newSHA being equal...
if hasNoConfiguration {
// ... unless we're trying to push an empty config in such case skip.
if deckgen.IsContentEmpty(targetConfig) {
return false, nil
}
return true, nil
}
return false, nil
}
// kongHasNoConfiguration checks Kong's status endpoint and read its config hash.
// If the config hash reported by Kong is the known empty hash, it's considered crashed.
// This allows providing configuration to Kong instances that have unexpectedly crashed and
// lost their configuration.
func kongHasNoConfiguration(ctx context.Context, client StatusClient) (bool, error) {
status, err := client.Status(ctx)
if err != nil {
return false, err
}
if hasNoConfig := status.ConfigurationHash == WellKnownInitialHash; hasNoConfig {
return true, nil
}
return false, nil
}