Skip to content

Commit 9a67a45

Browse files
committed
feat: finish implementation
Signed-off-by: Armando Ruocco <[email protected]>
1 parent 1505413 commit 9a67a45

File tree

6 files changed

+127
-21
lines changed

6 files changed

+127
-21
lines changed

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@ require (
114114
google.golang.org/genproto/googleapis/api v0.0.0-20240814211410-ddb44dafa142 // indirect
115115
google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142 // indirect
116116
google.golang.org/protobuf v1.35.1 // indirect
117+
gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect
117118
gopkg.in/inf.v0 v0.9.1 // indirect
118119
gopkg.in/ini.v1 v1.67.0 // indirect
119120
gopkg.in/yaml.v2 v2.4.0 // indirect

internal/client/client.go

Lines changed: 25 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"sync"
66
"time"
77

8+
"github.com/cloudnative-pg/machinery/pkg/log"
89
corev1 "k8s.io/api/core/v1"
910
"sigs.k8s.io/controller-runtime/pkg/client"
1011
)
@@ -27,6 +28,7 @@ func NewExtendedClient(baseClient client.Client, ttl int64) client.Client {
2728
return &ExtendedClient{
2829
Client: baseClient,
2930
ttl: ttl,
31+
mux: &sync.Mutex{},
3032
}
3133
}
3234

@@ -36,6 +38,10 @@ func (e *ExtendedClient) Get(
3638
obj client.Object,
3739
opts ...client.GetOption,
3840
) error {
41+
contextLogger := log.FromContext(ctx).
42+
WithName("extended_client").
43+
WithValues("name", key.Name, "namespace", key.Namespace)
44+
3945
if e.isCacheDisabled() {
4046
return e.Client.Get(ctx, key, obj, opts...)
4147
}
@@ -47,37 +53,36 @@ func (e *ExtendedClient) Get(
4753
e.mux.Lock()
4854
defer e.mux.Unlock()
4955

56+
expiredSecretIndex := -1
5057
// check if in cache
51-
for _, cache := range e.cachedSecrets {
52-
if cache.secret.Namespace == key.Namespace && cache.secret.Name == key.Name {
53-
if !e.isExpired(cache.fetchUnixTime) {
54-
cache.secret.DeepCopyInto(obj.(*corev1.Secret))
55-
return nil
56-
}
58+
for idx, cache := range e.cachedSecrets {
59+
if cache.secret.Namespace != key.Namespace || cache.secret.Name != key.Name {
60+
continue
61+
}
62+
if e.isExpired(cache.fetchUnixTime) {
63+
contextLogger.Trace("secret found, but it is expired")
64+
expiredSecretIndex = idx
5765
break
5866
}
67+
contextLogger.Trace("secret found, loading it from cache")
68+
cache.secret.DeepCopyInto(obj.(*corev1.Secret))
69+
return nil
5970
}
6071

6172
if err := e.Client.Get(ctx, key, obj); err != nil {
6273
return err
6374
}
6475

65-
secret := obj.(*corev1.Secret)
66-
67-
// check if the secret is already in cache if so replace it
68-
for _, cache := range e.cachedSecrets {
69-
if cache.secret.Namespace == key.Namespace && cache.secret.Name == key.Name {
70-
cache.secret = secret.DeepCopy()
71-
cache.fetchUnixTime = time.Now().Unix()
72-
return nil
73-
}
76+
cs := &cachedSecret{
77+
secret: obj.(*corev1.Secret).DeepCopy(),
78+
fetchUnixTime: time.Now().Unix(),
7479
}
7580

76-
// otherwise add it to the cache
77-
e.cachedSecrets = append(e.cachedSecrets, &cachedSecret{
78-
secret: secret.DeepCopy(),
79-
fetchUnixTime: time.Now().Unix(),
80-
})
81+
if expiredSecretIndex != -1 {
82+
e.cachedSecrets[expiredSecretIndex] = cs
83+
} else {
84+
e.cachedSecrets = append(e.cachedSecrets, cs)
85+
}
8186

8287
return nil
8388
}

internal/client/client_test.go

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
package client
2+
3+
import (
4+
"sigs.k8s.io/controller-runtime/pkg/client/fake"
5+
"time"
6+
7+
. "github.com/onsi/ginkgo/v2"
8+
. "github.com/onsi/gomega"
9+
corev1 "k8s.io/api/core/v1"
10+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
11+
"sigs.k8s.io/controller-runtime/pkg/client"
12+
)
13+
14+
var _ = Describe("ExtendedClient Get", func() {
15+
var (
16+
extendedClient *ExtendedClient
17+
secretInClient *corev1.Secret
18+
)
19+
20+
BeforeEach(func() {
21+
secretInClient = &corev1.Secret{
22+
ObjectMeta: metav1.ObjectMeta{
23+
Namespace: "default",
24+
Name: "test-secret",
25+
},
26+
}
27+
baseClient := fake.NewClientBuilder().WithObjects(secretInClient).Build()
28+
extendedClient = NewExtendedClient(baseClient, 60).(*ExtendedClient)
29+
})
30+
31+
It("returns secret from cache if not expired", func(ctx SpecContext) {
32+
secretNotInClient := &corev1.Secret{
33+
ObjectMeta: metav1.ObjectMeta{
34+
Namespace: "default",
35+
Name: "test-secret-not-in-client",
36+
},
37+
}
38+
39+
// manually add the secret to the cache, this is not present in the fake client so we are sure it is from the
40+
// cache
41+
extendedClient.cachedSecrets = []*cachedSecret{
42+
{
43+
secret: secretNotInClient,
44+
fetchUnixTime: time.Now().Unix(),
45+
},
46+
}
47+
48+
err := extendedClient.Get(ctx, client.ObjectKeyFromObject(secretNotInClient), secretInClient)
49+
Expect(err).NotTo(HaveOccurred())
50+
Expect(secretNotInClient).To(Equal(extendedClient.cachedSecrets[0].secret))
51+
})
52+
53+
It("fetches secret from base client if cache is expired", func(ctx SpecContext) {
54+
extendedClient.cachedSecrets = []*cachedSecret{
55+
{
56+
secret: secretInClient.DeepCopy(),
57+
fetchUnixTime: time.Now().Add(-2 * time.Minute).Unix(),
58+
},
59+
}
60+
61+
err := extendedClient.Get(ctx, client.ObjectKeyFromObject(secretInClient), secretInClient)
62+
Expect(err).NotTo(HaveOccurred())
63+
})
64+
65+
It("fetches secret from base client if not in cache", func(ctx SpecContext) {
66+
err := extendedClient.Get(ctx, client.ObjectKeyFromObject(secretInClient), secretInClient)
67+
Expect(err).NotTo(HaveOccurred())
68+
})
69+
70+
It("does not cache non-secret objects", func(ctx SpecContext) {
71+
configMap := &corev1.ConfigMap{
72+
ObjectMeta: metav1.ObjectMeta{
73+
Namespace: "default",
74+
Name: "test-configmap",
75+
},
76+
}
77+
err := extendedClient.Create(ctx, configMap)
78+
Expect(err).ToNot(HaveOccurred())
79+
80+
err = extendedClient.Get(ctx, client.ObjectKeyFromObject(configMap), configMap)
81+
Expect(err).NotTo(HaveOccurred())
82+
Expect(extendedClient.cachedSecrets).To(BeEmpty())
83+
})
84+
})

internal/client/suite_test.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package client_test
2+
3+
import (
4+
"testing"
5+
6+
. "github.com/onsi/ginkgo/v2"
7+
. "github.com/onsi/gomega"
8+
)
9+
10+
func TestClient(t *testing.T) {
11+
RegisterFailHandler(Fail)
12+
RunSpecs(t, "Client Suite")
13+
}

internal/cmd/instance/main.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ func NewCmd() *cobra.Command {
4040
_ = viper.BindEnv("pod-name", "POD_NAME")
4141
_ = viper.BindEnv("pgdata", "PGDATA")
4242
_ = viper.BindEnv("spool-directory", "SPOOL_DIRECTORY")
43+
_ = viper.BindEnv("secret-cache-ttl", "SECRET_CACHE_TTL")
4344

4445
return cmd
4546
}

internal/cnpgi/instance/manager.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import (
1818
"sigs.k8s.io/controller-runtime/pkg/log"
1919

2020
barmancloudv1 "github.com/cloudnative-pg/plugin-barman-cloud/api/v1"
21+
extendedclient "github.com/cloudnative-pg/plugin-barman-cloud/internal/client"
2122
)
2223

2324
var scheme = runtime.NewScheme()
@@ -36,6 +37,7 @@ func Start(ctx context.Context) error {
3637
boName := viper.GetString("barman-object-name")
3738
clusterName := viper.GetString("cluster-name")
3839
podName := viper.GetString("pod-name")
40+
secretCacheTTL := viper.GetInt64("secret-cache-ttl")
3941

4042
mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{
4143
Scheme: scheme,
@@ -69,7 +71,7 @@ func Start(ctx context.Context) error {
6971
}
7072

7173
if err := mgr.Add(&CNPGI{
72-
Client: mgr.GetClient(),
74+
Client: extendedclient.NewExtendedClient(mgr.GetClient(), secretCacheTTL),
7375
ClusterObjectKey: client.ObjectKey{
7476
Namespace: namespace,
7577
Name: clusterName,

0 commit comments

Comments
 (0)