/
konnect.go
97 lines (87 loc) · 2.75 KB
/
konnect.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
package adminapi
import (
"context"
"crypto/tls"
"errors"
"fmt"
"net/http"
"time"
"github.com/avast/retry-go/v4"
"github.com/go-logr/logr"
"github.com/kong/go-kong/kong"
"github.com/samber/lo"
tlsutil "github.com/kong/kubernetes-ingress-controller/v3/internal/util/tls"
)
type KonnectConfig struct {
// TODO https://github.com/Kong/kubernetes-ingress-controller/issues/3922
// ConfigSynchronizationEnabled is the only toggle we had prior to the addition of the license agent.
// We likely want to combine these into a single Konnect toggle or piggyback off other Konnect functionality.
ConfigSynchronizationEnabled bool
ControlPlaneID string
Address string
RefreshNodePeriod time.Duration
TLSClient TLSClientConfig
LicenseSynchronizationEnabled bool
InitialLicensePollingPeriod time.Duration
LicensePollingPeriod time.Duration
}
func NewKongClientForKonnectControlPlane(c KonnectConfig) (*KonnectClient, error) {
clientCertificate, err := tlsutil.ExtractClientCertificates(
[]byte(c.TLSClient.Cert),
c.TLSClient.CertFile,
[]byte(c.TLSClient.Key),
c.TLSClient.KeyFile,
)
if err != nil {
return nil, fmt.Errorf("failed to extract client certificates: %w", err)
}
if clientCertificate == nil {
return nil, fmt.Errorf("client ceritficate is missing")
}
tlsConfig := tls.Config{
Certificates: []tls.Certificate{*clientCertificate},
MinVersion: tls.VersionTLS12,
}
transport := http.DefaultTransport.(*http.Transport).Clone()
transport.TLSClientConfig = &tlsConfig
client, err := kong.NewClient(
lo.ToPtr(fmt.Sprintf("%s/%s/%s", c.Address, "kic/api/control-planes", c.ControlPlaneID)),
&http.Client{
Transport: transport,
},
)
if err != nil {
return nil, err
}
return NewKonnectClient(client, c.ControlPlaneID), nil
}
// EnsureKonnectConnection ensures that the client is able to connect to Konnect.
func EnsureKonnectConnection(ctx context.Context, client *kong.Client, logger logr.Logger) error {
const (
retries = 5
delay = time.Second
)
if err := retry.Do(
func() error {
// Call an arbitrary endpoint that should return no error.
if _, _, err := client.Services.List(ctx, &kong.ListOpt{Size: 1}); err != nil {
if errors.Is(err, context.Canceled) {
return retry.Unrecoverable(err)
}
return err
}
return nil
},
retry.Attempts(retries),
retry.Context(ctx),
retry.Delay(delay),
retry.DelayType(retry.FixedDelay),
retry.LastErrorOnly(true),
retry.OnRetry(func(n uint, err error) {
logger.Info("Konnect Admin API client unhealthy, retrying", "retry", n, "error", err.Error())
}),
); err != nil {
return fmt.Errorf("konnect client unhealthy, no success after %d retries: %w", retries, err)
}
return nil
}