Skip to content

Commit 5b5ada0

Browse files
authored
[Feature] [Platform] Cache Introduction (#1894)
1 parent b7ae7e9 commit 5b5ada0

File tree

6 files changed

+397
-0
lines changed

6 files changed

+397
-0
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
- (Feature) Ensure Group Service Type
88
- (Maintenance) Fix Helm & JWT CVE's
99
- (Feature) (Platform) Improve CLI Values
10+
- (Feature) (Platform) Envoy Cache Introduction
1011

1112
## [1.2.48](https://github.com/arangodb/kube-arangodb/tree/1.2.48) (2025-05-08)
1213
- (Maintenance) Extend Documentation
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
//
2+
// DISCLAIMER
3+
//
4+
// Copyright 2025 ArangoDB GmbH, Cologne, Germany
5+
//
6+
// Licensed under the Apache License, Version 2.0 (the "License");
7+
// you may not use this file except in compliance with the License.
8+
// You may obtain a copy of the License at
9+
//
10+
// http://www.apache.org/licenses/LICENSE-2.0
11+
//
12+
// Unless required by applicable law or agreed to in writing, software
13+
// distributed under the License is distributed on an "AS IS" BASIS,
14+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
// See the License for the specific language governing permissions and
16+
// limitations under the License.
17+
//
18+
// Copyright holder is ArangoDB GmbH, Cologne, Germany
19+
//
20+
21+
package definition
22+
23+
import (
24+
"context"
25+
"fmt"
26+
"time"
27+
28+
"github.com/arangodb/go-driver/v2/connection"
29+
30+
"github.com/arangodb/kube-arangodb/pkg/util"
31+
"github.com/arangodb/kube-arangodb/pkg/util/cache"
32+
"github.com/arangodb/kube-arangodb/pkg/util/shutdown"
33+
)
34+
35+
func NewRootRequestModifier(client AuthenticationV1Client) connection.Authentication {
36+
return authenticationModifier(NewRootFetcher(client))
37+
}
38+
39+
type authenticationModifier cache.ObjectFetcher[string]
40+
41+
func (a authenticationModifier) RequestModifier(r connection.Request) error {
42+
ctx, c := context.WithTimeout(shutdown.Context(), time.Second)
43+
defer c()
44+
45+
token, _, err := a(ctx)
46+
if err != nil {
47+
return err
48+
}
49+
50+
if token != "" {
51+
r.AddHeader("Authorization", fmt.Sprintf("bearer %s", token))
52+
}
53+
54+
return nil
55+
}
56+
57+
func NewRootFetcher(client AuthenticationV1Client) cache.ObjectFetcher[string] {
58+
return NewFetcher(client, "root")
59+
}
60+
61+
func NewFetcher(client AuthenticationV1Client, user string, roles ...string) cache.ObjectFetcher[string] {
62+
return func(ctx context.Context) (string, time.Duration, error) {
63+
resp, err := client.CreateToken(ctx, &CreateTokenRequest{
64+
User: util.NewType(user),
65+
Roles: roles,
66+
})
67+
if err != nil {
68+
return "", 0, err
69+
}
70+
71+
if lf := resp.GetLifetime(); lf != nil {
72+
return resp.GetToken(), lf.AsDuration() / 100 * 75, nil
73+
}
74+
75+
return resp.GetToken(), 5 * time.Minute, nil
76+
}
77+
}

pkg/util/cache/cache.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ type CacheExtract[K comparable, T any] func(ctx context.Context, in K) (T, error
4040

4141
type Cache[K comparable, T any] interface {
4242
Get(ctx context.Context, key K) (T, error)
43+
Invalidate(key K)
4344
}
4445

4546
type cache[K comparable, T any] struct {
@@ -75,6 +76,13 @@ func (c *cache[K, T]) Get(ctx context.Context, key K) (T, error) {
7576
return el, nil
7677
}
7778

79+
func (c *cache[K, T]) Invalidate(key K) {
80+
c.lock.Lock()
81+
defer c.lock.Unlock()
82+
83+
delete(c.items, key)
84+
}
85+
7886
type cacheItem[T any] struct {
7987
created time.Time
8088

pkg/util/cache/config.go

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
//
2+
// DISCLAIMER
3+
//
4+
// Copyright 2025 ArangoDB GmbH, Cologne, Germany
5+
//
6+
// Licensed under the Apache License, Version 2.0 (the "License");
7+
// you may not use this file except in compliance with the License.
8+
// You may obtain a copy of the License at
9+
//
10+
// http://www.apache.org/licenses/LICENSE-2.0
11+
//
12+
// Unless required by applicable law or agreed to in writing, software
13+
// distributed under the License is distributed on an "AS IS" BASIS,
14+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
// See the License for the specific language governing permissions and
16+
// limitations under the License.
17+
//
18+
// Copyright holder is ArangoDB GmbH, Cologne, Germany
19+
//
20+
21+
package cache
22+
23+
import (
24+
"context"
25+
"os"
26+
"sync"
27+
"time"
28+
29+
"github.com/arangodb/kube-arangodb/pkg/util"
30+
)
31+
32+
func NewConfigFile[T any](path string, ttl time.Duration) ConfigFile[T] {
33+
return &configFile[T]{
34+
path: path,
35+
ttl: ttl,
36+
}
37+
}
38+
39+
type ConfigFile[T any] interface {
40+
Get(ctx context.Context) (T, string, error)
41+
}
42+
43+
type configFile[T any] struct {
44+
lock sync.Mutex
45+
46+
path string
47+
hash string
48+
ttl time.Duration
49+
50+
object T
51+
52+
next time.Time
53+
}
54+
55+
func (c *configFile[T]) Get(_ context.Context) (T, string, error) {
56+
c.lock.Lock()
57+
defer c.lock.Unlock()
58+
59+
if time.Now().After(c.next) {
60+
d, err := os.ReadFile(c.path)
61+
if err != nil {
62+
return util.Default[T](), "", err
63+
}
64+
65+
obj, err := util.JsonOrYamlUnmarshal[T](d)
66+
if err != nil {
67+
return util.Default[T](), "", err
68+
}
69+
70+
c.object = obj
71+
c.hash = util.SHA256(d)
72+
c.next = time.Now().Add(c.ttl)
73+
}
74+
75+
return c.object, c.hash, nil
76+
}
77+
78+
type HashedConfigurationRetriever[T, S any] func(ctx context.Context, in S) (T, error)
79+
80+
func NewHashedConfiguration[T, S any](config ConfigFile[S], retriever HashedConfigurationRetriever[T, S]) HashedConfiguration[T] {
81+
return &hashedConfiguration[T, S]{
82+
config: config,
83+
retriever: retriever,
84+
}
85+
}
86+
87+
type HashedConfiguration[T any] interface {
88+
Get(ctx context.Context) (T, error)
89+
}
90+
91+
type hashedConfiguration[T, S any] struct {
92+
lock sync.Mutex
93+
94+
config ConfigFile[S]
95+
96+
retriever HashedConfigurationRetriever[T, S]
97+
98+
hash string
99+
obj T
100+
}
101+
102+
func (h *hashedConfiguration[T, S]) Get(ctx context.Context) (T, error) {
103+
h.lock.Lock()
104+
defer h.lock.Unlock()
105+
106+
in, hash, err := h.config.Get(ctx)
107+
if err != nil {
108+
return util.Default[T](), err
109+
}
110+
111+
if h.hash != hash {
112+
obj, err := h.retriever(ctx, in)
113+
if err != nil {
114+
return util.Default[T](), err
115+
}
116+
117+
h.hash = hash
118+
h.obj = obj
119+
}
120+
121+
return h.obj, nil
122+
}

pkg/util/cache/object.go

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
//
2+
// DISCLAIMER
3+
//
4+
// Copyright 2025 ArangoDB GmbH, Cologne, Germany
5+
//
6+
// Licensed under the Apache License, Version 2.0 (the "License");
7+
// you may not use this file except in compliance with the License.
8+
// You may obtain a copy of the License at
9+
//
10+
// http://www.apache.org/licenses/LICENSE-2.0
11+
//
12+
// Unless required by applicable law or agreed to in writing, software
13+
// distributed under the License is distributed on an "AS IS" BASIS,
14+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
// See the License for the specific language governing permissions and
16+
// limitations under the License.
17+
//
18+
// Copyright holder is ArangoDB GmbH, Cologne, Germany
19+
//
20+
21+
package cache
22+
23+
import (
24+
"context"
25+
"sync"
26+
"time"
27+
28+
"github.com/arangodb/kube-arangodb/pkg/util"
29+
)
30+
31+
func NewObject[T any](caller ObjectFetcher[T]) Object[T] {
32+
return &object[T]{
33+
caller: caller,
34+
}
35+
}
36+
37+
type ObjectFetcher[T any] func(ctx context.Context) (T, time.Duration, error)
38+
39+
type Object[T any] interface {
40+
Get(ctx context.Context) (T, error)
41+
}
42+
43+
type object[T any] struct {
44+
lock sync.Mutex
45+
46+
caller ObjectFetcher[T]
47+
48+
eol time.Time
49+
obj T
50+
}
51+
52+
func (o *object[T]) Get(ctx context.Context) (T, error) {
53+
o.lock.Lock()
54+
defer o.lock.Unlock()
55+
56+
if time.Now().Before(o.eol) || o.eol.IsZero() {
57+
obj, ttl, err := o.caller(ctx)
58+
if err != nil {
59+
return util.Default[T](), err
60+
}
61+
62+
if ttl <= 0 {
63+
return obj, nil
64+
}
65+
66+
o.obj = obj
67+
o.eol = time.Now().Add(ttl)
68+
}
69+
70+
return o.obj, nil
71+
}

0 commit comments

Comments
 (0)