@@ -22,6 +22,7 @@ import (
22
22
"crypto/x509"
23
23
"fmt"
24
24
"net/http"
25
+ "time"
25
26
26
27
"github.com/go-logr/logr"
27
28
"github.com/gophercloud/gophercloud"
@@ -31,12 +32,14 @@ import (
31
32
"github.com/gophercloud/utils/openstack/clientconfig"
32
33
corev1 "k8s.io/api/core/v1"
33
34
"k8s.io/apimachinery/pkg/types"
35
+ "k8s.io/apimachinery/pkg/util/cache"
34
36
"k8s.io/klog/v2"
35
37
"sigs.k8s.io/controller-runtime/pkg/client"
36
38
"sigs.k8s.io/yaml"
37
39
38
40
infrav1 "sigs.k8s.io/cluster-api-provider-openstack/api/v1alpha7"
39
41
"sigs.k8s.io/cluster-api-provider-openstack/pkg/clients"
42
+ "sigs.k8s.io/cluster-api-provider-openstack/pkg/utils/hash"
40
43
"sigs.k8s.io/cluster-api-provider-openstack/version"
41
44
)
42
45
@@ -45,9 +48,11 @@ const (
45
48
caSecretKey = "cacert"
46
49
)
47
50
48
- type providerScopeFactory struct {}
51
+ type providerScopeFactory struct {
52
+ clientCache * cache.LRUExpireCache
53
+ }
49
54
50
- func (providerScopeFactory ) NewClientScopeFromMachine (ctx context.Context , ctrlClient client.Client , openStackMachine * infrav1.OpenStackMachine , defaultCACert []byte , logger logr.Logger ) (Scope , error ) {
55
+ func (f * providerScopeFactory ) NewClientScopeFromMachine (ctx context.Context , ctrlClient client.Client , openStackMachine * infrav1.OpenStackMachine , defaultCACert []byte , logger logr.Logger ) (Scope , error ) {
51
56
var cloud clientconfig.Cloud
52
57
var caCert []byte
53
58
@@ -63,10 +68,14 @@ func (providerScopeFactory) NewClientScopeFromMachine(ctx context.Context, ctrlC
63
68
caCert = defaultCACert
64
69
}
65
70
66
- return NewProviderScope (cloud , caCert , logger )
71
+ if f .clientCache == nil {
72
+ return NewProviderScope (cloud , caCert , logger )
73
+ }
74
+
75
+ return NewCachedProviderScope (f .clientCache , cloud , caCert , logger )
67
76
}
68
77
69
- func (providerScopeFactory ) NewClientScopeFromCluster (ctx context.Context , ctrlClient client.Client , openStackCluster * infrav1.OpenStackCluster , defaultCACert []byte , logger logr.Logger ) (Scope , error ) {
78
+ func (f * providerScopeFactory ) NewClientScopeFromCluster (ctx context.Context , ctrlClient client.Client , openStackCluster * infrav1.OpenStackCluster , defaultCACert []byte , logger logr.Logger ) (Scope , error ) {
70
79
var cloud clientconfig.Cloud
71
80
var caCert []byte
72
81
@@ -82,7 +91,20 @@ func (providerScopeFactory) NewClientScopeFromCluster(ctx context.Context, ctrlC
82
91
caCert = defaultCACert
83
92
}
84
93
85
- return NewProviderScope (cloud , caCert , logger )
94
+ if f .clientCache == nil {
95
+ return NewProviderScope (cloud , caCert , logger )
96
+ }
97
+
98
+ return NewCachedProviderScope (f .clientCache , cloud , caCert , logger )
99
+ }
100
+
101
+ func getScopeCacheKey (cloud clientconfig.Cloud ) (string , error ) {
102
+ key , err := hash .ComputeSpewHash (cloud )
103
+ if err != nil {
104
+ return "" , err
105
+ }
106
+
107
+ return fmt .Sprintf ("%d" , key ), nil
86
108
}
87
109
88
110
type providerScope struct {
@@ -106,6 +128,34 @@ func NewProviderScope(cloud clientconfig.Cloud, caCert []byte, logger logr.Logge
106
128
}, nil
107
129
}
108
130
131
+ func NewCachedProviderScope (cache * cache.LRUExpireCache , cloud clientconfig.Cloud , caCert []byte , logger logr.Logger ) (Scope , error ) {
132
+ key , err := getScopeCacheKey (cloud )
133
+ if err != nil {
134
+ return nil , fmt .Errorf ("compute cloud config cache key: %w" , err )
135
+ }
136
+
137
+ if scope , found := cache .Get (key ); found {
138
+ logger .V (6 ).Info ("Using scope from cache" )
139
+ return scope .(Scope ), nil
140
+ }
141
+
142
+ scope , err := NewProviderScope (cloud , caCert , logger )
143
+ if err != nil {
144
+ return nil , err
145
+ }
146
+
147
+ token , err := scope .ExtractToken ()
148
+ if err != nil {
149
+ return nil , err
150
+ }
151
+
152
+ // compute the token expiration time
153
+ expiry := time .Until (token .ExpiresAt ) / 2
154
+
155
+ cache .Add (key , scope , expiry )
156
+ return scope , nil
157
+ }
158
+
109
159
func (s * providerScope ) Logger () logr.Logger {
110
160
return s .logger
111
161
}
@@ -134,6 +184,14 @@ func (s *providerScope) NewLbClient() (clients.LbClient, error) {
134
184
return clients .NewLbClient (s .providerClient , s .providerClientOpts )
135
185
}
136
186
187
+ func (s * providerScope ) ExtractToken () (* tokens.Token , error ) {
188
+ client , err := openstack .NewIdentityV3 (s .providerClient , gophercloud.EndpointOpts {})
189
+ if err != nil {
190
+ return nil , fmt .Errorf ("create new identity service client: %w" , err )
191
+ }
192
+ return tokens .Get (client , s .providerClient .Token ()).ExtractToken ()
193
+ }
194
+
137
195
func NewProviderClient (cloud clientconfig.Cloud , caCert []byte , logger logr.Logger ) (* gophercloud.ProviderClient , * clientconfig.ClientOpts , string , error ) {
138
196
clientOpts := new (clientconfig.ClientOpts )
139
197
if cloud .AuthInfo != nil {
0 commit comments