@@ -22,6 +22,7 @@ import (
2222 "crypto/x509"
2323 "fmt"
2424 "net/http"
25+ "time"
2526
2627 "github.com/go-logr/logr"
2728 "github.com/gophercloud/gophercloud"
@@ -31,12 +32,14 @@ import (
3132 "github.com/gophercloud/utils/openstack/clientconfig"
3233 corev1 "k8s.io/api/core/v1"
3334 "k8s.io/apimachinery/pkg/types"
35+ "k8s.io/apimachinery/pkg/util/cache"
3436 "k8s.io/klog/v2"
3537 "sigs.k8s.io/controller-runtime/pkg/client"
3638 "sigs.k8s.io/yaml"
3739
3840 infrav1 "sigs.k8s.io/cluster-api-provider-openstack/api/v1alpha7"
3941 "sigs.k8s.io/cluster-api-provider-openstack/pkg/clients"
42+ "sigs.k8s.io/cluster-api-provider-openstack/pkg/utils/hash"
4043 "sigs.k8s.io/cluster-api-provider-openstack/version"
4144)
4245
@@ -45,9 +48,11 @@ const (
4548 caSecretKey = "cacert"
4649)
4750
48- type providerScopeFactory struct {}
51+ type providerScopeFactory struct {
52+ cache * cache.LRUExpireCache
53+ }
4954
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 ) {
5156 var cloud clientconfig.Cloud
5257 var caCert []byte
5358
@@ -63,10 +68,14 @@ func (providerScopeFactory) NewClientScopeFromMachine(ctx context.Context, ctrlC
6368 caCert = defaultCACert
6469 }
6570
66- return NewProviderScope (cloud , caCert , logger )
71+ if f .cache == nil {
72+ return NewProviderScope (cloud , caCert , logger )
73+ }
74+
75+ return NewCachedProviderScope (f .cache , cloud , caCert , logger )
6776}
6877
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 ) {
7079 var cloud clientconfig.Cloud
7180 var caCert []byte
7281
@@ -82,7 +91,20 @@ func (providerScopeFactory) NewClientScopeFromCluster(ctx context.Context, ctrlC
8291 caCert = defaultCACert
8392 }
8493
85- return NewProviderScope (cloud , caCert , logger )
94+ if f .cache == nil {
95+ return NewProviderScope (cloud , caCert , logger )
96+ }
97+
98+ return NewCachedProviderScope (f .cache , 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
86108}
87109
88110type providerScope struct {
@@ -106,6 +128,34 @@ func NewProviderScope(cloud clientconfig.Cloud, caCert []byte, logger logr.Logge
106128 }, nil
107129}
108130
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 ("can't 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+
109159func (s * providerScope ) Logger () logr.Logger {
110160 return s .logger
111161}
@@ -134,6 +184,14 @@ func (s *providerScope) NewLbClient() (clients.LbClient, error) {
134184 return clients .NewLbClient (s .providerClient , s .providerClientOpts )
135185}
136186
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 ("can't create a new identity service client: %w" , err )
191+ }
192+ return tokens .Get (client , s .providerClient .Token ()).ExtractToken ()
193+ }
194+
137195func NewProviderClient (cloud clientconfig.Cloud , caCert []byte , logger logr.Logger ) (* gophercloud.ProviderClient , * clientconfig.ClientOpts , string , error ) {
138196 clientOpts := new (clientconfig.ClientOpts )
139197 if cloud .AuthInfo != nil {
0 commit comments