@@ -24,6 +24,7 @@ import (
24
24
25
25
"github.com/go-openapi/spec"
26
26
"k8s.io/apimachinery/pkg/api/errors"
27
+ "k8s.io/apimachinery/pkg/labels"
27
28
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
28
29
"k8s.io/apimachinery/pkg/util/wait"
29
30
"k8s.io/client-go/tools/cache"
@@ -89,6 +90,29 @@ func (c *Controller) Run(staticSpec *spec.Swagger, openAPIService *handler.OpenA
89
90
return
90
91
}
91
92
93
+ // create initial spec to avoid merging once per CRD on startup
94
+ crds , err := c .crdLister .List (labels .Everything ())
95
+ if err != nil {
96
+ utilruntime .HandleError (fmt .Errorf ("failed to initially list all CRDs: %v" , err ))
97
+ return
98
+ }
99
+ for _ , crd := range crds {
100
+ if ! apiextensions .IsCRDConditionTrue (crd , apiextensions .Established ) {
101
+ continue
102
+ }
103
+ newSpecs , changed , err := buildVersionSpecs (crd , nil )
104
+ if err != nil {
105
+ utilruntime .HandleError (fmt .Errorf ("failed to build OpenAPI spec of CRD %s: %v" , crd .Name , err ))
106
+ } else if ! changed {
107
+ continue
108
+ }
109
+ c .crdSpecs [crd .Name ] = newSpecs
110
+ }
111
+ if err := c .updateSpecLocked (); err != nil {
112
+ utilruntime .HandleError (fmt .Errorf ("failed to initially create OpenAPI spec for CRDs: %v" , err ))
113
+ return
114
+ }
115
+
92
116
// only start one worker thread since its a slow moving API
93
117
go wait .Until (c .runWorker , time .Second , stopCh )
94
118
@@ -147,6 +171,20 @@ func (c *Controller) sync(name string) error {
147
171
148
172
// compute CRD spec and see whether it changed
149
173
oldSpecs := c .crdSpecs [crd .Name ]
174
+ newSpecs , changed , err := buildVersionSpecs (crd , oldSpecs )
175
+ if err != nil {
176
+ return err
177
+ }
178
+ if ! changed {
179
+ return nil
180
+ }
181
+
182
+ // update specs of this CRD
183
+ c .crdSpecs [crd .Name ] = newSpecs
184
+ return c .updateSpecLocked ()
185
+ }
186
+
187
+ func buildVersionSpecs (crd * apiextensions.CustomResourceDefinition , oldSpecs map [string ]* spec.Swagger ) (map [string ]* spec.Swagger , bool , error ) {
150
188
newSpecs := map [string ]* spec.Swagger {}
151
189
anyChanged := false
152
190
for _ , v := range crd .Spec .Versions {
@@ -155,20 +193,18 @@ func (c *Controller) sync(name string) error {
155
193
}
156
194
spec , err := BuildSwagger (crd , v .Name )
157
195
if err != nil {
158
- return err
196
+ return nil , false , err
159
197
}
160
198
newSpecs [v .Name ] = spec
161
199
if oldSpecs [v .Name ] == nil || ! reflect .DeepEqual (oldSpecs [v .Name ], spec ) {
162
200
anyChanged = true
163
201
}
164
202
}
165
203
if ! anyChanged && len (oldSpecs ) == len (newSpecs ) {
166
- return nil
204
+ return newSpecs , false , nil
167
205
}
168
206
169
- // update specs of this CRD
170
- c .crdSpecs [crd .Name ] = newSpecs
171
- return c .updateSpecLocked ()
207
+ return newSpecs , true , nil
172
208
}
173
209
174
210
// updateSpecLocked aggregates all OpenAPI specs and updates openAPIService.
0 commit comments