Merge pull request #63206 from deads2k/api-11-restmapper

Automatic merge from submit-queue. If you want to cherry-pick this change to another branch, please follow the instructions <a href="https://github.com/kubernetes/community/blob/master/contributors/devel/cherry-picks.md">here</a>.

remove incorrect static restmapper from type registry

A RESTMapping can only be determined by inspecting a server since discovery is the authoritative source of mapping decisions.  This removes a deceptive method from the type registry and makes the old logic available for existing tests in a separate, clearly labeled package.

@kubernetes/sig-api-machinery-pr-reviews @kubernetes/sig-cli-maintainers 

```release-note
NONE
```
pull/8/head
Kubernetes Submit Queue 2018-05-01 08:10:37 -07:00 committed by GitHub
commit f03f83a20a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
71 changed files with 457 additions and 483 deletions

View File

@ -48,7 +48,6 @@ go_library(
"//pkg/apis/settings/install:go_default_library",
"//pkg/apis/storage:go_default_library",
"//pkg/apis/storage/install:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/api/meta:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime/serializer/recognizer:go_default_library",

View File

@ -30,7 +30,6 @@ import (
"reflect"
"strings"
"k8s.io/apimachinery/pkg/api/meta"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/runtime/serializer/recognizer"
@ -473,51 +472,3 @@ func (g TestGroup) SubResourcePath(resource, namespace, name, sub string) string
return path
}
// RESTMapper returns RESTMapper in legacyscheme.Registry.
func (g TestGroup) RESTMapper() meta.RESTMapper {
return legacyscheme.Registry.RESTMapper()
}
// ExternalGroupVersions returns all external group versions allowed for the server.
func ExternalGroupVersions() schema.GroupVersions {
versions := []schema.GroupVersion{}
for _, g := range Groups {
gv := g.GroupVersion()
versions = append(versions, *gv)
}
return versions
}
// GetCodecForObject gets codec based on runtime.Object
func GetCodecForObject(obj runtime.Object) (runtime.Codec, error) {
kinds, _, err := legacyscheme.Scheme.ObjectKinds(obj)
if err != nil {
return nil, fmt.Errorf("unexpected encoding error: %v", err)
}
kind := kinds[0]
for _, group := range Groups {
if group.GroupVersion().Group != kind.Group {
continue
}
if legacyscheme.Scheme.Recognizes(kind) {
return group.Codec(), nil
}
}
// Codec used for unversioned types
if legacyscheme.Scheme.Recognizes(kind) {
serializer, ok := runtime.SerializerInfoForMediaType(legacyscheme.Codecs.SupportedMediaTypes(), runtime.ContentTypeJSON)
if !ok {
return nil, fmt.Errorf("no serializer registered for json")
}
return serializer.Serializer, nil
}
return nil, fmt.Errorf("unexpected kind: %v", kind)
}
// NewTestGroup creates a new TestGroup.
func NewTestGroup(external, internal schema.GroupVersion, internalTypes map[string]reflect.Type, externalTypes map[string]reflect.Type) TestGroup {
return TestGroup{external, internal, internalTypes, externalTypes}
}

View File

@ -31,7 +31,6 @@ go_test(
"//vendor/k8s.io/apimachinery/pkg/api/meta:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
],
)

View File

@ -45,18 +45,6 @@ func Install(registry *registered.APIRegistrationManager, scheme *runtime.Scheme
"PersistentVolume",
"ComponentStatus",
),
IgnoredKinds: sets.NewString(
"ListOptions",
"DeleteOptions",
"Status",
"PodLogOptions",
"PodExecOptions",
"PodAttachOptions",
"PodPortForwardOptions",
"PodProxyOptions",
"NodeProxyOptions",
"ServiceProxyOptions",
),
},
announced.VersionToSchemeFunc{
v1.SchemeGroupVersion.Version: v1.AddToScheme,

View File

@ -24,7 +24,6 @@ import (
"k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/kubernetes/pkg/api/legacyscheme"
internal "k8s.io/kubernetes/pkg/apis/core"
)
@ -66,43 +65,6 @@ func TestCodec(t *testing.T) {
}
}
func TestRESTMapper(t *testing.T) {
gv := schema.GroupVersion{Group: "", Version: "v1"}
rcGVK := gv.WithKind("ReplicationController")
podTemplateGVK := gv.WithKind("PodTemplate")
if gvk, err := legacyscheme.Registry.RESTMapper().KindFor(internal.SchemeGroupVersion.WithResource("replicationcontrollers")); err != nil || gvk != rcGVK {
t.Errorf("unexpected version mapping: %v %v", gvk, err)
}
if m, err := legacyscheme.Registry.GroupOrDie(internal.GroupName).RESTMapper.RESTMapping(podTemplateGVK.GroupKind(), ""); err != nil || m.GroupVersionKind != podTemplateGVK || m.Resource != "podtemplates" {
t.Errorf("unexpected version mapping: %#v %v", m, err)
}
for _, version := range legacyscheme.Registry.GroupOrDie(internal.GroupName).GroupVersions {
mapping, err := legacyscheme.Registry.GroupOrDie(internal.GroupName).RESTMapper.RESTMapping(rcGVK.GroupKind(), version.Version)
if err != nil {
t.Errorf("unexpected error: %v", err)
}
if mapping.Resource != "replicationControllers" && mapping.Resource != "replicationcontrollers" {
t.Errorf("incorrect resource name: %#v", mapping)
}
if mapping.GroupVersionKind.GroupVersion() != version {
t.Errorf("incorrect version: %v", mapping)
}
rc := &internal.ReplicationController{ObjectMeta: metav1.ObjectMeta{Name: "foo"}}
name, err := meta.NewAccessor().Name(rc)
if err != nil {
t.Errorf("unexpected error: %v", err)
}
if name != "foo" {
t.Errorf("bad name: %q", name)
}
}
}
func TestUnversioned(t *testing.T) {
for _, obj := range []runtime.Object{
&metav1.Status{},

View File

@ -14,7 +14,6 @@ go_library(
importpath = "k8s.io/kubernetes/pkg/apis/core/validation",
visibility = ["//visibility:public"],
deps = [
"//pkg/api/legacyscheme:go_default_library",
"//pkg/api/service:go_default_library",
"//pkg/apis/core:go_default_library",
"//pkg/apis/core/helper:go_default_library",
@ -29,13 +28,11 @@ go_library(
"//vendor/github.com/golang/glog:go_default_library",
"//vendor/k8s.io/api/core/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/api/equality:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/api/meta:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/api/resource:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/api/validation:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1/validation:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/labels:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/diff:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/intstr:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library",

View File

@ -20,12 +20,9 @@ import (
"fmt"
"time"
"k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/util/validation"
"k8s.io/apimachinery/pkg/util/validation/field"
"k8s.io/kubernetes/pkg/api/legacyscheme"
"k8s.io/kubernetes/pkg/apis/core"
)
@ -90,40 +87,8 @@ func ValidateEvent(event *core.Event) field.ErrorList {
}
}
// For kinds we recognize, make sure InvolvedObject.Namespace is set for namespaced kinds
if namespaced, err := isNamespacedKind(event.InvolvedObject.Kind, event.InvolvedObject.APIVersion); err == nil {
if namespaced && len(event.InvolvedObject.Namespace) == 0 {
allErrs = append(allErrs, field.Required(field.NewPath("involvedObject", "namespace"), fmt.Sprintf("required for kind %s", event.InvolvedObject.Kind)))
}
if !namespaced && len(event.InvolvedObject.Namespace) > 0 {
allErrs = append(allErrs, field.Invalid(field.NewPath("involvedObject", "namespace"), event.InvolvedObject.Namespace, fmt.Sprintf("not allowed for kind %s", event.InvolvedObject.Kind)))
}
}
for _, msg := range validation.IsDNS1123Subdomain(event.Namespace) {
allErrs = append(allErrs, field.Invalid(field.NewPath("namespace"), event.Namespace, msg))
}
return allErrs
}
// Check whether the kind in groupVersion is scoped at the root of the api hierarchy
func isNamespacedKind(kind, groupVersion string) (bool, error) {
gv, err := schema.ParseGroupVersion(groupVersion)
if err != nil {
return false, err
}
g, err := legacyscheme.Registry.Group(gv.Group)
if err != nil {
return false, err
}
restMapping, err := g.RESTMapper.RESTMapping(schema.GroupKind{Group: gv.Group, Kind: kind}, gv.Version)
if err != nil {
return false, err
}
scopeName := restMapping.Scope.Name()
if scopeName == meta.RESTScopeNameNamespace {
return true, nil
}
return false, nil
}

View File

@ -58,6 +58,7 @@ go_test(
"//vendor/github.com/stretchr/testify/assert:go_default_library",
"//vendor/k8s.io/api/core/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/api/meta:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/api/meta/testrestmapper:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime/serializer:go_default_library",

View File

@ -32,6 +32,7 @@ import (
"k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/meta"
"k8s.io/apimachinery/pkg/api/meta/testrestmapper"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/runtime/serializer"
@ -60,7 +61,7 @@ func TestGarbageCollectorConstruction(t *testing.T) {
config := &restclient.Config{}
config.ContentConfig.NegotiatedSerializer = serializer.DirectCodecFactory{CodecFactory: metaonly.NewMetadataCodecFactory()}
tweakableRM := meta.NewDefaultRESTMapper(nil)
rm := &testRESTMapper{meta.MultiRESTMapper{tweakableRM, legacyscheme.Registry.RESTMapper()}}
rm := &testRESTMapper{meta.MultiRESTMapper{tweakableRM, testrestmapper.TestOnlyStaticRESTMapper(legacyscheme.Registry, legacyscheme.Scheme)}}
metaOnlyClientPool := dynamic.NewClientPool(config, rm, dynamic.LegacyAPIPathResolverFunc)
config.ContentConfig.NegotiatedSerializer = nil
clientPool := dynamic.NewClientPool(config, rm, dynamic.LegacyAPIPathResolverFunc)
@ -190,15 +191,15 @@ type garbageCollector struct {
func setupGC(t *testing.T, config *restclient.Config) garbageCollector {
config.ContentConfig.NegotiatedSerializer = serializer.DirectCodecFactory{CodecFactory: metaonly.NewMetadataCodecFactory()}
metaOnlyClientPool := dynamic.NewClientPool(config, legacyscheme.Registry.RESTMapper(), dynamic.LegacyAPIPathResolverFunc)
metaOnlyClientPool := dynamic.NewClientPool(config, testrestmapper.TestOnlyStaticRESTMapper(legacyscheme.Registry, legacyscheme.Scheme), dynamic.LegacyAPIPathResolverFunc)
config.ContentConfig.NegotiatedSerializer = nil
clientPool := dynamic.NewClientPool(config, legacyscheme.Registry.RESTMapper(), dynamic.LegacyAPIPathResolverFunc)
clientPool := dynamic.NewClientPool(config, testrestmapper.TestOnlyStaticRESTMapper(legacyscheme.Registry, legacyscheme.Scheme), dynamic.LegacyAPIPathResolverFunc)
podResource := map[schema.GroupVersionResource]struct{}{{Version: "v1", Resource: "pods"}: {}}
client := fake.NewSimpleClientset()
sharedInformers := informers.NewSharedInformerFactory(client, 0)
alwaysStarted := make(chan struct{})
close(alwaysStarted)
gc, err := NewGarbageCollector(metaOnlyClientPool, clientPool, &testRESTMapper{legacyscheme.Registry.RESTMapper()}, podResource, ignoredResources, sharedInformers, alwaysStarted)
gc, err := NewGarbageCollector(metaOnlyClientPool, clientPool, &testRESTMapper{testrestmapper.TestOnlyStaticRESTMapper(legacyscheme.Registry, legacyscheme.Scheme)}, podResource, ignoredResources, sharedInformers, alwaysStarted)
if err != nil {
t.Fatal(err)
}
@ -433,7 +434,7 @@ func TestGCListWatcher(t *testing.T) {
testHandler := &fakeActionHandler{}
srv, clientConfig := testServerAndClientConfig(testHandler.ServeHTTP)
defer srv.Close()
clientPool := dynamic.NewClientPool(clientConfig, legacyscheme.Registry.RESTMapper(), dynamic.LegacyAPIPathResolverFunc)
clientPool := dynamic.NewClientPool(clientConfig, testrestmapper.TestOnlyStaticRESTMapper(legacyscheme.Registry, legacyscheme.Scheme), dynamic.LegacyAPIPathResolverFunc)
podResource := schema.GroupVersionResource{Version: "v1", Resource: "pods"}
client, err := clientPool.ClientForGroupVersionResource(podResource)
if err != nil {
@ -822,7 +823,7 @@ func TestGarbageCollectorSync(t *testing.T) {
t.Fatal(err)
}
rm := &testRESTMapper{legacyscheme.Registry.RESTMapper()}
rm := &testRESTMapper{testrestmapper.TestOnlyStaticRESTMapper(legacyscheme.Registry, legacyscheme.Scheme)}
metaOnlyClientPool := dynamic.NewClientPool(clientConfig, rm, dynamic.LegacyAPIPathResolverFunc)
clientPool := dynamic.NewClientPool(clientConfig, rm, dynamic.LegacyAPIPathResolverFunc)
podResource := map[schema.GroupVersionResource]struct{}{

View File

@ -69,6 +69,7 @@ go_test(
"//vendor/k8s.io/api/autoscaling/v1:go_default_library",
"//vendor/k8s.io/api/autoscaling/v2beta1:go_default_library",
"//vendor/k8s.io/api/core/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/api/meta/testrestmapper:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/api/resource:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/labels:go_default_library",

View File

@ -27,6 +27,7 @@ import (
autoscalingv1 "k8s.io/api/autoscaling/v1"
autoscalingv2 "k8s.io/api/autoscaling/v2beta1"
"k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/meta/testrestmapper"
"k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
@ -511,7 +512,7 @@ func (tc *testCase) prepareTestClient(t *testing.T) (*fake.Clientset, *metricsfa
}
name := getForAction.GetName()
mapper := legacyscheme.Registry.RESTMapper()
mapper := testrestmapper.TestOnlyStaticRESTMapper(legacyscheme.Registry, legacyscheme.Scheme)
metrics := &cmapi.MetricValueList{}
var matchedTarget *autoscalingv2.MetricSpec
for i, target := range tc.metricsTarget {
@ -649,7 +650,7 @@ func (tc *testCase) setupController(t *testing.T) (*HorizontalController, inform
eventClient.Core(),
testScaleClient,
testClient.Autoscaling(),
legacyscheme.Registry.RESTMapper(),
testrestmapper.TestOnlyStaticRESTMapper(legacyscheme.Registry, legacyscheme.Scheme),
replicaCalc,
informerFactory.Autoscaling().V1().HorizontalPodAutoscalers(),
controller.NoResyncPeriodFunc(),

View File

@ -30,6 +30,7 @@ import (
autoscalingv1 "k8s.io/api/autoscaling/v1"
autoscalingv2 "k8s.io/api/autoscaling/v2beta1"
"k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/meta/testrestmapper"
"k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
@ -497,7 +498,7 @@ func (tc *legacyTestCase) runTest(t *testing.T) {
eventClient.Core(),
testScaleClient,
testClient.Autoscaling(),
legacyscheme.Registry.RESTMapper(),
testrestmapper.TestOnlyStaticRESTMapper(legacyscheme.Registry, legacyscheme.Scheme),
replicaCalc,
informerFactory.Autoscaling().V1().HorizontalPodAutoscalers(),
controller.NoResyncPeriodFunc(),

View File

@ -47,6 +47,7 @@ go_test(
"//vendor/github.com/stretchr/testify/assert:go_default_library",
"//vendor/k8s.io/api/autoscaling/v2beta1:go_default_library",
"//vendor/k8s.io/api/core/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/api/meta/testrestmapper:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/api/resource:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/labels:go_default_library",

View File

@ -23,6 +23,7 @@ import (
autoscalingapi "k8s.io/api/autoscaling/v2beta1"
"k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/meta/testrestmapper"
"k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
@ -153,7 +154,7 @@ func (tc *restClientTestCase) prepareTestClient(t *testing.T) (*metricsfake.Clie
return true, &metrics, nil
} else {
name := getForAction.GetName()
mapper := legacyscheme.Registry.RESTMapper()
mapper := testrestmapper.TestOnlyStaticRESTMapper(legacyscheme.Registry, legacyscheme.Scheme)
assert.NotNil(t, tc.singleObject, "should have only requested a single-object metric when we asked for metrics for a single object")
gk := schema.FromAPIVersionAndKind(tc.singleObject.APIVersion, tc.singleObject.Kind).GroupKind()
mapping, err := mapper.RESTMapping(gk)

View File

@ -24,6 +24,7 @@ import (
autoscalingv2 "k8s.io/api/autoscaling/v2beta1"
"k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/meta/testrestmapper"
"k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
@ -221,7 +222,7 @@ func (tc *replicaCalcTestCase) prepareTestClient(t *testing.T) (*fake.Clientset,
return true, &metrics, nil
}
name := getForAction.GetName()
mapper := legacyscheme.Registry.RESTMapper()
mapper := testrestmapper.TestOnlyStaticRESTMapper(legacyscheme.Registry, legacyscheme.Scheme)
metrics := &cmapi.MetricValueList{}
assert.NotNil(t, tc.metric.singleObject, "should have only requested a single-object metric when calling GetObjectMetricReplicas")
gk := schema.FromAPIVersionAndKind(tc.metric.singleObject.APIVersion, tc.metric.singleObject.Kind).GroupKind()

View File

@ -25,7 +25,6 @@ import (
"k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/api/meta"
"k8s.io/apimachinery/pkg/types"
"k8s.io/kubernetes/pkg/api/legacyscheme"
"k8s.io/kubernetes/pkg/kubectl"
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
@ -46,7 +45,6 @@ type SetLastAppliedOptions struct {
FilenameOptions resource.FilenameOptions
infoList []*resource.Info
mapper meta.RESTMapper
namespace string
enforceNamespace bool
dryRun bool
@ -117,7 +115,6 @@ func (o *SetLastAppliedOptions) Complete(f cmdutil.Factory, cmd *cobra.Command)
o.output = cmdutil.GetFlagString(cmd, "output")
o.shortOutput = o.output == "name"
o.mapper = f.RESTMapper()
var err error
o.namespace, o.enforceNamespace, err = f.DefaultNamespace()
if err != nil {
@ -205,7 +202,7 @@ func (o *SetLastAppliedOptions) RunSetLastApplied() error {
}
info.Refresh(patchedObj, false)
}
if err := o.PrintObj(info.AsVersioned(legacyscheme.Scheme), o.Out); err != nil {
if err := o.PrintObj(cmdutil.AsDefaultVersionedOrOriginal(info.Object, info.Mapping), o.Out); err != nil {
return err
}
}

View File

@ -127,7 +127,10 @@ func (o *CanIOptions) Complete(f cmdutil.Factory, args []string) error {
break
}
resourceTokens := strings.SplitN(args[1], "/", 2)
restMapper := f.RESTMapper()
restMapper, err := f.RESTMapper()
if err != nil {
return err
}
o.Resource = o.resourceFor(restMapper, resourceTokens[0])
if len(resourceTokens) > 1 {
o.ResourceName = resourceTokens[1]

View File

@ -127,16 +127,20 @@ func NewCmdAutoscale(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *
}
func (o *AutoscaleOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error {
var err error
o.dryRun = cmdutil.GetFlagBool(cmd, "dry-run")
o.createAnnotation = cmdutil.GetFlagBool(cmd, cmdutil.ApplyAnnotationsFlag)
o.builder = f.NewBuilder()
o.canBeAutoscaled = f.CanBeAutoscaled
o.mapper = f.RESTMapper()
o.mapper, err = f.RESTMapper()
if err != nil {
return err
}
o.clientForMapping = f.ClientForMapping
o.args = args
o.RecordFlags.Complete(f.Command(cmd, false))
var err error
o.Recorder, err = o.RecordFlags.ToRecorder()
if err != nil {
return err
@ -249,7 +253,7 @@ func (o *AutoscaleOptions) Run() error {
if err != nil {
return err
}
return printer.PrintObj(hpa.AsVersioned(legacyscheme.Scheme), o.Out)
return printer.PrintObj(cmdutil.AsDefaultVersionedOrOriginal(hpa.Object, hpa.Mapping), o.Out)
}
if err := kubectl.CreateOrUpdateAnnotation(o.createAnnotation, hpa.Object, cmdutil.InternalVersionJSONEncoder()); err != nil {
@ -266,7 +270,7 @@ func (o *AutoscaleOptions) Run() error {
if err != nil {
return err
}
return printer.PrintObj(info.AsVersioned(legacyscheme.Scheme), o.Out)
return printer.PrintObj(cmdutil.AsDefaultVersionedOrOriginal(info.Object, hpa.Mapping), o.Out)
})
if err != nil {
return err

View File

@ -228,7 +228,7 @@ func (options *CertificateOptions) modifyCertificateCondition(builder *resource.
}
found++
return options.PrintObj(info.AsVersioned(legacyscheme.Scheme), options.Out)
return options.PrintObj(cmdutil.AsDefaultVersionedOrOriginal(info.Object, info.Mapping), options.Out)
})
if found == 0 {
fmt.Fprintf(options.Out, "No resources found\n")

View File

@ -389,7 +389,10 @@ func RunCreateSubcommand(f cmdutil.Factory, options *CreateSubcommandOptions) er
if err != nil {
return err
}
mapper := f.RESTMapper()
mapper, err := f.RESTMapper()
if err != nil {
return err
}
if !options.DryRun {
// create subcommands have compiled knowledge of things they create, so type them directly
gvks, _, err := legacyscheme.Scheme.ObjectKinds(obj)
@ -423,7 +426,7 @@ func RunCreateSubcommand(f cmdutil.Factory, options *CreateSubcommandOptions) er
}
// ensure we pass a versioned object to the printer
obj = info.AsVersioned(legacyscheme.Scheme)
obj = cmdutil.AsDefaultVersionedOrOriginal(info.Object, info.Mapping)
} else {
if meta, err := meta.Accessor(obj); err == nil && nsOverriden {
meta.SetNamespace(namespace)

View File

@ -437,8 +437,12 @@ func TestClusterRoleValidate(t *testing.T) {
for name, test := range tests {
t.Run(name, func(t *testing.T) {
test.clusterRoleOptions.Mapper = tf.RESTMapper()
err := test.clusterRoleOptions.Validate()
var err error
test.clusterRoleOptions.Mapper, err = tf.RESTMapper()
if err != nil {
t.Fatal(err)
}
err = test.clusterRoleOptions.Validate()
if test.expectErr && err == nil {
t.Errorf("%s: expect error happens, but validate passes.", name)
}

View File

@ -205,7 +205,10 @@ func (o *CreateRoleOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args
o.ResourceNames = resourceNames
// Complete other options for Run.
o.Mapper = f.RESTMapper()
o.Mapper, err = f.RESTMapper()
if err != nil {
return err
}
o.DryRun = cmdutil.GetDryRunFlag(cmd)
o.OutputFormat = cmdutil.GetFlagString(cmd, "output")

View File

@ -339,8 +339,12 @@ func TestValidate(t *testing.T) {
}
for name, test := range tests {
test.roleOptions.Mapper = tf.RESTMapper()
err := test.roleOptions.Validate()
var err error
test.roleOptions.Mapper, err = tf.RESTMapper()
if err != nil {
t.Fatal(err)
}
err = test.roleOptions.Validate()
if test.expectErr && err == nil {
t.Errorf("%s: expect error happens but validate passes.", name)
}

View File

@ -29,7 +29,6 @@ import (
corev1 "k8s.io/api/core/v1"
policyv1beta1 "k8s.io/api/policy/v1beta1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/fields"
"k8s.io/apimachinery/pkg/labels"
@ -68,7 +67,6 @@ type DrainOptions struct {
DeleteLocalData bool
Selector string
PodSelector string
mapper meta.RESTMapper
nodeInfos []*resource.Info
typer runtime.ObjectTyper
@ -741,7 +739,7 @@ func (o *DrainOptions) RunCordonOrUncordon(desired bool) error {
fmt.Printf("error: %v", err)
continue
}
printer.PrintObj(nodeInfo.AsVersioned(legacyscheme.Scheme), o.Out)
printer.PrintObj(cmdutil.AsDefaultVersionedOrOriginal(nodeInfo.Object, nodeInfo.Mapping), o.Out)
} else {
if !o.DryRun {
helper := resource.NewHelper(o.restClient, nodeInfo.Mapping)
@ -767,7 +765,7 @@ func (o *DrainOptions) RunCordonOrUncordon(desired bool) error {
fmt.Fprintf(o.ErrOut, "%v", err)
continue
}
printer.PrintObj(nodeInfo.AsVersioned(legacyscheme.Scheme), o.Out)
printer.PrintObj(cmdutil.AsDefaultVersionedOrOriginal(nodeInfo.Object, nodeInfo.Mapping), o.Out)
}
} else {
printer, err := o.ToPrinter("skipped")
@ -775,7 +773,7 @@ func (o *DrainOptions) RunCordonOrUncordon(desired bool) error {
fmt.Fprintf(o.ErrOut, "%v", err)
continue
}
printer.PrintObj(nodeInfo.AsVersioned(legacyscheme.Scheme), o.Out)
printer.PrintObj(cmdutil.AsDefaultVersionedOrOriginal(nodeInfo.Object, nodeInfo.Mapping), o.Out)
}
}

View File

@ -836,7 +836,6 @@ func TestDeletePods(t *testing.T) {
o := DrainOptions{
PrintFlags: printers.NewPrintFlags("drained"),
}
o.mapper = tf.RESTMapper()
o.Out = os.Stdout
o.ToPrinter = func(operation string) (printers.ResourcePrinterFunc, error) {

View File

@ -91,12 +91,16 @@ func NewCmdExplain(parent string, f cmdutil.Factory, streams genericclioptions.I
}
func (o *ExplainOptions) Complete(f cmdutil.Factory, cmd *cobra.Command) error {
var err error
o.Recursive = cmdutil.GetFlagBool(cmd, "recursive")
o.ApiVersion = cmdutil.GetFlagString(cmd, "api-version")
o.Mapper = f.RESTMapper()
o.Mapper, err = f.RESTMapper()
if err != nil {
return err
}
var err error
o.Schema, err = f.OpenAPISchema()
if err != nil {
return err

View File

@ -187,7 +187,10 @@ func (o *ExposeServiceOptions) Complete(f cmdutil.Factory, cmd *cobra.Command) e
o.MapBasedSelectorForObject = f.MapBasedSelectorForObject
o.PortsForObject = f.PortsForObject
o.ProtocolsForObject = f.ProtocolsForObject
o.Mapper = f.RESTMapper()
o.Mapper, err = f.RESTMapper()
if err != nil {
return err
}
o.LabelsForObject = f.LabelsForObject
o.Namespace, o.EnforceNamespace, err = f.DefaultNamespace()
@ -336,7 +339,7 @@ func (o *ExposeServiceOptions) RunExpose(cmd *cobra.Command, args []string) erro
return err
}
return o.PrintObj(info.AsVersioned(legacyscheme.Scheme), o.Out)
return o.PrintObj(cmdutil.AsDefaultVersionedOrOriginal(info.Object, info.Mapping), o.Out)
})
if err != nil {
return err

View File

@ -21,7 +21,6 @@ import (
"github.com/spf13/cobra"
"k8s.io/apimachinery/pkg/api/meta"
"k8s.io/apimachinery/pkg/types"
utilerrors "k8s.io/apimachinery/pkg/util/errors"
"k8s.io/kubernetes/pkg/api/legacyscheme"
@ -43,7 +42,6 @@ type PauseConfig struct {
ToPrinter func(string) (printers.ResourcePrinterFunc, error)
Pauser func(info *resource.Info) ([]byte, error)
Mapper meta.RESTMapper
Infos []*resource.Info
genericclioptions.IOStreams
@ -105,8 +103,6 @@ func (o *PauseConfig) CompletePause(f cmdutil.Factory, cmd *cobra.Command, args
return cmdutil.UsageErrorf(cmd, "%s", cmd.Use)
}
o.Mapper = f.RESTMapper()
o.Pauser = f.Pauser
cmdNamespace, enforceNamespace, err := f.DefaultNamespace()
@ -160,7 +156,7 @@ func (o PauseConfig) RunPause() error {
allErrs = append(allErrs, err)
continue
}
printer.PrintObj(info.AsVersioned(legacyscheme.Scheme), o.Out)
printer.PrintObj(cmdutil.AsDefaultVersionedOrOriginal(info.Object, info.Mapping), o.Out)
continue
}
@ -176,7 +172,7 @@ func (o PauseConfig) RunPause() error {
allErrs = append(allErrs, err)
continue
}
printer.PrintObj(info.AsVersioned(legacyscheme.Scheme), o.Out)
printer.PrintObj(cmdutil.AsDefaultVersionedOrOriginal(info.Object, info.Mapping), o.Out)
}
return utilerrors.NewAggregate(allErrs)

View File

@ -21,7 +21,6 @@ import (
"github.com/spf13/cobra"
"k8s.io/apimachinery/pkg/api/meta"
"k8s.io/apimachinery/pkg/types"
utilerrors "k8s.io/apimachinery/pkg/util/errors"
"k8s.io/kubernetes/pkg/api/legacyscheme"
@ -43,7 +42,6 @@ type ResumeConfig struct {
ToPrinter func(string) (printers.ResourcePrinterFunc, error)
Resumer func(object *resource.Info) ([]byte, error)
Mapper meta.RESTMapper
Infos []*resource.Info
genericclioptions.IOStreams
@ -103,8 +101,6 @@ func (o *ResumeConfig) CompleteResume(f cmdutil.Factory, cmd *cobra.Command, arg
return cmdutil.UsageErrorf(cmd, "%s", cmd.Use)
}
o.Mapper = f.RESTMapper()
o.Resumer = f.Resumer
cmdNamespace, enforceNamespace, err := f.DefaultNamespace()
@ -165,7 +161,7 @@ func (o ResumeConfig) RunResume() error {
allErrs = append(allErrs, err)
continue
}
printer.PrintObj(info.AsVersioned(legacyscheme.Scheme), o.Out)
printer.PrintObj(cmdutil.AsDefaultVersionedOrOriginal(info.Object, info.Mapping), o.Out)
}
obj, err := resource.NewHelper(info.Client, info.Mapping).Patch(info.Namespace, info.Name, types.StrategicMergePatchType, patch.Patch)
@ -180,7 +176,7 @@ func (o ResumeConfig) RunResume() error {
allErrs = append(allErrs, err)
continue
}
printer.PrintObj(info.AsVersioned(legacyscheme.Scheme), o.Out)
printer.PrintObj(cmdutil.AsDefaultVersionedOrOriginal(info.Object, info.Mapping), o.Out)
}
return utilerrors.NewAggregate(allErrs)

View File

@ -19,7 +19,6 @@ package rollout
import (
"io"
"k8s.io/apimachinery/pkg/api/meta"
utilerrors "k8s.io/apimachinery/pkg/util/errors"
"k8s.io/kubernetes/pkg/api/legacyscheme"
"k8s.io/kubernetes/pkg/kubectl"
@ -41,7 +40,6 @@ type UndoOptions struct {
ToPrinter func(string) (printers.ResourcePrinterFunc, error)
Rollbackers []kubectl.Rollbacker
Mapper meta.RESTMapper
Infos []*resource.Info
ToRevision int64
DryRun bool
@ -107,7 +105,6 @@ func (o *UndoOptions) CompleteUndo(f cmdutil.Factory, cmd *cobra.Command, out io
}
o.ToRevision = cmdutil.GetFlagInt64(cmd, "to-revision")
o.Mapper = f.RESTMapper()
o.Out = out
o.DryRun = cmdutil.GetDryRunFlag(cmd)
@ -171,7 +168,7 @@ func (o *UndoOptions) RunUndo() error {
allErrs = append(allErrs, err)
continue
}
printer.PrintObj(info.AsVersioned(legacyscheme.Scheme), o.Out)
printer.PrintObj(cmdutil.AsDefaultVersionedOrOriginal(info.Object, info.Mapping), o.Out)
}
return utilerrors.NewAggregate(allErrs)
}

View File

@ -643,7 +643,10 @@ func (o *RunOptions) createGeneratedObject(f cmdutil.Factory, cmd *cobra.Command
return nil, err
}
mapper := f.RESTMapper()
mapper, err := f.RESTMapper()
if err != nil {
return nil, err
}
// run has compiled knowledge of the thing is is creating
groupVersionKinds, _, err := legacyscheme.Scheme.ObjectKinds(obj)
if err != nil {
@ -693,7 +696,7 @@ func (o *RunOptions) createGeneratedObject(f cmdutil.Factory, cmd *cobra.Command
return nil, err
}
versioned = info.AsVersioned(legacyscheme.Scheme)
versioned = cmdutil.AsDefaultVersionedOrOriginal(info.Object, info.Mapping)
}
return &RunObject{
Versioned: versioned,

View File

@ -327,7 +327,7 @@ func (o *EnvOptions) RunEnv() error {
return err
}
patches := CalculatePatches(infos, cmdutil.InternalVersionJSONEncoder(), func(info *resource.Info) ([]byte, error) {
info.Object = info.AsVersioned(legacyscheme.Scheme)
info.Object = cmdutil.AsDefaultVersionedOrOriginal(info.Object, info.Mapping)
_, err := o.updatePodSpecForObject(info.Object, func(spec *v1.PodSpec) error {
resolutionErrorsEncountered := false
containers, _ := selectContainers(spec.Containers, o.ContainerSelector)
@ -418,7 +418,7 @@ func (o *EnvOptions) RunEnv() error {
}
if o.Local || o.dryRun {
if err := o.PrintObj(patch.Info.AsVersioned(legacyscheme.Scheme), o.Out); err != nil {
if err := o.PrintObj(cmdutil.AsDefaultVersionedOrOriginal(patch.Info.Object, patch.Info.Mapping), o.Out); err != nil {
return err
}
continue
@ -437,7 +437,7 @@ func (o *EnvOptions) RunEnv() error {
return fmt.Errorf("at least one environment variable must be provided")
}
if err := o.PrintObj(info.AsVersioned(legacyscheme.Scheme), o.Out); err != nil {
if err := o.PrintObj(cmdutil.AsDefaultVersionedOrOriginal(info.Object, info.Mapping), o.Out); err != nil {
return err
}
}

View File

@ -211,7 +211,7 @@ func (o *SetImageOptions) Run() error {
patches := CalculatePatches(o.Infos, cmdutil.InternalVersionJSONEncoder(), func(info *resource.Info) ([]byte, error) {
transformed := false
info.Object = info.AsVersioned(legacyscheme.Scheme)
info.Object = cmdutil.AsDefaultVersionedOrOriginal(info.Object, info.Mapping)
_, err := o.UpdatePodSpecForObject(info.Object, func(spec *v1.PodSpec) error {
for name, image := range o.ContainerImages {
var (
@ -275,7 +275,7 @@ func (o *SetImageOptions) Run() error {
}
if o.Local || o.DryRun {
if err := o.PrintObj(patch.Info.AsVersioned(legacyscheme.Scheme), o.Out); err != nil {
if err := o.PrintObj(cmdutil.AsDefaultVersionedOrOriginal(patch.Info.Object, patch.Info.Mapping), o.Out); err != nil {
return err
}
continue
@ -289,7 +289,7 @@ func (o *SetImageOptions) Run() error {
}
info.Refresh(obj, true)
if err := o.PrintObj(info.AsVersioned(legacyscheme.Scheme), o.Out); err != nil {
if err := o.PrintObj(cmdutil.AsDefaultVersionedOrOriginal(info.Object, info.Mapping), o.Out); err != nil {
return err
}
}

View File

@ -224,7 +224,7 @@ func (o *SetResourcesOptions) Run() error {
allErrs := []error{}
patches := CalculatePatches(o.Infos, cmdutil.InternalVersionJSONEncoder(), func(info *resource.Info) ([]byte, error) {
transformed := false
info.Object = info.AsVersioned(legacyscheme.Scheme)
info.Object = cmdutil.AsDefaultVersionedOrOriginal(info.Object, info.Mapping)
_, err := o.UpdatePodSpecForObject(info.Object, func(spec *v1.PodSpec) error {
containers, _ := selectContainers(spec.Containers, o.ContainerSelector)
if len(containers) != 0 {
@ -277,7 +277,7 @@ func (o *SetResourcesOptions) Run() error {
}
if o.Local || o.DryRun {
if err := o.PrintObj(patch.Info.AsVersioned(legacyscheme.Scheme), o.Out); err != nil {
if err := o.PrintObj(cmdutil.AsDefaultVersionedOrOriginal(patch.Info.Object, patch.Info.Mapping), o.Out); err != nil {
return err
}
continue
@ -290,7 +290,7 @@ func (o *SetResourcesOptions) Run() error {
}
info.Refresh(obj, true)
if err := o.PrintObj(info.AsVersioned(legacyscheme.Scheme), o.Out); err != nil {
if err := o.PrintObj(cmdutil.AsDefaultVersionedOrOriginal(info.Object, info.Mapping), o.Out); err != nil {
return err
}
}

View File

@ -59,7 +59,6 @@ type SetSelectorOptions struct {
Recorder genericclioptions.Recorder
builder *resource.Builder
mapper meta.RESTMapper
genericclioptions.IOStreams
}
@ -140,9 +139,6 @@ func (o *SetSelectorOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, arg
return err
}
mapper := f.RESTMapper()
o.mapper = mapper
o.resources, o.selector, err = getResourcesAndSelector(args)
if err != nil {
return err
@ -208,7 +204,7 @@ func (o *SetSelectorOptions) RunSelector() error {
return r.Visit(func(info *resource.Info, err error) error {
patch := &Patch{Info: info}
CalculatePatch(patch, cmdutil.InternalVersionJSONEncoder(), func(info *resource.Info) ([]byte, error) {
versioned := info.AsVersioned(legacyscheme.Scheme)
versioned := cmdutil.AsDefaultVersionedOrOriginal(info.Object, info.Mapping)
patch.Info.Object = versioned
selectErr := updateSelectorForObject(info.Object, *o.selector)
if selectErr != nil {
@ -236,7 +232,7 @@ func (o *SetSelectorOptions) RunSelector() error {
}
info.Refresh(patched, true)
return o.PrintObj(patch.Info.AsVersioned(legacyscheme.Scheme), o.Out)
return o.PrintObj(cmdutil.AsDefaultVersionedOrOriginal(patch.Info.Object, info.Mapping), o.Out)
})
}

View File

@ -174,7 +174,7 @@ func (o *SetServiceAccountOptions) Complete(f cmdutil.Factory, cmd *cobra.Comman
func (o *SetServiceAccountOptions) Run() error {
patchErrs := []error{}
patchFn := func(info *resource.Info) ([]byte, error) {
info.Object = info.AsVersioned(legacyscheme.Scheme)
info.Object = cmdutil.AsDefaultVersionedOrOriginal(info.Object, info.Mapping)
_, err := o.updatePodSpecForObject(info.Object, func(podSpec *v1.PodSpec) error {
podSpec.ServiceAccountName = o.serviceAccountName
return nil
@ -198,7 +198,7 @@ func (o *SetServiceAccountOptions) Run() error {
continue
}
if o.local || o.dryRun {
if err := o.PrintObj(patch.Info.AsVersioned(legacyscheme.Scheme), o.Out); err != nil {
if err := o.PrintObj(cmdutil.AsDefaultVersionedOrOriginal(patch.Info.Object, patch.Info.Mapping), o.Out); err != nil {
return err
}
continue
@ -210,7 +210,7 @@ func (o *SetServiceAccountOptions) Run() error {
}
info.Refresh(patched, true)
if err := o.PrintObj(info.AsVersioned(legacyscheme.Scheme), o.Out); err != nil {
if err := o.PrintObj(cmdutil.AsDefaultVersionedOrOriginal(info.Object, info.Mapping), o.Out); err != nil {
return err
}
}

View File

@ -230,7 +230,7 @@ func (o *SubjectOptions) Run(fn updateSubjects) error {
transformed, err := updateSubjectForObject(info.Object, subjects, fn)
if transformed && err == nil {
// TODO: switch UpdatePodSpecForObject to work on v1.PodSpec
return runtime.Encode(cmdutil.InternalVersionJSONEncoder(), info.AsVersioned(legacyscheme.Scheme))
return runtime.Encode(cmdutil.InternalVersionJSONEncoder(), cmdutil.AsDefaultVersionedOrOriginal(info.Object, info.Mapping))
}
return nil, err
})
@ -263,7 +263,7 @@ func (o *SubjectOptions) Run(fn updateSubjects) error {
}
info.Refresh(obj, true)
return o.PrintObj(info.AsVersioned(legacyscheme.Scheme), o.Out)
return o.PrintObj(cmdutil.AsDefaultVersionedOrOriginal(info.Object, info.Mapping), o.Out)
}
return utilerrors.NewAggregate(allErrs)
}

View File

@ -22,6 +22,7 @@ go_library(
"//pkg/printers:go_default_library",
"//vendor/github.com/spf13/cobra:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/api/meta:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/api/meta/testrestmapper:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1/unstructured:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",

View File

@ -28,6 +28,7 @@ import (
"github.com/spf13/cobra"
"k8s.io/apimachinery/pkg/api/meta"
"k8s.io/apimachinery/pkg/api/meta/testrestmapper"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime"
@ -337,7 +338,7 @@ func (f *TestFactory) Command(*cobra.Command, bool) string {
}
func (f *TestFactory) NewBuilder() *resource.Builder {
mapper := f.RESTMapper()
mapper, err := f.RESTMapper()
return resource.NewBuilder(
&resource.Mapper{
@ -351,7 +352,7 @@ func (f *TestFactory) NewBuilder() *resource.Builder {
Decoder: unstructured.UnstructuredJSONScheme,
},
f.CategoryExpander(),
)
).AddError(err)
}
func (f *TestFactory) KubernetesClientSet() (*kubernetes.Clientset, error) {
@ -425,7 +426,7 @@ func (f *TestFactory) ClientSetForVersion(requiredVersion *schema.GroupVersion)
return f.ClientSet()
}
func (f *TestFactory) RESTMapper() meta.RESTMapper {
func (f *TestFactory) RESTMapper() (meta.RESTMapper, error) {
groupResources := testDynamicResources()
mapper := discovery.NewRESTMapper(groupResources)
// for backwards compatibility with existing tests, allow rest mappings from the scheme to show up
@ -433,14 +434,14 @@ func (f *TestFactory) RESTMapper() meta.RESTMapper {
mapper = meta.FirstHitRESTMapper{
MultiRESTMapper: meta.MultiRESTMapper{
mapper,
legacyscheme.Registry.RESTMapper(),
testrestmapper.TestOnlyStaticRESTMapper(legacyscheme.Registry, legacyscheme.Scheme),
},
}
// TODO: should probably be the external scheme
fakeDs := &fakeCachedDiscoveryClient{}
expander := cmdutil.NewShortcutExpander(mapper, fakeDs)
return expander
return expander, nil
}
func (f *TestFactory) LogsForObject(object, options runtime.Object, timeout time.Duration) (*restclient.Request, error) {

View File

@ -4,6 +4,7 @@ go_library(
name = "go_default_library",
srcs = [
"cached_discovery.go",
"conversion.go",
"factory.go",
"factory_builder.go",
"factory_client_access.go",
@ -104,6 +105,7 @@ go_test(
"//vendor/k8s.io/apimachinery/pkg/api/equality:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/api/errors:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/api/meta:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/api/meta/testrestmapper:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/labels:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",

View File

@ -0,0 +1,40 @@
/*
Copyright 2018 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 util
import (
"k8s.io/apimachinery/pkg/api/meta"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/kubernetes/pkg/api/legacyscheme"
)
// AsDefaultVersionedOrOriginal returns the object as a Go object in the external form if possible (matching the
// group version kind of the mapping if provided, a best guess based on serialization if not provided, or obj if it cannot be converted.
// TODO update call sites to specify the scheme they want on their builder.
func AsDefaultVersionedOrOriginal(obj runtime.Object, mapping *meta.RESTMapping) runtime.Object {
converter := runtime.ObjectConvertor(legacyscheme.Scheme)
groupVersioner := runtime.GroupVersioner(schema.GroupVersions(legacyscheme.Registry.RegisteredGroupVersions()))
if mapping != nil {
groupVersioner = mapping.GroupVersionKind.GroupVersion()
}
if obj, err := converter.ConvertToVersion(obj, groupVersioner); err == nil {
return obj
}
return obj
}

View File

@ -164,7 +164,7 @@ type ClientAccessFactory interface {
// Generally they provide object typing and functions that build requests based on the negotiated clients.
type ObjectMappingFactory interface {
// Returns interfaces for dealing with arbitrary runtime.Objects.
RESTMapper() meta.RESTMapper
RESTMapper() (meta.RESTMapper, error)
// Returns interface for expanding categories like `all`.
CategoryExpander() categories.CategoryExpander
// Returns a RESTClient for working with the specified RESTMapping or an error. This is intended

View File

@ -47,7 +47,7 @@ func NewBuilderFactory(clientAccessFactory ClientAccessFactory, objectMappingFac
// NewBuilder returns a new resource builder for structured api objects.
func (f *ring2Factory) NewBuilder() *resource.Builder {
clientMapperFunc := resource.ClientMapperFunc(f.objectMappingFactory.ClientForMapping)
mapper := f.objectMappingFactory.RESTMapper()
mapper, mapperErr := f.objectMappingFactory.RESTMapper()
unstructuredClientMapperFunc := resource.ClientMapperFunc(f.objectMappingFactory.UnstructuredClientForMapping)
@ -65,7 +65,7 @@ func (f *ring2Factory) NewBuilder() *resource.Builder {
Decoder: unstructured.UnstructuredJSONScheme,
},
categoryExpander,
)
).AddError(mapperErr)
}
// PluginLoader loads plugins from a path set by the KUBECTL_PLUGINS_PATH env var.
@ -97,7 +97,11 @@ func (f *ring2Factory) ScaleClient() (scaleclient.ScalesGetter, error) {
return nil, err
}
resolver := scaleclient.NewDiscoveryScaleKindResolver(discoClient)
mapper := f.objectMappingFactory.RESTMapper()
mapper, err := f.objectMappingFactory.RESTMapper()
if err != nil {
return nil, err
}
return scaleclient.New(restClient, mapper, dynamic.LegacyAPIPathResolverFunc, resolver), nil
}

View File

@ -27,8 +27,6 @@ import (
"sync"
"time"
"github.com/golang/glog"
"k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@ -37,7 +35,6 @@ import (
"k8s.io/client-go/discovery"
"k8s.io/client-go/dynamic"
restclient "k8s.io/client-go/rest"
"k8s.io/kubernetes/pkg/api/legacyscheme"
"k8s.io/kubernetes/pkg/apis/apps"
"k8s.io/kubernetes/pkg/apis/batch"
api "k8s.io/kubernetes/pkg/apis/core"
@ -72,26 +69,18 @@ func NewObjectMappingFactory(clientAccessFactory ClientAccessFactory) ObjectMapp
return f
}
// objectLoader attempts to perform discovery against the server, and will fall back to
// the built in mapper if necessary. It supports unstructured objects either way, since
// the underlying Scheme supports Unstructured. The mapper will return converters that can
// convert versioned types to unstructured and back.
func (f *ring1Factory) restMapper() (meta.RESTMapper, error) {
// RESTMapper returns a mapper.
func (f *ring1Factory) RESTMapper() (meta.RESTMapper, error) {
discoveryClient, err := f.clientAccessFactory.DiscoveryClient()
if err != nil {
glog.V(3).Infof("Unable to get a discovery client to find server resources, falling back to hardcoded types: %v", err)
return legacyscheme.Registry.RESTMapper(), nil
return nil, err
}
// allow conversion between typed and unstructured objects
mapper := discovery.NewDeferredDiscoveryRESTMapper(discoveryClient)
// TODO: should this also indicate it recognizes typed objects?
expander := NewShortcutExpander(mapper, discoveryClient)
return expander, err
}
func (f *ring1Factory) RESTMapper() meta.RESTMapper {
return meta.NewLazyRESTMapperLoader(f.restMapper)
return expander, nil
}
func (f *ring1Factory) CategoryExpander() categories.CategoryExpander {

View File

@ -26,6 +26,7 @@ import (
"k8s.io/api/core/v1"
apiequality "k8s.io/apimachinery/pkg/api/equality"
"k8s.io/apimachinery/pkg/api/meta"
"k8s.io/apimachinery/pkg/api/meta/testrestmapper"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/runtime"
@ -34,6 +35,7 @@ import (
"k8s.io/apimachinery/pkg/watch"
manualfake "k8s.io/client-go/rest/fake"
testcore "k8s.io/client-go/testing"
"k8s.io/kubernetes/pkg/api/legacyscheme"
"k8s.io/kubernetes/pkg/api/testapi"
api "k8s.io/kubernetes/pkg/apis/core"
"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/fake"
@ -470,7 +472,7 @@ func TestDiscoveryReplaceAliases(t *testing.T) {
}
ds := &fakeDiscoveryClient{}
mapper := NewShortcutExpander(testapi.Default.RESTMapper(), ds)
mapper := NewShortcutExpander(testrestmapper.TestOnlyStaticRESTMapper(legacyscheme.Registry, legacyscheme.Scheme), ds)
b := resource.NewBuilder(
&resource.Mapper{
RESTMapper: mapper,

View File

@ -19,9 +19,10 @@ package util
import (
"testing"
"k8s.io/apimachinery/pkg/api/meta/testrestmapper"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/kubernetes/pkg/api/testapi"
"k8s.io/kubernetes/pkg/api/legacyscheme"
)
func TestReplaceAliases(t *testing.T) {
@ -126,7 +127,7 @@ func TestReplaceAliases(t *testing.T) {
}
ds := &fakeDiscoveryClient{}
mapper := NewShortcutExpander(testapi.Default.RESTMapper(), ds)
mapper := NewShortcutExpander(testrestmapper.TestOnlyStaticRESTMapper(legacyscheme.Registry, legacyscheme.Scheme), ds)
for _, test := range tests {
ds.serverResourcesHandler = func() ([]*metav1.APIResourceList, error) {
@ -178,7 +179,7 @@ func TestKindFor(t *testing.T) {
}
ds := &fakeDiscoveryClient{}
mapper := NewShortcutExpander(testapi.Default.RESTMapper(), ds)
mapper := NewShortcutExpander(testrestmapper.TestOnlyStaticRESTMapper(legacyscheme.Registry, legacyscheme.Scheme), ds)
for i, test := range tests {
ds.serverResourcesHandler = func() ([]*metav1.APIResourceList, error) {

View File

@ -51,6 +51,7 @@ go_test(
deps = [
"//pkg/kubectl/cmd/util/openapi/testing:go_default_library",
"//pkg/kubectl/scheme:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/api/meta/testrestmapper:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
],
)

View File

@ -20,6 +20,7 @@ import (
"reflect"
"testing"
"k8s.io/apimachinery/pkg/api/meta/testrestmapper"
"k8s.io/kubernetes/pkg/kubectl/scheme"
)
@ -56,7 +57,7 @@ func TestSplitAndParseResourceRequest(t *testing.T) {
},
}
mapper := scheme.Registry.RESTMapper(scheme.Versions...)
mapper := testrestmapper.TestOnlyStaticRESTMapper(scheme.Registry, scheme.Scheme, scheme.Versions...)
for _, test := range tests {
gotInResource, gotFieldsPath, err := SplitAndParseResourceRequest(test.inresource, mapper)
if err != nil {

View File

@ -65,6 +65,7 @@ go_test(
"//vendor/k8s.io/api/core/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/api/equality:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/api/meta:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/api/meta/testrestmapper:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/api/resource:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/labels:go_default_library",

View File

@ -56,6 +56,9 @@ type Builder struct {
// it does not ever need to rely upon discovery.
objectTyper runtime.ObjectTyper
// local indicates that we cannot make server calls
local bool
errs []error
paths []Visitor
@ -142,6 +145,14 @@ func (b *Builder) Schema(schema validation.Schema) *Builder {
return b
}
func (b *Builder) AddError(err error) *Builder {
if err == nil {
return b
}
b.errs = append(b.errs, err)
return b
}
// FilenameParam groups input in two categories: URLs and files (files, directories, STDIN)
// If enforceNamespace is false, namespaces in the specs will be allowed to
// override the default namespace. If it is true, namespaces that don't match
@ -192,6 +203,7 @@ func (b *Builder) Unstructured() *Builder {
return b
}
b.mapper = b.unstructured
b.mapper.localFn = b.isLocal
b.objectTyper = unstructuredscheme.NewUnstructuredObjectTyper()
return b
@ -212,6 +224,7 @@ func (b *Builder) Internal(typer runtime.ObjectTyper) *Builder {
return b
}
b.mapper = b.internal
b.mapper.localFn = b.isLocal
b.objectTyper = typer
return b
@ -227,12 +240,17 @@ func (b *Builder) LocalParam(local bool) *Builder {
// Local will avoid asking the server for results.
func (b *Builder) Local() *Builder {
b.local = true
mapper := *b.mapper
mapper.ClientMapper = DisabledClientForMapping{ClientMapper: mapper.ClientMapper}
b.mapper = &mapper
return b
}
func (b *Builder) isLocal() bool {
return b.local
}
// Mapper returns a copy of the current mapper.
func (b *Builder) Mapper() *Mapper {
mapper := *b.mapper

View File

@ -34,6 +34,7 @@ import (
"k8s.io/api/core/v1"
apiequality "k8s.io/apimachinery/pkg/api/equality"
"k8s.io/apimachinery/pkg/api/meta"
"k8s.io/apimachinery/pkg/api/meta/testrestmapper"
"k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
@ -58,7 +59,7 @@ var (
corev1GV = schema.GroupVersion{Version: "v1"}
corev1Codec = scheme.Codecs.CodecForVersions(scheme.Codecs.LegacyCodec(corev1GV), scheme.Codecs.UniversalDecoder(corev1GV), corev1GV, corev1GV)
metaAccessor = meta.NewAccessor()
restmapper = scheme.Registry.RESTMapper()
restmapper = testrestmapper.TestOnlyStaticRESTMapper(scheme.Registry, scheme.Scheme)
)
func stringBody(body string) io.ReadCloser {
@ -299,7 +300,8 @@ func TestPathBuilderAndVersionedObjectNotDefaulted(t *testing.T) {
if info.Name != "update-demo-kitten" || info.Namespace != "" || info.Object == nil {
t.Errorf("unexpected info: %#v", info)
}
obj := info.AsVersioned(legacyscheme.Scheme)
obj := info.Object
version, ok := obj.(*v1.ReplicationController)
// versioned object does not have defaulting applied
if obj == nil || !ok || version.Spec.Replicas != nil {

View File

@ -22,6 +22,8 @@ import (
client "k8s.io/client-go/rest"
)
type RESTMapperFunc func() (meta.RESTMapper, error)
// RESTClient is a client helper for dealing with RESTful resources
// in a generic way.
type RESTClient interface {

View File

@ -28,6 +28,9 @@ import (
// Mapper is a convenience struct for holding references to the interfaces
// needed to create Info for arbitrary objects.
type Mapper struct {
// localFn indicates the call can't make server requests
localFn func() bool
RESTMapper meta.RESTMapper
ClientMapper ClientMapper
Decoder runtime.Decoder
@ -42,31 +45,34 @@ func (m *Mapper) InfoForData(data []byte, source string) (*Info, error) {
return nil, fmt.Errorf("unable to decode %q: %v", source, err)
}
mapping, err := m.RESTMapper.RESTMapping(gvk.GroupKind(), gvk.Version)
if err != nil {
return nil, fmt.Errorf("unable to recognize %q: %v", source, err)
}
client, err := m.ClientMapper.ClientForMapping(mapping)
if err != nil {
return nil, fmt.Errorf("unable to connect to a server to handle %q: %v", mapping.Resource, err)
}
name, _ := metadataAccessor.Name(obj)
namespace, _ := metadataAccessor.Namespace(obj)
resourceVersion, _ := metadataAccessor.ResourceVersion(obj)
return &Info{
Client: client,
Mapping: mapping,
ret := &Info{
Source: source,
Namespace: namespace,
Name: name,
ResourceVersion: resourceVersion,
Object: obj,
}, nil
}
if m.localFn == nil || !m.localFn() {
mapping, err := m.RESTMapper.RESTMapping(gvk.GroupKind(), gvk.Version)
if err != nil {
return nil, fmt.Errorf("unable to recognize %q: %v", source, err)
}
ret.Mapping = mapping
client, err := m.ClientMapper.ClientForMapping(mapping)
if err != nil {
return nil, fmt.Errorf("unable to connect to a server to handle %q: %v", mapping.Resource, err)
}
ret.Client = client
}
return ret, nil
}
// InfoForObject creates an Info object for the given Object. An error is returned
@ -78,33 +84,37 @@ func (m *Mapper) InfoForObject(obj runtime.Object, typer runtime.ObjectTyper, pr
return nil, fmt.Errorf("unable to get type info from the object %q: %v", reflect.TypeOf(obj), err)
}
groupVersionKind := groupVersionKinds[0]
gvk := groupVersionKinds[0]
if len(groupVersionKinds) > 1 && len(preferredGVKs) > 0 {
groupVersionKind = preferredObjectKind(groupVersionKinds, preferredGVKs)
gvk = preferredObjectKind(groupVersionKinds, preferredGVKs)
}
mapping, err := m.RESTMapper.RESTMapping(groupVersionKind.GroupKind(), groupVersionKind.Version)
if err != nil {
return nil, fmt.Errorf("unable to recognize %v: %v", groupVersionKind, err)
}
client, err := m.ClientMapper.ClientForMapping(mapping)
if err != nil {
return nil, fmt.Errorf("unable to connect to a server to handle %q: %v", mapping.Resource, err)
}
name, _ := metadataAccessor.Name(obj)
namespace, _ := metadataAccessor.Namespace(obj)
resourceVersion, _ := metadataAccessor.ResourceVersion(obj)
return &Info{
Client: client,
Mapping: mapping,
ret := &Info{
Namespace: namespace,
Name: name,
ResourceVersion: resourceVersion,
Object: obj,
}, nil
}
if m.localFn == nil || !m.localFn() {
mapping, err := m.RESTMapper.RESTMapping(gvk.GroupKind(), gvk.Version)
if err != nil {
return nil, fmt.Errorf("unable to recognize %v", err)
}
ret.Mapping = mapping
client, err := m.ClientMapper.ClientForMapping(mapping)
if err != nil {
return nil, fmt.Errorf("unable to connect to a server to handle %q: %v", mapping.Resource, err)
}
ret.Client = client
}
return ret, nil
}
// preferredObjectKind picks the possibility that most closely matches the priority list in this order:

View File

@ -180,22 +180,6 @@ func (i *Info) ResourceMapping() *meta.RESTMapping {
return i.Mapping
}
// Versioned returns the object as a Go type in the mapping's version or returns an error.
func (i *Info) versioned(convertor runtime.ObjectConvertor) (runtime.Object, error) {
return convertor.ConvertToVersion(i.Object, i.Mapping.GroupVersionKind.GroupVersion())
}
// AsVersioned returns the object as a Go object in the external form if possible (matching the
// group version kind of the mapping, or i.Object if it cannot be converted.
// Deprecated this function will be removed once calling code is updated to indicate the correct
// negoticatedserializers during construction of the builder
func (i *Info) AsVersioned(convertor runtime.ObjectConvertor) runtime.Object {
if obj, err := i.versioned(convertor); err == nil {
return obj
}
return i.Object
}
// VisitorList implements Visit for the sub visitors it contains. The first error
// returned from a child Visitor will terminate iteration.
type VisitorList []Visitor

View File

@ -71,18 +71,6 @@ func init() {
"PersistentVolume",
"ComponentStatus",
),
IgnoredKinds: sets.NewString(
"ListOptions",
"DeleteOptions",
"Status",
"PodLogOptions",
"PodExecOptions",
"PodAttachOptions",
"PodPortForwardOptions",
"PodProxyOptions",
"NodeProxyOptions",
"ServiceProxyOptions",
),
},
announced.VersionToSchemeFunc{
corev1.SchemeGroupVersion.Version: corev1.AddToScheme,

View File

@ -30,6 +30,7 @@ go_test(
"//pkg/api/legacyscheme:go_default_library",
"//pkg/apis/core:go_default_library",
"//pkg/kubeapiserver/admission:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/api/meta/testrestmapper:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",

View File

@ -20,6 +20,7 @@ import (
"strings"
"testing"
"k8s.io/apimachinery/pkg/api/meta/testrestmapper"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
@ -87,7 +88,7 @@ func newGCPermissionsEnforcement() (*gcPermissionsEnforcement, error) {
}
genericPluginInitializer := initializer.New(nil, nil, fakeAuthorizer{}, nil)
pluginInitializer := kubeadmission.NewPluginInitializer(nil, nil, nil, legacyscheme.Registry.RESTMapper(), nil)
pluginInitializer := kubeadmission.NewPluginInitializer(nil, nil, nil, testrestmapper.TestOnlyStaticRESTMapper(legacyscheme.Registry, legacyscheme.Scheme), nil)
initializersChain := admission.PluginInitializers{}
initializersChain = append(initializersChain, genericPluginInitializer)
initializersChain = append(initializersChain, pluginInitializer)

View File

@ -65,6 +65,7 @@ filegroup(
srcs = [
":package-srcs",
"//staging/src/k8s.io/apimachinery/pkg/api/meta/table:all-srcs",
"//staging/src/k8s.io/apimachinery/pkg/api/meta/testrestmapper:all-srcs",
],
tags = ["automanaged"],
)

View File

@ -0,0 +1,30 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library")
go_library(
name = "go_default_library",
srcs = ["test_restmapper.go"],
importpath = "k8s.io/apimachinery/pkg/api/meta/testrestmapper",
visibility = ["//visibility:public"],
deps = [
"//vendor/k8s.io/apimachinery/pkg/api/meta:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apimachinery:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apimachinery/registered:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@ -0,0 +1,132 @@
/*
Copyright 2018 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 testrestmapper
import (
"k8s.io/apimachinery/pkg/api/meta"
"k8s.io/apimachinery/pkg/apimachinery"
"k8s.io/apimachinery/pkg/apimachinery/registered"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/util/sets"
)
// TestOnlyStaticRESTMapper returns a union RESTMapper of all known types with priorities chosen in the following order:
// 1. legacy kube group preferred version, extensions preferred version, metrics perferred version, legacy
// kube any version, extensions any version, metrics any version, all other groups alphabetical preferred version,
// all other groups alphabetical.
func TestOnlyStaticRESTMapper(m *registered.APIRegistrationManager, scheme *runtime.Scheme, versionPatterns ...schema.GroupVersion) meta.RESTMapper {
unionMapper := meta.MultiRESTMapper{}
unionedGroups := sets.NewString()
for _, enabledVersion := range m.RegisteredGroupVersions() {
if !unionedGroups.Has(enabledVersion.Group) {
unionedGroups.Insert(enabledVersion.Group)
groupMeta := m.GroupOrDie(enabledVersion.Group)
if groupMeta != nil {
unionMapper = append(unionMapper, newRESTMapper(scheme, groupMeta))
}
}
}
if len(versionPatterns) != 0 {
resourcePriority := []schema.GroupVersionResource{}
kindPriority := []schema.GroupVersionKind{}
for _, versionPriority := range versionPatterns {
resourcePriority = append(resourcePriority, versionPriority.WithResource(meta.AnyResource))
kindPriority = append(kindPriority, versionPriority.WithKind(meta.AnyKind))
}
return meta.PriorityRESTMapper{Delegate: unionMapper, ResourcePriority: resourcePriority, KindPriority: kindPriority}
}
prioritizedGroups := []string{"", "extensions", "metrics"}
resourcePriority, kindPriority := prioritiesForGroups(m, prioritizedGroups...)
prioritizedGroupsSet := sets.NewString(prioritizedGroups...)
remainingGroups := sets.String{}
for _, enabledVersion := range m.RegisteredGroupVersions() {
if !prioritizedGroupsSet.Has(enabledVersion.Group) {
remainingGroups.Insert(enabledVersion.Group)
}
}
remainingResourcePriority, remainingKindPriority := prioritiesForGroups(m, remainingGroups.List()...)
resourcePriority = append(resourcePriority, remainingResourcePriority...)
kindPriority = append(kindPriority, remainingKindPriority...)
return meta.PriorityRESTMapper{Delegate: unionMapper, ResourcePriority: resourcePriority, KindPriority: kindPriority}
}
// prioritiesForGroups returns the resource and kind priorities for a PriorityRESTMapper, preferring the preferred version of each group first,
// then any non-preferred version of the group second.
func prioritiesForGroups(m *registered.APIRegistrationManager, groups ...string) ([]schema.GroupVersionResource, []schema.GroupVersionKind) {
resourcePriority := []schema.GroupVersionResource{}
kindPriority := []schema.GroupVersionKind{}
for _, group := range groups {
availableVersions := m.RegisteredVersionsForGroup(group)
if len(availableVersions) > 0 {
resourcePriority = append(resourcePriority, availableVersions[0].WithResource(meta.AnyResource))
kindPriority = append(kindPriority, availableVersions[0].WithKind(meta.AnyKind))
}
}
for _, group := range groups {
resourcePriority = append(resourcePriority, schema.GroupVersionResource{Group: group, Version: meta.AnyVersion, Resource: meta.AnyResource})
kindPriority = append(kindPriority, schema.GroupVersionKind{Group: group, Version: meta.AnyVersion, Kind: meta.AnyKind})
}
return resourcePriority, kindPriority
}
func newRESTMapper(scheme *runtime.Scheme, groupMeta *apimachinery.GroupMeta) meta.RESTMapper {
// the list of kinds that are scoped at the root of the api hierarchy
// if a kind is not enumerated here, it is assumed to have a namespace scope
rootScoped := sets.NewString()
if groupMeta.RootScopedKinds != nil {
rootScoped = groupMeta.RootScopedKinds
}
mapper := meta.NewDefaultRESTMapper(groupMeta.GroupVersions)
for _, gv := range groupMeta.GroupVersions {
for kind := range scheme.KnownTypes(gv) {
if ignoredKinds.Has(kind) {
continue
}
scope := meta.RESTScopeNamespace
if rootScoped.Has(kind) {
scope = meta.RESTScopeRoot
}
mapper.Add(gv.WithKind(kind), scope)
}
}
return mapper
}
// hardcoded is good enough for the test we're running
var ignoredKinds = sets.NewString(
"ListOptions",
"DeleteOptions",
"Status",
"PodLogOptions",
"PodExecOptions",
"PodAttachOptions",
"PodPortForwardOptions",
"PodProxyOptions",
"NodeProxyOptions",
"ServiceProxyOptions",
)

View File

@ -13,7 +13,6 @@ go_library(
],
importpath = "k8s.io/apimachinery/pkg/apimachinery",
deps = [
"//vendor/k8s.io/apimachinery/pkg/api/meta:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library",
],

View File

@ -11,7 +11,6 @@ go_library(
importpath = "k8s.io/apimachinery/pkg/apimachinery/announced",
deps = [
"//vendor/github.com/golang/glog:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/api/meta:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apimachinery:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apimachinery/registered:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",

View File

@ -21,7 +21,6 @@ import (
"github.com/golang/glog"
"k8s.io/apimachinery/pkg/api/meta"
"k8s.io/apimachinery/pkg/apimachinery"
"k8s.io/apimachinery/pkg/apimachinery/registered"
"k8s.io/apimachinery/pkg/runtime"
@ -49,7 +48,6 @@ type GroupMetaFactoryArgs struct {
VersionPreferenceOrder []string
// RootScopedKinds are resources that are not namespaced.
RootScopedKinds sets.String // nil is allowed
IgnoredKinds sets.String // nil is allowed
// May be nil if there are no internal objects.
AddInternalObjectsToScheme SchemeFunc
@ -154,40 +152,9 @@ func (gmf *GroupMetaFactory) Register(m *registered.APIRegistrationManager, sche
GroupVersions: externalVersions,
RootScopedKinds: gmf.GroupArgs.RootScopedKinds,
}
groupMeta.RESTMapper = gmf.newRESTMapper(scheme, externalVersions, groupMeta)
if err := m.RegisterGroup(*groupMeta); err != nil {
return err
}
return nil
}
func (gmf *GroupMetaFactory) newRESTMapper(scheme *runtime.Scheme, externalVersions []schema.GroupVersion, groupMeta *apimachinery.GroupMeta) meta.RESTMapper {
// the list of kinds that are scoped at the root of the api hierarchy
// if a kind is not enumerated here, it is assumed to have a namespace scope
rootScoped := sets.NewString()
if gmf.GroupArgs.RootScopedKinds != nil {
rootScoped = gmf.GroupArgs.RootScopedKinds
}
ignoredKinds := sets.NewString()
if gmf.GroupArgs.IgnoredKinds != nil {
ignoredKinds = gmf.GroupArgs.IgnoredKinds
}
mapper := meta.NewDefaultRESTMapper(externalVersions)
for _, gv := range externalVersions {
for kind := range scheme.KnownTypes(gv) {
if ignoredKinds.Has(kind) {
continue
}
scope := meta.RESTScopeNamespace
if rootScoped.Has(kind) {
scope = meta.RESTScopeRoot
}
mapper.Add(gv.WithKind(kind), scope)
}
}
return mapper
}

View File

@ -21,10 +21,8 @@ go_library(
srcs = ["registered.go"],
importpath = "k8s.io/apimachinery/pkg/apimachinery/registered",
deps = [
"//vendor/k8s.io/apimachinery/pkg/api/meta:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apimachinery:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library",
],
)

View File

@ -22,10 +22,8 @@ import (
"sort"
"strings"
"k8s.io/apimachinery/pkg/api/meta"
"k8s.io/apimachinery/pkg/apimachinery"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/util/sets"
)
// APIRegistrationManager provides the concept of what API groups are enabled.
@ -140,73 +138,6 @@ func (m *APIRegistrationManager) GroupOrDie(group string) *apimachinery.GroupMet
return &groupMetaCopy
}
// RESTMapper returns a union RESTMapper of all known types with priorities chosen in the following order:
// 1. legacy kube group preferred version, extensions preferred version, metrics perferred version, legacy
// kube any version, extensions any version, metrics any version, all other groups alphabetical preferred version,
// all other groups alphabetical.
func (m *APIRegistrationManager) RESTMapper(versionPatterns ...schema.GroupVersion) meta.RESTMapper {
unionMapper := meta.MultiRESTMapper{}
unionedGroups := sets.NewString()
for enabledVersion := range m.registeredVersions {
if !unionedGroups.Has(enabledVersion.Group) {
unionedGroups.Insert(enabledVersion.Group)
groupMeta := m.groupMetaMap[enabledVersion.Group]
if groupMeta != nil {
unionMapper = append(unionMapper, groupMeta.RESTMapper)
}
}
}
if len(versionPatterns) != 0 {
resourcePriority := []schema.GroupVersionResource{}
kindPriority := []schema.GroupVersionKind{}
for _, versionPriority := range versionPatterns {
resourcePriority = append(resourcePriority, versionPriority.WithResource(meta.AnyResource))
kindPriority = append(kindPriority, versionPriority.WithKind(meta.AnyKind))
}
return meta.PriorityRESTMapper{Delegate: unionMapper, ResourcePriority: resourcePriority, KindPriority: kindPriority}
}
prioritizedGroups := []string{"", "extensions", "metrics"}
resourcePriority, kindPriority := m.prioritiesForGroups(prioritizedGroups...)
prioritizedGroupsSet := sets.NewString(prioritizedGroups...)
remainingGroups := sets.String{}
for enabledVersion := range m.registeredVersions {
if !prioritizedGroupsSet.Has(enabledVersion.Group) {
remainingGroups.Insert(enabledVersion.Group)
}
}
remainingResourcePriority, remainingKindPriority := m.prioritiesForGroups(remainingGroups.List()...)
resourcePriority = append(resourcePriority, remainingResourcePriority...)
kindPriority = append(kindPriority, remainingKindPriority...)
return meta.PriorityRESTMapper{Delegate: unionMapper, ResourcePriority: resourcePriority, KindPriority: kindPriority}
}
// prioritiesForGroups returns the resource and kind priorities for a PriorityRESTMapper, preferring the preferred version of each group first,
// then any non-preferred version of the group second.
func (m *APIRegistrationManager) prioritiesForGroups(groups ...string) ([]schema.GroupVersionResource, []schema.GroupVersionKind) {
resourcePriority := []schema.GroupVersionResource{}
kindPriority := []schema.GroupVersionKind{}
for _, group := range groups {
availableVersions := m.RegisteredVersionsForGroup(group)
if len(availableVersions) > 0 {
resourcePriority = append(resourcePriority, availableVersions[0].WithResource(meta.AnyResource))
kindPriority = append(kindPriority, availableVersions[0].WithKind(meta.AnyKind))
}
}
for _, group := range groups {
resourcePriority = append(resourcePriority, schema.GroupVersionResource{Group: group, Version: meta.AnyVersion, Resource: meta.AnyResource})
kindPriority = append(kindPriority, schema.GroupVersionKind{Group: group, Version: meta.AnyVersion, Kind: meta.AnyKind})
}
return resourcePriority, kindPriority
}
// AllPreferredGroupVersions returns the preferred versions of all registered
// groups in the form of "group1/version1,group2/version2,..."
func (m *APIRegistrationManager) AllPreferredGroupVersions() string {

View File

@ -17,7 +17,6 @@ limitations under the License.
package apimachinery
import (
"k8s.io/apimachinery/pkg/api/meta"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/util/sets"
)
@ -28,8 +27,4 @@ type GroupMeta struct {
GroupVersions []schema.GroupVersion
RootScopedKinds sets.String
// RESTMapper provides the default mapping between REST paths and the objects declared in a Scheme and all known
// versions.
RESTMapper meta.RESTMapper
}

View File

@ -16,7 +16,6 @@ go_test(
embed = [":go_default_library"],
deps = [
"//vendor/github.com/stretchr/testify/assert:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/api/meta:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apimachinery:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",

View File

@ -34,7 +34,6 @@ import (
// "github.com/go-openapi/spec"
"github.com/stretchr/testify/assert"
"k8s.io/apimachinery/pkg/api/meta"
"k8s.io/apimachinery/pkg/apimachinery"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
@ -153,13 +152,8 @@ func TestInstallAPIGroups(t *testing.T) {
scheme.AddKnownTypes(v1GroupVersion, &metav1.Status{})
metav1.AddToGroupVersion(scheme, v1GroupVersion)
mapper := meta.NewDefaultRESTMapper([]schema.GroupVersion{gv})
for kind := range scheme.KnownTypes(gv) {
mapper.Add(gv.WithKind(kind), meta.RESTScopeNamespace)
}
groupMeta := apimachinery.GroupMeta{
GroupVersions: []schema.GroupVersion{gv},
RESTMapper: mapper,
}
return APIGroupInfo{

View File

@ -147,8 +147,11 @@ func TestServerSidePrint(t *testing.T) {
printer := newFakePrinter(printersinternal.AddHandlers)
factory := util.NewFactory(clientcmd.NewDefaultClientConfig(*createKubeConfig(s.URL), &clientcmd.ConfigOverrides{}))
mapper := factory.RESTMapper()
mapper, err := factory.RESTMapper()
if err != nil {
t.Errorf("unexpected error getting mapper: %v", err)
return
}
for gvk, apiType := range legacyscheme.Scheme.AllKnownTypes() {
// we do not care about internal objects or lists // TODO make sure this is always true
if gvk.Version == runtime.APIVersionInternal || strings.HasSuffix(apiType.Name(), "List") {

View File

@ -21,7 +21,6 @@ go_test(
"//cmd/kube-apiserver/app/options:go_default_library",
"//pkg/api/legacyscheme:go_default_library",
"//pkg/apis/core:go_default_library",
"//pkg/kubectl/cmd/util:go_default_library",
"//pkg/master:go_default_library",
"//test/integration:go_default_library",
"//test/integration/framework:go_default_library",
@ -38,10 +37,10 @@ go_test(
"//vendor/k8s.io/apiserver/pkg/server:go_default_library",
"//vendor/k8s.io/apiserver/pkg/server/options:go_default_library",
"//vendor/k8s.io/apiserver/pkg/storage/storagebackend:go_default_library",
"//vendor/k8s.io/client-go/discovery:go_default_library",
"//vendor/k8s.io/client-go/discovery/cached:go_default_library",
"//vendor/k8s.io/client-go/kubernetes:go_default_library",
"//vendor/k8s.io/client-go/rest:go_default_library",
"//vendor/k8s.io/client-go/tools/clientcmd:go_default_library",
"//vendor/k8s.io/client-go/tools/clientcmd/api:go_default_library",
"//vendor/k8s.io/client-go/util/flowcontrol:go_default_library",
],
)

View File

@ -43,16 +43,15 @@ import (
genericapiserver "k8s.io/apiserver/pkg/server"
genericapiserveroptions "k8s.io/apiserver/pkg/server/options"
"k8s.io/apiserver/pkg/storage/storagebackend"
"k8s.io/client-go/discovery"
cacheddiscovery "k8s.io/client-go/discovery/cached"
clientset "k8s.io/client-go/kubernetes"
restclient "k8s.io/client-go/rest"
"k8s.io/client-go/tools/clientcmd"
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
"k8s.io/client-go/util/flowcontrol"
"k8s.io/kubernetes/cmd/kube-apiserver/app"
"k8s.io/kubernetes/cmd/kube-apiserver/app/options"
"k8s.io/kubernetes/pkg/api/legacyscheme"
kapi "k8s.io/kubernetes/pkg/apis/core"
"k8s.io/kubernetes/pkg/kubectl/cmd/util"
"k8s.io/kubernetes/test/integration"
"k8s.io/kubernetes/test/integration/framework"
@ -434,84 +433,84 @@ var etcdStorageData = map[schema.GroupVersionResource]struct {
var ephemeralWhiteList = createEphemeralWhiteList(
// k8s.io/kubernetes/pkg/api/v1
gvr("", "v1", "bindings"), // annotation on pod, not stored in etcd
gvr("", "v1", "rangeallocations"), // stored in various places in etcd but cannot be directly created
gvr("", "v1", "componentstatuses"), // status info not stored in etcd
gvr("", "v1", "serializedreferences"), // used for serilization, not stored in etcd
gvr("", "v1", "nodeconfigsources"), // subfield of node.spec, but shouldn't be directly created
gvr("", "v1", "podstatusresults"), // wrapper object not stored in etcd
gvk("", "v1", "Binding"), // annotation on pod, not stored in etcd
gvk("", "v1", "RangeAllocation"), // stored in various places in etcd but cannot be directly created
gvk("", "v1", "ComponentStatus"), // status info not stored in etcd
gvk("", "v1", "SerializedReference"), // used for serilization, not stored in etcd
gvk("", "v1", "NodeConfigSource"), // subfield of node.spec, but shouldn't be directly created
gvk("", "v1", "PodStatusResult"), // wrapper object not stored in etcd
// --
// k8s.io/kubernetes/pkg/apis/authentication/v1beta1
gvr("authentication.k8s.io", "v1beta1", "tokenreviews"), // not stored in etcd
gvk("authentication.k8s.io", "v1beta1", "TokenReview"), // not stored in etcd
// --
// k8s.io/kubernetes/pkg/apis/authentication/v1
gvr("authentication.k8s.io", "v1", "tokenreviews"), // not stored in etcd
gvr("authentication.k8s.io", "v1", "tokenrequests"), // not stored in etcd
gvk("authentication.k8s.io", "v1", "TokenReview"), // not stored in etcd
gvk("authentication.k8s.io", "v1", "TokenRequest"), // not stored in etcd
// --
// k8s.io/kubernetes/pkg/apis/authorization/v1beta1
// SRR objects that are not stored in etcd
gvr("authorization.k8s.io", "v1beta1", "selfsubjectrulesreviews"),
gvk("authorization.k8s.io", "v1beta1", "SelfSubjectRulesReview"),
// SAR objects that are not stored in etcd
gvr("authorization.k8s.io", "v1beta1", "selfsubjectaccessreviews"),
gvr("authorization.k8s.io", "v1beta1", "localsubjectaccessreviews"),
gvr("authorization.k8s.io", "v1beta1", "subjectaccessreviews"),
gvk("authorization.k8s.io", "v1beta1", "SelfSubjectAccessReview"),
gvk("authorization.k8s.io", "v1beta1", "LocalSubjectAccessReview"),
gvk("authorization.k8s.io", "v1beta1", "SubjectAccessReview"),
// --
// k8s.io/kubernetes/pkg/apis/authorization/v1
// SRR objects that are not stored in etcd
gvr("authorization.k8s.io", "v1", "selfsubjectrulesreviews"),
gvk("authorization.k8s.io", "v1", "SelfSubjectRulesReview"),
// SAR objects that are not stored in etcd
gvr("authorization.k8s.io", "v1", "selfsubjectaccessreviews"),
gvr("authorization.k8s.io", "v1", "localsubjectaccessreviews"),
gvr("authorization.k8s.io", "v1", "subjectaccessreviews"),
gvk("authorization.k8s.io", "v1", "SelfSubjectAccessReview"),
gvk("authorization.k8s.io", "v1", "LocalSubjectAccessReview"),
gvk("authorization.k8s.io", "v1", "SubjectAccessReview"),
// --
// k8s.io/kubernetes/pkg/apis/autoscaling/v1
gvr("autoscaling", "v1", "scales"), // not stored in etcd, part of kapiv1.ReplicationController
gvk("autoscaling", "v1", "Scale"), // not stored in etcd, part of kapiv1.ReplicationController
// --
// k8s.io/kubernetes/pkg/apis/apps/v1beta1
gvr("apps", "v1beta1", "scales"), // not stored in etcd, part of kapiv1.ReplicationController
gvr("apps", "v1beta1", "deploymentrollbacks"), // used to rollback deployment, not stored in etcd
gvk("apps", "v1beta1", "Scale"), // not stored in etcd, part of kapiv1.ReplicationController
gvk("apps", "v1beta1", "DeploymentRollback"), // used to rollback deployment, not stored in etcd
// --
// k8s.io/kubernetes/pkg/apis/apps/v1beta2
gvr("apps", "v1beta2", "scales"), // not stored in etcd, part of kapiv1.ReplicationController
gvk("apps", "v1beta2", "Scale"), // not stored in etcd, part of kapiv1.ReplicationController
// --
// k8s.io/kubernetes/pkg/apis/batch/v1beta1
gvr("batch", "v1beta1", "jobtemplates"), // not stored in etcd
gvk("batch", "v1beta1", "JobTemplate"), // not stored in etcd
// --
// k8s.io/kubernetes/pkg/apis/batch/v2alpha1
gvr("batch", "v2alpha1", "jobtemplates"), // not stored in etcd
gvk("batch", "v2alpha1", "JobTemplate"), // not stored in etcd
// --
// k8s.io/kubernetes/pkg/apis/componentconfig/v1alpha1
gvr("componentconfig", "v1alpha1", "kubeschedulerconfigurations"), // not stored in etcd
gvk("componentconfig", "v1alpha1", "KubeSchedulerConfiguration"), // not stored in etcd
// --
// k8s.io/kubernetes/pkg/apis/extensions/v1beta1
gvr("extensions", "v1beta1", "deploymentrollbacks"), // used to rollback deployment, not stored in etcd
gvr("extensions", "v1beta1", "replicationcontrollerdummies"), // not stored in etcd
gvr("extensions", "v1beta1", "scales"), // not stored in etcd, part of kapiv1.ReplicationController
gvk("extensions", "v1beta1", "DeploymentRollback"), // used to rollback deployment, not stored in etcd
gvk("extensions", "v1beta1", "ReplicationControllerDummy"), // not stored in etcd
gvk("extensions", "v1beta1", "Scale"), // not stored in etcd, part of kapiv1.ReplicationController
// --
// k8s.io/kubernetes/pkg/apis/imagepolicy/v1alpha1
gvr("imagepolicy.k8s.io", "v1alpha1", "imagereviews"), // not stored in etcd
gvk("imagepolicy.k8s.io", "v1alpha1", "ImageReview"), // not stored in etcd
// --
// k8s.io/kubernetes/pkg/apis/policy/v1beta1
gvr("policy", "v1beta1", "evictions"), // not stored in etcd, deals with evicting kapiv1.Pod
gvk("policy", "v1beta1", "Eviction"), // not stored in etcd, deals with evicting kapiv1.Pod
// --
// k8s.io/kubernetes/pkg/apis/admission/v1beta1
gvr("admission.k8s.io", "v1beta1", "admissionreviews"), // not stored in etcd, call out to webhooks.
gvk("admission.k8s.io", "v1beta1", "AdmissionReview"), // not stored in etcd, call out to webhooks.
// --
)
@ -561,7 +560,7 @@ func TestEtcdStoragePath(t *testing.T) {
kindSeen := sets.NewString()
pathSeen := map[string][]schema.GroupVersionResource{}
etcdSeen := map[schema.GroupVersionResource]empty{}
ephemeralSeen := map[schema.GroupVersionResource]empty{}
ephemeralSeen := map[schema.GroupVersionKind]empty{}
cohabitatingResources := map[string]map[schema.GroupVersionKind]empty{}
for gvk, apiType := range legacyscheme.Scheme.AllKnownTypes() {
@ -577,6 +576,11 @@ func TestEtcdStoragePath(t *testing.T) {
kindSeen.Insert(kind)
continue
}
_, isEphemeral := ephemeralWhiteList[gvk]
if isEphemeral {
ephemeralSeen[gvk] = empty{}
continue
}
mapping, err := mapper.RESTMapping(gvk.GroupKind(), gvk.Version)
if err != nil {
@ -588,25 +592,12 @@ func TestEtcdStoragePath(t *testing.T) {
etcdSeen[gvResource] = empty{}
testData, hasTest := etcdStorageData[gvResource]
_, isEphemeral := ephemeralWhiteList[gvResource]
if !hasTest && !isEphemeral {
if !hasTest {
t.Errorf("no test data for %s from %s. Please add a test for your new type to etcdStorageData.", kind, pkgPath)
continue
}
if hasTest && isEphemeral {
t.Errorf("duplicate test data for %s from %s. Object has both test data and is ephemeral.", kind, pkgPath)
continue
}
if isEphemeral { // TODO it would be nice if we could remove this and infer if an object is not stored in etcd
// t.Logf("Skipping test for %s from %s", kind, pkgPath)
ephemeralSeen[gvResource] = empty{}
delete(etcdSeen, gvResource)
continue
}
if len(testData.expectedEtcdPath) == 0 {
t.Errorf("empty test data for %s from %s", kind, pkgPath)
continue
@ -811,7 +802,11 @@ func startRealMasterOrDie(t *testing.T, certDir string) (*allClient, clientv3.KV
t.Fatal(err)
}
mapper := util.NewFactory(clientcmd.NewDefaultClientConfig(*clientcmdapi.NewConfig(), &clientcmd.ConfigOverrides{})).RESTMapper()
discoveryClient := cacheddiscovery.NewMemCacheClient(kubeClient.Discovery())
restMapper := discovery.NewDeferredDiscoveryRESTMapper(discoveryClient)
restMapper.Reset()
// allow conversion between typed and unstructured objects
mapper := discovery.NewDeferredDiscoveryRESTMapper(discoveryClient)
return client, kvClient, mapper
}
@ -888,17 +883,21 @@ func gvr(g, v, r string) schema.GroupVersionResource {
return schema.GroupVersionResource{Group: g, Version: v, Resource: r}
}
func gvk(g, v, k string) schema.GroupVersionKind {
return schema.GroupVersionKind{Group: g, Version: v, Kind: k}
}
func gvkP(g, v, k string) *schema.GroupVersionKind {
return &schema.GroupVersionKind{Group: g, Version: v, Kind: k}
}
func createEphemeralWhiteList(gvrs ...schema.GroupVersionResource) map[schema.GroupVersionResource]empty {
ephemeral := map[schema.GroupVersionResource]empty{}
for _, gvResource := range gvrs {
if _, ok := ephemeral[gvResource]; ok {
func createEphemeralWhiteList(gvks ...schema.GroupVersionKind) map[schema.GroupVersionKind]empty {
ephemeral := map[schema.GroupVersionKind]empty{}
for _, gvKind := range gvks {
if _, ok := ephemeral[gvKind]; ok {
panic("invalid ephemeral whitelist contains duplicate keys")
}
ephemeral[gvResource] = empty{}
ephemeral[gvKind] = empty{}
}
return ephemeral
}