Skip to content

Commit cd10e3e

Browse files
armrufcanovai
authored andcommitted
feat: secret cache
Signed-off-by: Armando Ruocco <[email protected]>
1 parent 9a67a45 commit cd10e3e

File tree

13 files changed

+144
-37
lines changed

13 files changed

+144
-37
lines changed

Makefile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,11 +45,11 @@ help: ## Display this help.
4545

4646
.PHONY: manifests
4747
manifests: controller-gen ## Generate WebhookConfiguration, ClusterRole and CustomResourceDefinition objects.
48-
$(CONTROLLER_GEN) rbac:roleName=plugin-barman-cloud crd webhook paths="./..." output:crd:artifacts:config=config/crd/bases
48+
$(CONTROLLER_GEN) rbac:roleName=plugin-barman-cloud crd webhook paths="./api/..." output:crd:artifacts:config=config/crd/bases
4949

5050
.PHONY: generate
5151
generate: controller-gen ## Generate code containing DeepCopy, DeepCopyInto, and DeepCopyObject method implementations.
52-
$(CONTROLLER_GEN) object:headerFile="hack/boilerplate.go.txt" paths="./..."
52+
$(CONTROLLER_GEN) object:headerFile="hack/boilerplate.go.txt" paths="./api/..."
5353

5454
.PHONY: fmt
5555
fmt: ## Run go fmt against code.

api/v1/objectstore_types.go

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,29 @@ import (
2121
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2222
)
2323

24-
// EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN!
25-
// NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized.
24+
// InstanceSidecarConfiguration defines the configuration for the sidecar that runs in the instance pods.
25+
type InstanceSidecarConfiguration struct {
26+
// The expiration time of the cache entries not managed by the informers. Expressed in seconds.
27+
// +optional
28+
// +kubebuilder:validation:Minimum=0
29+
// +kubebuilder:validation:Maximum=3600
30+
// +kubebuilder:default=180
31+
CacheTTL *int `json:"cacheTTL,omitempty"`
32+
}
33+
34+
// GetCacheTTL returns the cache TTL value, defaulting to 180 seconds if not set.
35+
func (i InstanceSidecarConfiguration) GetCacheTTL() int {
36+
if i.CacheTTL == nil {
37+
return 180
38+
}
39+
return *i.CacheTTL
40+
}
2641

2742
// ObjectStoreSpec defines the desired state of ObjectStore.
2843
type ObjectStoreSpec struct {
2944
Configuration barmanapi.BarmanObjectStoreConfiguration `json:"configuration"`
3045

31-
// TODO: we add here any exclusive fields for our plugin CRD
46+
InstanceSidecarConfiguration InstanceSidecarConfiguration `json:"instanceSidecarConfiguration,omitempty"`
3247
}
3348

3449
// ObjectStoreStatus defines the observed state of ObjectStore.

api/v1/zz_generated.deepcopy.go

Lines changed: 21 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

config/crd/bases/barmancloud.cnpg.io_objectstores.yaml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -378,6 +378,18 @@ spec:
378378
required:
379379
- destinationPath
380380
type: object
381+
instanceSidecarConfiguration:
382+
description: InstanceSidecarConfiguration defines the configuration
383+
for the sidecar that runs in the instance pods.
384+
properties:
385+
cacheTTL:
386+
default: 180
387+
description: The expiration time of the cache entries not managed
388+
by the informers. Expressed in seconds.
389+
maximum: 3600
390+
minimum: 0
391+
type: integer
392+
type: object
381393
required:
382394
- configuration
383395
type: object

internal/cmd/instance/main.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,6 @@ 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")
4443

4544
return cmd
4645
}

internal/client/client.go renamed to internal/cnpgi/instance/internal/client/client.go

Lines changed: 37 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,12 @@ package client
22

33
import (
44
"context"
5+
"fmt"
56
"sync"
67
"time"
78

89
"github.com/cloudnative-pg/machinery/pkg/log"
10+
v1 "github.com/cloudnative-pg/plugin-barman-cloud/api/v1"
911
corev1 "k8s.io/api/core/v1"
1012
"sigs.k8s.io/controller-runtime/pkg/client"
1113
)
@@ -15,23 +17,38 @@ type cachedSecret struct {
1517
fetchUnixTime int64
1618
}
1719

18-
// ExtendedClient is an extended client that is capable of caching multiple secrets without relying on 'list and watch'
20+
// ExtendedClient is an extended client that is capable of caching multiple secrets without relying on informers
1921
type ExtendedClient struct {
2022
client.Client
21-
cachedSecrets []*cachedSecret
22-
mux *sync.Mutex
23-
ttl int64
23+
barmanObjectKey client.ObjectKey
24+
cachedSecrets []*cachedSecret
25+
mux *sync.Mutex
26+
ttl int
2427
}
2528

2629
// NewExtendedClient returns an extended client capable of caching secrets on the 'Get' operation
27-
func NewExtendedClient(baseClient client.Client, ttl int64) client.Client {
30+
func NewExtendedClient(
31+
baseClient client.Client,
32+
objectStoreKey client.ObjectKey,
33+
) client.Client {
2834
return &ExtendedClient{
29-
Client: baseClient,
30-
ttl: ttl,
31-
mux: &sync.Mutex{},
35+
Client: baseClient,
36+
barmanObjectKey: objectStoreKey,
37+
mux: &sync.Mutex{},
3238
}
3339
}
3440

41+
func (e *ExtendedClient) refreshTTL(ctx context.Context) error {
42+
var object v1.ObjectStore
43+
if err := e.Get(ctx, e.barmanObjectKey, &object); err != nil {
44+
return fmt.Errorf("failed to get the object store while refreshing the TTL parameter: %w", err)
45+
}
46+
47+
e.ttl = object.Spec.InstanceSidecarConfiguration.GetCacheTTL()
48+
49+
return nil
50+
}
51+
3552
func (e *ExtendedClient) Get(
3653
ctx context.Context,
3754
key client.ObjectKey,
@@ -42,14 +59,21 @@ func (e *ExtendedClient) Get(
4259
WithName("extended_client").
4360
WithValues("name", key.Name, "namespace", key.Namespace)
4461

45-
if e.isCacheDisabled() {
62+
if _, ok := obj.(*corev1.Secret); !ok {
63+
contextLogger.Trace("not a secret, skipping")
4664
return e.Client.Get(ctx, key, obj, opts...)
4765
}
4866

49-
if _, ok := obj.(*corev1.Secret); !ok {
67+
if err := e.refreshTTL(ctx); err != nil {
68+
return err
69+
}
70+
71+
if e.isCacheDisabled() {
72+
contextLogger.Trace("cache is disabled")
5073
return e.Client.Get(ctx, key, obj, opts...)
5174
}
5275

76+
contextLogger.Trace("locking the cache")
5377
e.mux.Lock()
5478
defer e.mux.Unlock()
5579

@@ -64,7 +88,7 @@ func (e *ExtendedClient) Get(
6488
expiredSecretIndex = idx
6589
break
6690
}
67-
contextLogger.Trace("secret found, loading it from cache")
91+
contextLogger.Debug("secret found, loading it from cache")
6892
cache.secret.DeepCopyInto(obj.(*corev1.Secret))
6993
return nil
7094
}
@@ -78,6 +102,7 @@ func (e *ExtendedClient) Get(
78102
fetchUnixTime: time.Now().Unix(),
79103
}
80104

105+
contextLogger.Debug("setting secret in the cache")
81106
if expiredSecretIndex != -1 {
82107
e.cachedSecrets[expiredSecretIndex] = cs
83108
} else {
@@ -88,7 +113,7 @@ func (e *ExtendedClient) Get(
88113
}
89114

90115
func (e *ExtendedClient) isExpired(unixTime int64) bool {
91-
return time.Now().Unix()-unixTime > e.ttl
116+
return time.Now().Unix()-unixTime > int64(e.ttl)
92117
}
93118

94119
func (e *ExtendedClient) isCacheDisabled() bool {

internal/client/client_test.go renamed to internal/cnpgi/instance/internal/client/client_test.go

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,35 @@
11
package client
22

33
import (
4+
"k8s.io/apimachinery/pkg/runtime"
5+
"k8s.io/utils/ptr"
46
"sigs.k8s.io/controller-runtime/pkg/client/fake"
57
"time"
68

7-
. "github.com/onsi/ginkgo/v2"
8-
. "github.com/onsi/gomega"
9+
v1 "github.com/cloudnative-pg/plugin-barman-cloud/api/v1"
910
corev1 "k8s.io/api/core/v1"
1011
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
1112
"sigs.k8s.io/controller-runtime/pkg/client"
13+
14+
. "github.com/onsi/ginkgo/v2"
15+
. "github.com/onsi/gomega"
1216
)
1317

18+
var scheme = buildScheme()
19+
20+
func buildScheme() *runtime.Scheme {
21+
scheme := runtime.NewScheme()
22+
_ = corev1.AddToScheme(scheme)
23+
_ = v1.AddToScheme(scheme)
24+
25+
return scheme
26+
}
27+
1428
var _ = Describe("ExtendedClient Get", func() {
1529
var (
1630
extendedClient *ExtendedClient
1731
secretInClient *corev1.Secret
32+
objectStore *v1.ObjectStore
1833
)
1934

2035
BeforeEach(func() {
@@ -24,8 +39,22 @@ var _ = Describe("ExtendedClient Get", func() {
2439
Name: "test-secret",
2540
},
2641
}
27-
baseClient := fake.NewClientBuilder().WithObjects(secretInClient).Build()
28-
extendedClient = NewExtendedClient(baseClient, 60).(*ExtendedClient)
42+
objectStore = &v1.ObjectStore{
43+
ObjectMeta: metav1.ObjectMeta{
44+
Namespace: "default",
45+
Name: "test-object-store",
46+
},
47+
Spec: v1.ObjectStoreSpec{
48+
InstanceSidecarConfiguration: v1.InstanceSidecarConfiguration{
49+
CacheTTL: ptr.To(60),
50+
},
51+
},
52+
}
53+
54+
baseClient := fake.NewClientBuilder().
55+
WithScheme(scheme).
56+
WithObjects(secretInClient, objectStore).Build()
57+
extendedClient = NewExtendedClient(baseClient, client.ObjectKeyFromObject(objectStore)).(*ExtendedClient)
2958
})
3059

3160
It("returns secret from cache if not expired", func(ctx SpecContext) {

internal/client/doc.go renamed to internal/cnpgi/instance/internal/client/doc.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
// Package client provides an extended client that is capable of caching multiple secrets without relying on
2-
// 'list and watch'
2+
// informers
33
package client

internal/client/suite_test.go renamed to internal/cnpgi/instance/internal/client/suite_test.go

File renamed without changes.

internal/cnpgi/instance/manager.go

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package instance
22

33
import (
44
"context"
5+
extendedclient "github.com/cloudnative-pg/plugin-barman-cloud/internal/cnpgi/instance/internal/client"
56
"os"
67
"path"
78

@@ -18,7 +19,6 @@ import (
1819
"sigs.k8s.io/controller-runtime/pkg/log"
1920

2021
barmancloudv1 "github.com/cloudnative-pg/plugin-barman-cloud/api/v1"
21-
extendedclient "github.com/cloudnative-pg/plugin-barman-cloud/internal/client"
2222
)
2323

2424
var scheme = runtime.NewScheme()
@@ -37,7 +37,6 @@ func Start(ctx context.Context) error {
3737
boName := viper.GetString("barman-object-name")
3838
clusterName := viper.GetString("cluster-name")
3939
podName := viper.GetString("pod-name")
40-
secretCacheTTL := viper.GetInt64("secret-cache-ttl")
4140

4241
mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{
4342
Scheme: scheme,
@@ -70,17 +69,19 @@ func Start(ctx context.Context) error {
7069
os.Exit(1)
7170
}
7271

72+
barmanObjectKey := client.ObjectKey{
73+
Namespace: namespace,
74+
Name: boName,
75+
}
76+
7377
if err := mgr.Add(&CNPGI{
74-
Client: extendedclient.NewExtendedClient(mgr.GetClient(), secretCacheTTL),
78+
Client: extendedclient.NewExtendedClient(mgr.GetClient(), barmanObjectKey),
7579
ClusterObjectKey: client.ObjectKey{
7680
Namespace: namespace,
7781
Name: clusterName,
7882
},
79-
BarmanObjectKey: client.ObjectKey{
80-
Namespace: namespace,
81-
Name: boName,
82-
},
83-
InstanceName: podName,
83+
BarmanObjectKey: barmanObjectKey,
84+
InstanceName: podName,
8485
// TODO: improve
8586
PGDataPath: viper.GetString("pgdata"),
8687
PGWALPath: path.Join(viper.GetString("pgdata"), "pg_wal"),

0 commit comments

Comments
 (0)