diff --git a/staging/src/k8s.io/apiextensions-apiserver/pkg/controller/openapi/BUILD b/staging/src/k8s.io/apiextensions-apiserver/pkg/controller/openapi/BUILD index 38b71df1d00..8f750597808 100644 --- a/staging/src/k8s.io/apiextensions-apiserver/pkg/controller/openapi/BUILD +++ b/staging/src/k8s.io/apiextensions-apiserver/pkg/controller/openapi/BUILD @@ -21,6 +21,7 @@ go_library( "//staging/src/k8s.io/apimachinery/pkg/api/errors:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1beta1:go_default_library", + "//staging/src/k8s.io/apimachinery/pkg/labels:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/util/runtime:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/util/wait:go_default_library", diff --git a/staging/src/k8s.io/apiextensions-apiserver/pkg/controller/openapi/controller.go b/staging/src/k8s.io/apiextensions-apiserver/pkg/controller/openapi/controller.go index 0e083f9c18b..4d5e9ed5359 100644 --- a/staging/src/k8s.io/apiextensions-apiserver/pkg/controller/openapi/controller.go +++ b/staging/src/k8s.io/apiextensions-apiserver/pkg/controller/openapi/controller.go @@ -24,6 +24,7 @@ import ( "github.com/go-openapi/spec" "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/labels" utilruntime "k8s.io/apimachinery/pkg/util/runtime" "k8s.io/apimachinery/pkg/util/wait" "k8s.io/client-go/tools/cache" @@ -89,6 +90,29 @@ func (c *Controller) Run(staticSpec *spec.Swagger, openAPIService *handler.OpenA return } + // create initial spec to avoid merging once per CRD on startup + crds, err := c.crdLister.List(labels.Everything()) + if err != nil { + utilruntime.HandleError(fmt.Errorf("failed to initially list all CRDs: %v", err)) + return + } + for _, crd := range crds { + if !apiextensions.IsCRDConditionTrue(crd, apiextensions.Established) { + continue + } + newSpecs, changed, err := buildVersionSpecs(crd, nil) + if err != nil { + utilruntime.HandleError(fmt.Errorf("failed to build OpenAPI spec of CRD %s: %v", crd.Name, err)) + } else if !changed { + continue + } + c.crdSpecs[crd.Name] = newSpecs + } + if err := c.updateSpecLocked(); err != nil { + utilruntime.HandleError(fmt.Errorf("failed to initially create OpenAPI spec for CRDs: %v", err)) + return + } + // only start one worker thread since its a slow moving API go wait.Until(c.runWorker, time.Second, stopCh) @@ -147,6 +171,20 @@ func (c *Controller) sync(name string) error { // compute CRD spec and see whether it changed oldSpecs := c.crdSpecs[crd.Name] + newSpecs, changed, err := buildVersionSpecs(crd, oldSpecs) + if err != nil { + return err + } + if !changed { + return nil + } + + // update specs of this CRD + c.crdSpecs[crd.Name] = newSpecs + return c.updateSpecLocked() +} + +func buildVersionSpecs(crd *apiextensions.CustomResourceDefinition, oldSpecs map[string]*spec.Swagger) (map[string]*spec.Swagger, bool, error) { newSpecs := map[string]*spec.Swagger{} anyChanged := false for _, v := range crd.Spec.Versions { @@ -155,7 +193,7 @@ func (c *Controller) sync(name string) error { } spec, err := BuildSwagger(crd, v.Name) if err != nil { - return err + return nil, false, err } newSpecs[v.Name] = spec if oldSpecs[v.Name] == nil || !reflect.DeepEqual(oldSpecs[v.Name], spec) { @@ -163,12 +201,10 @@ func (c *Controller) sync(name string) error { } } if !anyChanged && len(oldSpecs) == len(newSpecs) { - return nil + return newSpecs, false, nil } - // update specs of this CRD - c.crdSpecs[crd.Name] = newSpecs - return c.updateSpecLocked() + return newSpecs, true, nil } // updateSpecLocked aggregates all OpenAPI specs and updates openAPIService.