Skip to content

Commit 26c95ad

Browse files
authored
Merge pull request #1891 from FillZpp/fix-panic-for-lazy-dynamicRESTMapper
🐛 Fix panic for lazy dynamicRESTMapper
2 parents 5d08242 + 04f281d commit 26c95ad

File tree

3 files changed

+39
-14
lines changed

3 files changed

+39
-14
lines changed

pkg/client/apiutil/apiutil_suite_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
1414
limitations under the License.
1515
*/
1616

17-
package apiutil_test
17+
package apiutil
1818

1919
import (
2020
"testing"

pkg/client/apiutil/dynamicrestmapper.go

+14-5
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ package apiutil
1919
import (
2020
"errors"
2121
"sync"
22+
"sync/atomic"
2223

2324
"golang.org/x/time/rate"
2425
"k8s.io/apimachinery/pkg/api/meta"
@@ -38,7 +39,8 @@ type dynamicRESTMapper struct {
3839

3940
lazy bool
4041
// Used for lazy init.
41-
initOnce sync.Once
42+
inited uint32
43+
initMtx sync.Mutex
4244
}
4345

4446
// DynamicRESTMapperOption is a functional option on the dynamicRESTMapper.
@@ -125,11 +127,18 @@ func (drm *dynamicRESTMapper) setStaticMapper() error {
125127

126128
// init initializes drm only once if drm is lazy.
127129
func (drm *dynamicRESTMapper) init() (err error) {
128-
drm.initOnce.Do(func() {
129-
if drm.lazy {
130-
err = drm.setStaticMapper()
130+
// skip init if drm is not lazy or has initialized
131+
if !drm.lazy || atomic.LoadUint32(&drm.inited) != 0 {
132+
return nil
133+
}
134+
135+
drm.initMtx.Lock()
136+
defer drm.initMtx.Unlock()
137+
if drm.inited == 0 {
138+
if err = drm.setStaticMapper(); err == nil {
139+
atomic.StoreUint32(&drm.inited, 1)
131140
}
132-
})
141+
}
133142
return err
134143
}
135144

pkg/client/apiutil/dynamicrestmapper_test.go

+24-8
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,10 @@ See the License for the specific language governing permissions and
1414
limitations under the License.
1515
*/
1616

17-
package apiutil_test
17+
package apiutil
1818

1919
import (
20+
"fmt"
2021
"time"
2122

2223
. "github.com/onsi/ginkgo"
@@ -26,8 +27,6 @@ import (
2627
"golang.org/x/time/rate"
2728
"k8s.io/apimachinery/pkg/api/meta"
2829
"k8s.io/apimachinery/pkg/runtime/schema"
29-
30-
"sigs.k8s.io/controller-runtime/pkg/client/apiutil"
3130
)
3231

3332
var (
@@ -52,7 +51,7 @@ var _ = Describe("Dynamic REST Mapper", func() {
5251
}
5352

5453
lim = rate.NewLimiter(rate.Limit(5), 5)
55-
mapper, err = apiutil.NewDynamicRESTMapper(cfg, apiutil.WithLimiter(lim), apiutil.WithCustomMapper(func() (meta.RESTMapper, error) {
54+
mapper, err = NewDynamicRESTMapper(cfg, WithLimiter(lim), WithCustomMapper(func() (meta.RESTMapper, error) {
5655
baseMapper := meta.NewDefaultRESTMapper(nil)
5756
addToMapper(baseMapper)
5857

@@ -146,11 +145,28 @@ var _ = Describe("Dynamic REST Mapper", func() {
146145
By("ensuring that it was only refreshed once")
147146
Expect(count).To(Equal(1))
148147
})
149-
}
150148

151-
PIt("should lazily initialize if the lazy option is used", func() {
152-
153-
})
149+
It("should lazily initialize if the lazy option is used", func() {
150+
var err error
151+
var failedOnce bool
152+
mockErr := fmt.Errorf("mock failed once")
153+
mapper, err = NewDynamicRESTMapper(cfg, WithLazyDiscovery, WithCustomMapper(func() (meta.RESTMapper, error) {
154+
// Make newMapper fail once
155+
if !failedOnce {
156+
failedOnce = true
157+
return nil, mockErr
158+
}
159+
baseMapper := meta.NewDefaultRESTMapper(nil)
160+
addToMapper(baseMapper)
161+
return baseMapper, nil
162+
}))
163+
Expect(err).NotTo(HaveOccurred())
164+
Expect(mapper.(*dynamicRESTMapper).staticMapper).To(BeNil())
165+
166+
Expect(callWithTarget()).To(MatchError(mockErr))
167+
Expect(callWithTarget()).To(Succeed())
168+
})
169+
}
154170

155171
Describe("KindFor", func() {
156172
mapperTest(func() error {

0 commit comments

Comments
 (0)