Skip to content

Commit a7a1898

Browse files
author
ykwang
committed
fix panic for lazy dynamicRESTMapper
1 parent 67d2efd commit a7a1898

3 files changed

Lines changed: 55 additions & 30 deletions

File tree

pkg/client/apiutil/apiutil_suite_test.go

Lines changed: 1 addition & 1 deletion
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

Lines changed: 14 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,9 @@
1-
/*
2-
Copyright 2019 The Kubernetes Authors.
3-
4-
Licensed under the Apache License, Version 2.0 (the "License");
5-
you may not use this file except in compliance with the License.
6-
You may obtain a copy of the License at
7-
8-
http://www.apache.org/licenses/LICENSE-2.0
9-
10-
Unless required by applicable law or agreed to in writing, software
11-
distributed under the License is distributed on an "AS IS" BASIS,
12-
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13-
See the License for the specific language governing permissions and
14-
limitations under the License.
15-
*/
16-
171
package apiutil
182

193
import (
204
"errors"
215
"sync"
6+
"sync/atomic"
227

238
"golang.org/x/time/rate"
249
"k8s.io/apimachinery/pkg/api/meta"
@@ -38,7 +23,8 @@ type dynamicRESTMapper struct {
3823

3924
lazy bool
4025
// Used for lazy init.
41-
initOnce sync.Once
26+
inited uint32
27+
initMtx sync.Mutex
4228
}
4329

4430
// DynamicRESTMapperOption is a functional option on the dynamicRESTMapper
@@ -125,11 +111,18 @@ func (drm *dynamicRESTMapper) setStaticMapper() error {
125111

126112
// init initializes drm only once if drm is lazy.
127113
func (drm *dynamicRESTMapper) init() (err error) {
128-
drm.initOnce.Do(func() {
129-
if drm.lazy {
130-
err = drm.setStaticMapper()
114+
// skip init if drm is not lazy or has initialized
115+
if !drm.lazy || atomic.LoadUint32(&drm.inited) != 0 {
116+
return nil
117+
}
118+
119+
drm.initMtx.Lock()
120+
defer drm.initMtx.Unlock()
121+
if drm.inited == 0 {
122+
if err = drm.setStaticMapper(); err == nil {
123+
atomic.StoreUint32(&drm.inited, 1)
131124
}
132-
})
125+
}
133126
return err
134127
}
135128

pkg/client/apiutil/dynamicrestmapper_test.go

Lines changed: 40 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,23 @@
1-
package apiutil_test
1+
/*
2+
Copyright 2021 The Kubernetes Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package apiutil
218

319
import (
20+
"fmt"
421
"time"
522

623
. "github.com/onsi/ginkgo"
@@ -10,8 +27,6 @@ import (
1027
"golang.org/x/time/rate"
1128
"k8s.io/apimachinery/pkg/api/meta"
1229
"k8s.io/apimachinery/pkg/runtime/schema"
13-
14-
"sigs.k8s.io/controller-runtime/pkg/client/apiutil"
1530
)
1631

1732
var (
@@ -36,7 +51,7 @@ var _ = Describe("Dynamic REST Mapper", func() {
3651
}
3752

3853
lim = rate.NewLimiter(rate.Limit(5), 5)
39-
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) {
4055
baseMapper := meta.NewDefaultRESTMapper(nil)
4156
addToMapper(baseMapper)
4257

@@ -130,11 +145,28 @@ var _ = Describe("Dynamic REST Mapper", func() {
130145
By("ensuring that it was only refreshed once")
131146
Expect(count).To(Equal(1))
132147
})
133-
}
134148

135-
PIt("should lazily initialize if the lazy option is used", func() {
136-
137-
})
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+
}
138170

139171
Describe("KindFor", func() {
140172
mapperTest(func() error {

0 commit comments

Comments
 (0)