client-set: use clientset internal scheme

This commit is contained in:
Dr. Stefan Schimanski 2017-02-19 15:05:24 +01:00
parent 49c536baee
commit 92c36bed4a
9 changed files with 307 additions and 126 deletions

View File

@ -85,11 +85,12 @@ func packageForGroup(gv clientgentypes.GroupVersion, typeList []*types.Type, cli
DefaultGen: generator.DefaultGen{
OptionalName: strings.ToLower(c.Namers["private"].Name(t)),
},
outputPackage: groupVersionClientPackage,
group: gv.Group.NonEmpty(),
version: gv.Version.String(),
typeToMatch: t,
imports: generator.NewImportTracker(),
outputPackage: groupVersionClientPackage,
clientsetPackage: clientsetPackage,
group: gv.Group.NonEmpty(),
version: gv.Version.String(),
typeToMatch: t,
imports: generator.NewImportTracker(),
})
}
@ -97,13 +98,14 @@ func packageForGroup(gv clientgentypes.GroupVersion, typeList []*types.Type, cli
DefaultGen: generator.DefaultGen{
OptionalName: gv.Group.NonEmpty() + "_client",
},
outputPackage: groupVersionClientPackage,
inputPackage: inputPackage,
group: gv.Group.NonEmpty(),
version: gv.Version.String(),
apiPath: apiPath,
types: typeList,
imports: generator.NewImportTracker(),
outputPackage: groupVersionClientPackage,
inputPackage: inputPackage,
clientsetPackage: clientsetPackage,
group: gv.Group.NonEmpty(),
version: gv.Version.String(),
apiPath: apiPath,
types: typeList,
imports: generator.NewImportTracker(),
})
expansionFileName := "generated_expansion"
@ -154,6 +156,39 @@ func packageForClientset(customArgs clientgenargs.Args, clientsetPackage string,
}
}
func packageForScheme(customArgs clientgenargs.Args, clientsetPackage string, srcTreePath string, boilerplate []byte, generatedBy string) generator.Package {
schemePackage := filepath.Join(clientsetPackage, "scheme")
return &generator.DefaultPackage{
PackageName: "scheme",
PackagePath: schemePackage,
HeaderText: boilerplate,
PackageDocumentation: []byte(
generatedBy +
`// This package contains the scheme of the automatically generated clientset.
`),
// GeneratorFunc returns a list of generators. Each generator generates a
// single file.
GeneratorFunc: func(c *generator.Context) (generators []generator.Generator) {
generators = []generator.Generator{
// Always generate a "doc.go" file.
generator.DefaultGen{OptionalName: "doc"},
&genScheme{
DefaultGen: generator.DefaultGen{
OptionalName: "register",
},
inputPackages: customArgs.GroupVersionToInputPath,
outputPackage: schemePackage,
outputPath: filepath.Join(srcTreePath, schemePackage),
groups: customArgs.Groups,
imports: generator.NewImportTracker(),
},
}
return generators
},
}
}
// Packages makes the client package definition.
func Packages(context *generator.Context, arguments *args.GeneratorArgs) generator.Packages {
boilerplate, err := arguments.LoadGoBoilerplate()
@ -204,6 +239,7 @@ func Packages(context *generator.Context, arguments *args.GeneratorArgs) generat
clientsetPackage := filepath.Join(customArgs.ClientsetOutputPath, customArgs.ClientsetName)
packageList = append(packageList, packageForClientset(customArgs, clientsetPackage, boilerplate, generatedBy))
packageList = append(packageList, packageForScheme(customArgs, clientsetPackage, arguments.OutputBase, boilerplate, generatedBy))
if customArgs.FakeClient {
packageList = append(packageList, fake.PackageForClientset(customArgs, clientsetPackage, boilerplate, generatedBy))
}

View File

@ -18,6 +18,7 @@ package generators
import (
"io"
"path/filepath"
"k8s.io/gengo/generator"
"k8s.io/gengo/namer"
@ -32,9 +33,10 @@ type genGroup struct {
version string
apiPath string
// types in this group
types []*types.Type
imports namer.ImportTracker
inputPackage string
types []*types.Type
imports namer.ImportTracker
inputPackage string
clientsetPackage string
}
var _ generator.Generator = &genGroup{}
@ -52,6 +54,7 @@ func (g *genGroup) Namers(c *generator.Context) namer.NameSystems {
func (g *genGroup) Imports(c *generator.Context) (imports []string) {
imports = append(imports, g.imports.ImportLines()...)
imports = append(imports, filepath.Join(g.clientsetPackage, "scheme"))
return
}
@ -85,17 +88,14 @@ func (g *genGroup) GenerateType(c *generator.Context, t *types.Type, w io.Writer
"groupName": groupName,
"types": g.types,
"apiPath": apiPath(g.group),
"fmtErrorf": c.Universe.Function(types.Name{Package: "fmt", Name: "Errorf"}),
"runtimeAPIVersionInternal": c.Universe.Variable(types.Name{Package: "k8s.io/apimachinery/pkg/runtime", Name: "APIVersionInternal"}),
"schemaGroupVersion": c.Universe.Type(types.Name{Package: "k8s.io/apimachinery/pkg/runtime/schema", Name: "GroupVersion"}),
"schemaParseGroupVersion": c.Universe.Function(types.Name{Package: "k8s.io/apimachinery/pkg/runtime/schema", Name: "ParseGroupVersion"}),
"runtimeAPIVersionInternal": c.Universe.Variable(types.Name{Package: "k8s.io/apimachinery/pkg/runtime", Name: "APIVersionInternal"}),
"serializerDirectCodecFactory": c.Universe.Type(types.Name{Package: "k8s.io/apimachinery/pkg/runtime/serializer", Name: "DirectCodecFactory"}),
"restConfig": c.Universe.Type(types.Name{Package: "k8s.io/client-go/rest", Name: "Config"}),
"restDefaultKubernetesUserAgent": c.Universe.Function(types.Name{Package: "k8s.io/client-go/rest", Name: "DefaultKubernetesUserAgent"}),
"restRESTClientInterface": c.Universe.Type(types.Name{Package: "k8s.io/client-go/rest", Name: "Interface"}),
"restRESTClientFor": c.Universe.Function(types.Name{Package: "k8s.io/client-go/rest", Name: "RESTClientFor"}),
"apiCodecs": c.Universe.Variable(types.Name{Package: "k8s.io/kubernetes/pkg/api", Name: "Codecs"}),
"apiRegistry": c.Universe.Variable(types.Name{Package: "k8s.io/kubernetes/pkg/api", Name: "Registry"}),
"SchemeGroupVersion": c.Universe.Variable(types.Name{Package: g.inputPackage, Name: "SchemeGroupVersion"}),
}
sw.Do(groupInterfaceTemplate, m)
sw.Do(groupClientTemplate, m)
@ -198,8 +198,7 @@ func New(c $.restRESTClientInterface|raw$) *$.GroupVersion$Client {
var setInternalVersionClientDefaultsTemplate = `
func setConfigDefaults(config *$.restConfig|raw$) error {
// if $.group$ group is not registered, return an error
g, err := $.apiRegistry|raw$.Group("$.groupName$")
g, err := scheme.Registry.Group("$.groupName$")
if err != nil {
return err
}
@ -209,10 +208,10 @@ func setConfigDefaults(config *$.restConfig|raw$) error {
config.UserAgent = $.restDefaultKubernetesUserAgent|raw$()
}
if config.GroupVersion == nil || config.GroupVersion.Group != g.GroupVersion.Group {
copyGroupVersion := g.GroupVersion
config.GroupVersion = &copyGroupVersion
gv := g.GroupVersion
config.GroupVersion = &gv
}
config.NegotiatedSerializer = $.apiCodecs|raw$
config.NegotiatedSerializer = scheme.Codecs
if config.QPS == 0 {
config.QPS = 5
@ -227,22 +226,14 @@ func setConfigDefaults(config *$.restConfig|raw$) error {
var setClientDefaultsTemplate = `
func setConfigDefaults(config *$.restConfig|raw$) error {
gv, err := $.schemaParseGroupVersion|raw$("$.groupName$/$.version$")
if err != nil {
return err
}
// if $.groupName$/$.version$ is not enabled, return an error
if ! $.apiRegistry|raw$.IsEnabledVersion(gv) {
return $.fmtErrorf|raw$("$.groupName$/$.version$ is not enabled")
}
gv := $.SchemeGroupVersion|raw$
config.GroupVersion = &gv
config.APIPath = $.apiPath$
config.NegotiatedSerializer = $.serializerDirectCodecFactory|raw${CodecFactory: scheme.Codecs}
if config.UserAgent == "" {
config.UserAgent = $.restDefaultKubernetesUserAgent|raw$()
}
copyGroupVersion := gv
config.GroupVersion = &copyGroupVersion
config.NegotiatedSerializer = $.serializerDirectCodecFactory|raw${CodecFactory: $.apiCodecs|raw$}
return nil
}

View File

@ -0,0 +1,175 @@
/*
Copyright 2017 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package generators
import (
"fmt"
"io"
"os"
"path/filepath"
"strings"
"k8s.io/gengo/generator"
"k8s.io/gengo/namer"
"k8s.io/gengo/types"
clientgentypes "k8s.io/kubernetes/cmd/libs/go2idl/client-gen/types"
)
// genScheme produces a package for a clientset with the scheme, codecs and parameter codecs.
type genScheme struct {
generator.DefaultGen
outputPackage string
groups []clientgentypes.GroupVersions
inputPackages map[clientgentypes.GroupVersion]string
outputPath string
imports namer.ImportTracker
schemeGenerated bool
}
func (g *genScheme) Namers(c *generator.Context) namer.NameSystems {
return namer.NameSystems{
"raw": namer.NewRawNamer(g.outputPackage, g.imports),
}
}
// We only want to call GenerateType() once.
func (g *genScheme) Filter(c *generator.Context, t *types.Type) bool {
ret := !g.schemeGenerated
g.schemeGenerated = true
return ret
}
func (g *genScheme) Imports(c *generator.Context) (imports []string) {
imports = append(imports, g.imports.ImportLines()...)
internal := g.internalClientset()
for _, group := range g.groups {
for _, version := range group.Versions {
packagePath := g.inputPackages[clientgentypes.GroupVersion{Group: group.Group, Version: version}]
if internal {
// import the install package for internal clientsets instead of the type package with register.go
if version != "" {
packagePath = filepath.Dir(packagePath)
}
packagePath = filepath.Join(packagePath, "install")
imports = append(imports, strings.ToLower(fmt.Sprintf("%s \"%s\"", group.Group.NonEmpty(), packagePath)))
break
} else {
imports = append(imports, strings.ToLower(fmt.Sprintf("%s%s \"%s\"", group.Group.NonEmpty(), version.NonEmpty(), packagePath)))
}
}
}
return
}
func (g *genScheme) GenerateType(c *generator.Context, t *types.Type, w io.Writer) error {
sw := generator.NewSnippetWriter(w, c, "$", "$")
allGroupVersions := clientgentypes.ToGroupVersionPackages(g.groups)
allInstallGroups := clientgentypes.ToGroupInstallPackages(g.groups)
m := map[string]interface{}{
"allGroupVersions": allGroupVersions,
"allInstallGroups": allInstallGroups,
"customRegister": false,
"osGetenv": c.Universe.Function(types.Name{Package: "os", Name: "Getenv"}),
"runtimeNewParameterCodec": c.Universe.Function(types.Name{Package: "k8s.io/apimachinery/pkg/runtime", Name: "NewParameterCodec"}),
"runtimeNewScheme": c.Universe.Function(types.Name{Package: "k8s.io/apimachinery/pkg/runtime", Name: "NewScheme"}),
"serializerNewCodecFactory": c.Universe.Function(types.Name{Package: "k8s.io/apimachinery/pkg/runtime/serializer", Name: "NewCodecFactory"}),
"runtimeScheme": c.Universe.Type(types.Name{Package: "k8s.io/apimachinery/pkg/runtime", Name: "Scheme"}),
"schemaGroupVersion": c.Universe.Type(types.Name{Package: "k8s.io/apimachinery/pkg/runtime/schema", Name: "GroupVersion"}),
"metav1AddToGroupVersion": c.Universe.Function(types.Name{Package: "k8s.io/apimachinery/pkg/apis/meta/v1", Name: "AddToGroupVersion"}),
"announcedAPIGroupFactoryRegistry": c.Universe.Type(types.Name{Package: "k8s.io/apimachinery/pkg/apimachinery/announced", Name: "APIGroupFactoryRegistry"}),
"registeredNewOrDie": c.Universe.Function(types.Name{Package: "k8s.io/apimachinery/pkg/apimachinery/registered", Name: "NewOrDie"}),
"registeredAPIRegistrationManager": c.Universe.Type(types.Name{Package: "k8s.io/apimachinery/pkg/apimachinery/registered", Name: "APIRegistrationManager"}),
}
sw.Do(globalsTemplate, m)
if _, err := os.Stat(filepath.Join(g.outputPath, strings.ToLower("register_custom.go"))); err == nil {
m["customRegister"] = true
}
if g.internalClientset() {
sw.Do(internalRegistration, m)
} else {
sw.Do(registration, m)
}
return sw.Error()
}
func (g *genScheme) internalClientset() bool {
for _, group := range g.groups {
for _, v := range group.Versions {
if v == "" {
return true
}
}
}
return false
}
var globalsTemplate = `
var Scheme = $.runtimeNewScheme|raw$()
var Codecs = $.serializerNewCodecFactory|raw$(Scheme)
var ParameterCodec = $.runtimeNewParameterCodec|raw$(Scheme)
`
var internalRegistration = `
var Registry = $.registeredNewOrDie|raw$($.osGetenv|raw$("KUBE_API_VERSIONS"))
var GroupFactoryRegistry = make($.announcedAPIGroupFactoryRegistry|raw$)
func init() {
$.metav1AddToGroupVersion|raw$(Scheme, $.schemaGroupVersion|raw${Version: "v1"})
Install(GroupFactoryRegistry, Registry, Scheme)
}
// Install registers the API group and adds types to a scheme
func Install(groupFactoryRegistry $.announcedAPIGroupFactoryRegistry|raw$, registry *$.registeredAPIRegistrationManager|raw$, scheme *$.runtimeScheme|raw$) {
$range .allInstallGroups$ $.InstallPackageName$.Install(groupFactoryRegistry, registry, scheme)
$end$
$if .customRegister$ExtraInstall(groupFactoryRegistry, registry, scheme)$end$
}
`
var registration = `
func init() {
$.metav1AddToGroupVersion|raw$(Scheme, $.schemaGroupVersion|raw${Version: "v1"})
AddToScheme(Scheme)
}
// AddToScheme adds all types of this clientset into the given scheme. This allows composition
// of clientsets, like in:
//
// import (
// "k8s.io/client-go/kubernetes"
// clientsetscheme "k8s.io/client-go/kuberentes/scheme"
// aggregatorclientsetscheme "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/scheme"
// )
//
// kclientset, _ := kubernetes.NewForConfig(c)
// aggregatorclientsetscheme.AddToScheme(clientsetscheme.Scheme)
//
// After this, RawExtensions in Kubernetes types will serialize kube-aggregator types
// correctly.
func AddToScheme(scheme *$.runtimeScheme|raw$) {
$range .allGroupVersions$ $.PackageName$.AddToScheme(scheme)
$end$
$if .customRegister$ExtraAddToScheme(scheme)$end$
}
`

View File

@ -29,11 +29,12 @@ import (
// genClientForType produces a file for each top-level type.
type genClientForType struct {
generator.DefaultGen
outputPackage string
group string
version string
typeToMatch *types.Type
imports namer.ImportTracker
outputPackage string
clientsetPackage string
group string
version string
typeToMatch *types.Type
imports namer.ImportTracker
}
var _ generator.Generator = &genClientForType{}
@ -78,19 +79,19 @@ func (g *genClientForType) GenerateType(c *generator.Context, t *types.Type, w i
pkg := filepath.Base(t.Name.Package)
namespaced := !extractBoolTagOrDie("nonNamespaced", t.SecondClosestCommentLines)
m := map[string]interface{}{
"type": t,
"package": pkg,
"Package": namer.IC(pkg),
"namespaced": namespaced,
"Group": namer.IC(g.group),
"GroupVersion": namer.IC(g.group) + namer.IC(g.version),
"DeleteOptions": c.Universe.Type(types.Name{Package: "k8s.io/apimachinery/pkg/apis/meta/v1", Name: "DeleteOptions"}),
"ListOptions": c.Universe.Type(types.Name{Package: "k8s.io/apimachinery/pkg/apis/meta/v1", Name: "ListOptions"}),
"GetOptions": c.Universe.Type(types.Name{Package: "k8s.io/apimachinery/pkg/apis/meta/v1", Name: "GetOptions"}),
"PatchType": c.Universe.Type(types.Name{Package: "k8s.io/apimachinery/pkg/types", Name: "PatchType"}),
"watchInterface": c.Universe.Type(types.Name{Package: "k8s.io/apimachinery/pkg/watch", Name: "Interface"}),
"RESTClientInterface": c.Universe.Type(types.Name{Package: "k8s.io/client-go/rest", Name: "Interface"}),
"apiParameterCodec": c.Universe.Type(types.Name{Package: "k8s.io/kubernetes/pkg/api", Name: "ParameterCodec"}),
"type": t,
"package": pkg,
"Package": namer.IC(pkg),
"namespaced": namespaced,
"Group": namer.IC(g.group),
"GroupVersion": namer.IC(g.group) + namer.IC(g.version),
"DeleteOptions": c.Universe.Type(types.Name{Package: "k8s.io/apimachinery/pkg/apis/meta/v1", Name: "DeleteOptions"}),
"ListOptions": c.Universe.Type(types.Name{Package: "k8s.io/apimachinery/pkg/apis/meta/v1", Name: "ListOptions"}),
"GetOptions": c.Universe.Type(types.Name{Package: "k8s.io/apimachinery/pkg/apis/meta/v1", Name: "GetOptions"}),
"PatchType": c.Universe.Type(types.Name{Package: "k8s.io/apimachinery/pkg/types", Name: "PatchType"}),
"watchInterface": c.Universe.Type(types.Name{Package: "k8s.io/apimachinery/pkg/watch", Name: "Interface"}),
"RESTClientInterface": c.Universe.Type(types.Name{Package: "k8s.io/client-go/rest", Name: "Interface"}),
"schemeParameterCodec": c.Universe.Variable(types.Name{Package: filepath.Join(g.clientsetPackage, "scheme"), Name: "ParameterCodec"}),
}
sw.Do(getterComment, m)
@ -224,7 +225,7 @@ func (c *$.type|privatePlural$) List(opts $.ListOptions|raw$) (result *$.type|ra
err = c.client.Get().
$if .namespaced$Namespace(c.ns).$end$
Resource("$.type|allLowercasePlural$").
VersionedParams(&opts, $.apiParameterCodec|raw$).
VersionedParams(&opts, $.schemeParameterCodec|raw$).
Do().
Into(result)
return
@ -238,7 +239,7 @@ func (c *$.type|privatePlural$) Get(name string, options $.GetOptions|raw$) (res
$if .namespaced$Namespace(c.ns).$end$
Resource("$.type|allLowercasePlural$").
Name(name).
VersionedParams(&options, $.apiParameterCodec|raw$).
VersionedParams(&options, $.schemeParameterCodec|raw$).
Do().
Into(result)
return
@ -264,7 +265,7 @@ func (c *$.type|privatePlural$) DeleteCollection(options *$.DeleteOptions|raw$,
return c.client.Delete().
$if .namespaced$Namespace(c.ns).$end$
Resource("$.type|allLowercasePlural$").
VersionedParams(&listOptions, $.apiParameterCodec|raw$).
VersionedParams(&listOptions, $.schemeParameterCodec|raw$).
Body(options).
Do().
Error()
@ -325,7 +326,7 @@ func (c *$.type|privatePlural$) Watch(opts $.ListOptions|raw$) ($.watchInterface
Prefix("watch").
$if .namespaced$Namespace(c.ns).$end$
Resource("$.type|allLowercasePlural$").
VersionedParams(&opts, $.apiParameterCodec|raw$).
VersionedParams(&opts, $.schemeParameterCodec|raw$).
Watch()
}
`

View File

@ -102,6 +102,17 @@ func ToGroupVersionPackages(groups []GroupVersions) []GroupVersionPackage {
return groupVersionPackages
}
func ToGroupInstallPackages(groups []GroupVersions) []GroupInstallPackage {
var groupInstallPackages []GroupInstallPackage
for _, group := range groups {
groupInstallPackages = append(groupInstallPackages, GroupInstallPackage{
Group: Group(namer.IC(group.Group.NonEmpty())),
InstallPackageName: strings.ToLower(group.Group.NonEmpty()),
})
}
return groupInstallPackages
}
// NormalizeGroupVersion calls normalizes the GroupVersion.
//func NormalizeGroupVersion(gv GroupVersion) GroupVersion {
// return GroupVersion{Group: gv.Group.NonEmpty(), Version: gv.Version, NonEmptyVersion: normalization.Version(gv.Version)}

View File

@ -62,3 +62,8 @@ type GroupVersionPackage struct {
GroupVersion string
PackageName string
}
type GroupInstallPackage struct {
Group Group
InstallPackageName string
}

View File

@ -1,25 +0,0 @@
/*
Copyright 2016 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package federation_internalclientset
// These imports are the API groups the client will support.
import (
_ "k8s.io/kubernetes/federation/apis/federation/install"
)
func init() {
}

View File

@ -1,42 +0,0 @@
/*
Copyright 2015 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package internalclientset
// These imports are the API groups the client will support.
import (
"fmt"
"k8s.io/kubernetes/pkg/api"
_ "k8s.io/kubernetes/pkg/api/install"
_ "k8s.io/kubernetes/pkg/apis/apps/install"
_ "k8s.io/kubernetes/pkg/apis/authentication/install"
_ "k8s.io/kubernetes/pkg/apis/authorization/install"
_ "k8s.io/kubernetes/pkg/apis/autoscaling/install"
_ "k8s.io/kubernetes/pkg/apis/batch/install"
_ "k8s.io/kubernetes/pkg/apis/certificates/install"
_ "k8s.io/kubernetes/pkg/apis/componentconfig/install"
_ "k8s.io/kubernetes/pkg/apis/extensions/install"
_ "k8s.io/kubernetes/pkg/apis/policy/install"
_ "k8s.io/kubernetes/pkg/apis/rbac/install"
_ "k8s.io/kubernetes/pkg/apis/storage/install"
)
func init() {
if missingVersions := api.Registry.ValidateEnvRequestedVersions(); len(missingVersions) != 0 {
panic(fmt.Sprintf("KUBE_API_VERSIONS contains versions that are not installed: %q.", missingVersions))
}
}

View File

@ -0,0 +1,29 @@
/*
Copyright 2017 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package scheme
import (
"k8s.io/apimachinery/pkg/apimachinery/announced"
"k8s.io/apimachinery/pkg/apimachinery/registered"
"k8s.io/apimachinery/pkg/runtime"
componentconfig "k8s.io/kubernetes/pkg/apis/componentconfig/install"
)
func ExtraInstall(groupFactoryRegistry announced.APIGroupFactoryRegistry, registry *registered.APIRegistrationManager, scheme *runtime.Scheme) {
// componentconfig is an apigroup, but we don't have an API endpoint because its objects are just embedded in ConfigMaps.
componentconfig.Install(groupFactoryRegistry, registry, scheme)
}