@@ -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"
@@ -35,8 +36,10 @@ import (
3536 "sigs.k8s.io/controller-runtime/pkg/client"
3637 "sigs.k8s.io/yaml"
3738
39+ "k8s.io/apimachinery/pkg/util/cache"
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,10 @@ func (providerScopeFactory) NewClientScopeFromMachine(ctx context.Context, ctrlC
6368 caCert = defaultCACert
6469 }
6570
66- return NewProviderScope ( cloud , caCert , logger )
71+ return NewCachedProviderScope ( f . cache , cloud , caCert , logger )
6772}
6873
69- func (providerScopeFactory ) NewClientScopeFromCluster (ctx context.Context , ctrlClient client.Client , openStackCluster * infrav1.OpenStackCluster , defaultCACert []byte , logger logr.Logger ) (Scope , error ) {
74+ func (f * providerScopeFactory ) NewClientScopeFromCluster (ctx context.Context , ctrlClient client.Client , openStackCluster * infrav1.OpenStackCluster , defaultCACert []byte , logger logr.Logger ) (Scope , error ) {
7075 var cloud clientconfig.Cloud
7176 var caCert []byte
7277
@@ -82,7 +87,16 @@ func (providerScopeFactory) NewClientScopeFromCluster(ctx context.Context, ctrlC
8287 caCert = defaultCACert
8388 }
8489
85- return NewProviderScope (cloud , caCert , logger )
90+ return NewCachedProviderScope (f .cache , cloud , caCert , logger )
91+ }
92+
93+ func getScopeCacheKey (cloud clientconfig.Cloud ) (string , error ) {
94+ key , err := hash .ComputeSpewHash (cloud )
95+ if err != nil {
96+ return "" , err
97+ }
98+
99+ return fmt .Sprintf ("%d" , key ), nil
86100}
87101
88102type providerScope struct {
@@ -106,6 +120,34 @@ func NewProviderScope(cloud clientconfig.Cloud, caCert []byte, logger logr.Logge
106120 }, nil
107121}
108122
123+ func NewCachedProviderScope (cache * cache.LRUExpireCache , cloud clientconfig.Cloud , caCert []byte , logger logr.Logger ) (Scope , error ) {
124+ key , err := getScopeCacheKey (cloud )
125+ if err != nil {
126+ return nil , fmt .Errorf ("can't compute cloud config cache key: %w" , err )
127+ }
128+
129+ if scope , found := cache .Get (key ); found {
130+ logger .V (6 ).Info ("Using scope from cache" )
131+ return scope .(Scope ), nil
132+ }
133+
134+ scope , err := NewProviderScope (cloud , caCert , logger )
135+ if err != nil {
136+ return nil , err
137+ }
138+
139+ token , err := scope .ExtractToken ()
140+ if err != nil {
141+ return nil , err
142+ }
143+
144+ // compute the token expiration time
145+ expiry := time .Until (token .ExpiresAt ) / 2
146+
147+ cache .Add (key , scope , expiry )
148+ return scope , nil
149+ }
150+
109151func (s * providerScope ) Logger () logr.Logger {
110152 return s .logger
111153}
@@ -134,6 +176,14 @@ func (s *providerScope) NewLbClient() (clients.LbClient, error) {
134176 return clients .NewLbClient (s .providerClient , s .providerClientOpts )
135177}
136178
179+ func (s * providerScope ) ExtractToken () (* tokens.Token , error ) {
180+ client , err := openstack .NewIdentityV3 (s .providerClient , gophercloud.EndpointOpts {})
181+ if err != nil {
182+ return nil , fmt .Errorf ("can't create a new identity service client: %w" , err )
183+ }
184+ return tokens .Get (client , s .providerClient .Token ()).ExtractToken ()
185+ }
186+
137187func NewProviderClient (cloud clientconfig.Cloud , caCert []byte , logger logr.Logger ) (* gophercloud.ProviderClient , * clientconfig.ClientOpts , string , error ) {
138188 clientOpts := new (clientconfig.ClientOpts )
139189 if cloud .AuthInfo != nil {
0 commit comments