19
19
package certprovider
20
20
21
21
import (
22
+ "context"
22
23
"fmt"
23
24
"sync"
25
+ "sync/atomic"
24
26
)
25
27
26
28
// provStore is the global singleton certificate provider store.
@@ -53,6 +55,22 @@ type wrappedProvider struct {
53
55
store * store
54
56
}
55
57
58
+ // closedProvider always returns errProviderClosed error.
59
+ type closedProvider struct {}
60
+
61
+ func (c closedProvider ) KeyMaterial (ctx context.Context ) (* KeyMaterial , error ) {
62
+ return nil , errProviderClosed
63
+ }
64
+
65
+ func (c closedProvider ) Close () {
66
+ }
67
+
68
+ // singleCloseWrappedProvider wraps a provider instance with a reference count
69
+ // to properly handle multiple calls to Close.
70
+ type singleCloseWrappedProvider struct {
71
+ provider atomic.Pointer [Provider ]
72
+ }
73
+
56
74
// store is a collection of provider instances, safe for concurrent access.
57
75
type store struct {
58
76
mu sync.Mutex
@@ -75,6 +93,28 @@ func (wp *wrappedProvider) Close() {
75
93
}
76
94
}
77
95
96
+ // Close overrides the Close method of the embedded provider to avoid release the
97
+ // already released reference.
98
+ func (w * singleCloseWrappedProvider ) Close () {
99
+ newProvider := Provider (closedProvider {})
100
+ oldProvider := w .provider .Swap (& newProvider )
101
+ (* oldProvider ).Close ()
102
+ }
103
+
104
+ // KeyMaterial returns the key material sourced by the Provider.
105
+ // Callers are expected to use the returned value as read-only.
106
+ func (w * singleCloseWrappedProvider ) KeyMaterial (ctx context.Context ) (* KeyMaterial , error ) {
107
+ return (* w .provider .Load ()).KeyMaterial (ctx )
108
+ }
109
+
110
+ // newSingleCloseWrappedProvider create wrapper a provider instance with a reference count
111
+ // to properly handle multiple calls to Close.
112
+ func newSingleCloseWrappedProvider (provider Provider ) * singleCloseWrappedProvider {
113
+ w := & singleCloseWrappedProvider {}
114
+ w .provider .Store (& provider )
115
+ return w
116
+ }
117
+
78
118
// BuildableConfig wraps parsed provider configuration and functionality to
79
119
// instantiate provider instances.
80
120
type BuildableConfig struct {
@@ -112,7 +152,7 @@ func (bc *BuildableConfig) Build(opts BuildOptions) (Provider, error) {
112
152
}
113
153
if wp , ok := provStore .providers [sk ]; ok {
114
154
wp .refCount ++
115
- return wp , nil
155
+ return newSingleCloseWrappedProvider ( wp ) , nil
116
156
}
117
157
118
158
provider := bc .starter (opts )
@@ -126,7 +166,7 @@ func (bc *BuildableConfig) Build(opts BuildOptions) (Provider, error) {
126
166
store : provStore ,
127
167
}
128
168
provStore .providers [sk ] = wp
129
- return wp , nil
169
+ return newSingleCloseWrappedProvider ( wp ) , nil
130
170
}
131
171
132
172
// String returns the provider name and config as a colon separated string.
0 commit comments