mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-30 15:05:27 +00:00
Unify Object and UnstructuredObject
The unified RESTMapper and Typer follow the new rules, but on error will fallback to the legacy path (while still supporting Unstructured objects). This allows callers to handle the appropriate distinction themselves if necessary. Add a LocalParam() method to the resource.Builder that DRYs up a large chunk of complicated code in set commands.
This commit is contained in:
parent
7563a0c4d8
commit
04ab96d2bd
@ -189,13 +189,10 @@ func (o AnnotateOptions) RunAnnotate(f cmdutil.Factory, cmd *cobra.Command) erro
|
||||
changeCause := f.Command(cmd, false)
|
||||
|
||||
includeUninitialized := cmdutil.ShouldIncludeUninitialized(cmd, false)
|
||||
b := f.NewBuilder()
|
||||
if o.local {
|
||||
b = b.Local()
|
||||
} else {
|
||||
b = b.Unstructured()
|
||||
}
|
||||
b = b.ContinueOnError().
|
||||
b := f.NewBuilder().
|
||||
Unstructured().
|
||||
LocalParam(o.local).
|
||||
ContinueOnError().
|
||||
NamespaceParam(namespace).DefaultNamespace().
|
||||
FilenameParam(enforceNamespace, &o.FilenameOptions).
|
||||
IncludeUninitialized(includeUninitialized).
|
||||
|
@ -112,7 +112,7 @@ func (o *SetLastAppliedOptions) Complete(f cmdutil.Factory, cmd *cobra.Command)
|
||||
o.Codec = f.JSONEncoder()
|
||||
|
||||
var err error
|
||||
o.Mapper, o.Typer = f.UnstructuredObject()
|
||||
o.Mapper, o.Typer = f.Object()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -128,22 +128,20 @@ func (o *ConvertOptions) Complete(f cmdutil.Factory, out io.Writer, cmd *cobra.C
|
||||
}
|
||||
|
||||
// build the builder
|
||||
o.builder = f.NewBuilder()
|
||||
o.builder = f.NewBuilder().LocalParam(o.local)
|
||||
if !o.local {
|
||||
schema, err := f.Validator(cmdutil.GetFlagBool(cmd, "validate"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
o.builder = o.builder.Schema(schema)
|
||||
} else {
|
||||
o.builder = o.builder.Local()
|
||||
o.builder.Schema(schema)
|
||||
}
|
||||
|
||||
cmdNamespace, _, err := f.DefaultNamespace()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
o.builder = o.builder.NamespaceParam(cmdNamespace).
|
||||
o.builder.NamespaceParam(cmdNamespace).
|
||||
ContinueOnError().
|
||||
FilenameParam(false, &o.FilenameOptions).
|
||||
Flatten()
|
||||
|
@ -18,6 +18,7 @@ package cmd
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
@ -98,30 +99,30 @@ func TestConvertObject(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
f, tf, _, _ := cmdtesting.NewAPIFactory()
|
||||
tf.UnstructuredClient = &fake.RESTClient{
|
||||
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
|
||||
t.Fatalf("unexpected request: %#v\n%#v", req.URL, req)
|
||||
return nil, nil
|
||||
}),
|
||||
}
|
||||
tf.Namespace = "test"
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
|
||||
for _, tc := range testcases {
|
||||
cmd := NewCmdConvert(f, buf)
|
||||
cmd.Flags().Set("filename", tc.file)
|
||||
cmd.Flags().Set("output-version", tc.outputVersion)
|
||||
cmd.Flags().Set("local", "true")
|
||||
cmd.Flags().Set("output", "go-template")
|
||||
|
||||
for _, field := range tc.fields {
|
||||
buf.Reset()
|
||||
tf.Printer, _ = printers.NewTemplatePrinter([]byte(field.template))
|
||||
cmd.Run(cmd, []string{})
|
||||
if buf.String() != field.expected {
|
||||
t.Errorf("unexpected output when converting %s to %q, expected: %q, but got %q", tc.file, tc.outputVersion, field.expected, buf.String())
|
||||
}
|
||||
t.Run(fmt.Sprintf("%s %s", tc.name, field), func(t *testing.T) {
|
||||
f, tf, _, _ := cmdtesting.NewAPIFactory()
|
||||
tf.UnstructuredClient = &fake.RESTClient{
|
||||
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
|
||||
t.Fatalf("unexpected request: %#v\n%#v", req.URL, req)
|
||||
return nil, nil
|
||||
}),
|
||||
}
|
||||
tf.Namespace = "test"
|
||||
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
cmd := NewCmdConvert(f, buf)
|
||||
cmd.Flags().Set("filename", tc.file)
|
||||
cmd.Flags().Set("output-version", tc.outputVersion)
|
||||
cmd.Flags().Set("local", "true")
|
||||
cmd.Flags().Set("output", "go-template")
|
||||
tf.Printer, _ = printers.NewTemplatePrinter([]byte(field.template))
|
||||
cmd.Run(cmd, []string{})
|
||||
if buf.String() != field.expected {
|
||||
t.Errorf("unexpected output when converting %s to %q, expected: %q, but got %q", tc.file, tc.outputVersion, field.expected, buf.String())
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -191,13 +191,9 @@ func (o *LabelOptions) RunLabel(f cmdutil.Factory, cmd *cobra.Command) error {
|
||||
changeCause := f.Command(cmd, false)
|
||||
|
||||
includeUninitialized := cmdutil.ShouldIncludeUninitialized(cmd, false)
|
||||
b := f.NewBuilder()
|
||||
if o.local {
|
||||
b = b.Local()
|
||||
} else {
|
||||
b = b.Unstructured()
|
||||
}
|
||||
b = b.
|
||||
b := f.NewBuilder().
|
||||
Unstructured().
|
||||
LocalParam(o.local).
|
||||
ContinueOnError().
|
||||
NamespaceParam(cmdNamespace).DefaultNamespace().
|
||||
FilenameParam(enforceNamespace, &o.FilenameOptions).
|
||||
@ -304,16 +300,10 @@ func (o *LabelOptions) RunLabel(f cmdutil.Factory, cmd *cobra.Command) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
var mapper meta.RESTMapper
|
||||
if o.local {
|
||||
mapper, _ = f.Object()
|
||||
} else {
|
||||
mapper, _ = f.UnstructuredObject()
|
||||
}
|
||||
if o.outputFormat != "" {
|
||||
return f.PrintObject(cmd, o.local, mapper, outputObj, o.out)
|
||||
return f.PrintObject(cmd, o.local, r.Mapper().RESTMapper, outputObj, o.out)
|
||||
}
|
||||
f.PrintSuccess(mapper, false, o.out, info.Mapping.Resource, info.Name, o.dryrun, dataChangeMsg)
|
||||
f.PrintSuccess(r.Mapper().RESTMapper, false, o.out, info.Mapping.Resource, info.Name, o.dryrun, dataChangeMsg)
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
@ -230,7 +230,7 @@ func TestGetUnknownSchemaObject(t *testing.T) {
|
||||
tf.Namespace = "test"
|
||||
tf.ClientConfig = defaultClientConfig()
|
||||
|
||||
mapper, _ := f.UnstructuredObject()
|
||||
mapper, _ := f.Object()
|
||||
m, err := mapper.RESTMapping(schema.GroupKind{Group: "apitest", Kind: "Type"})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
@ -236,6 +236,7 @@ func (o *EnvOptions) RunEnv(f cmdutil.Factory) error {
|
||||
|
||||
if len(o.From) != 0 {
|
||||
b := f.NewBuilder().
|
||||
LocalParam(o.Local).
|
||||
ContinueOnError().
|
||||
NamespaceParam(cmdNamespace).DefaultNamespace().
|
||||
FilenameParam(enforceNamespace, &o.FilenameOptions).
|
||||
@ -246,8 +247,6 @@ func (o *EnvOptions) RunEnv(f cmdutil.Factory) error {
|
||||
LabelSelectorParam(o.Selector).
|
||||
ResourceTypeOrNameArgs(o.All, o.From).
|
||||
Latest()
|
||||
} else {
|
||||
b = b.Local()
|
||||
}
|
||||
|
||||
infos, err := b.Do().Infos()
|
||||
@ -304,18 +303,16 @@ func (o *EnvOptions) RunEnv(f cmdutil.Factory) error {
|
||||
}
|
||||
|
||||
b := f.NewBuilder().
|
||||
LocalParam(o.Local).
|
||||
ContinueOnError().
|
||||
NamespaceParam(cmdNamespace).DefaultNamespace().
|
||||
FilenameParam(enforceNamespace, &o.FilenameOptions).
|
||||
Flatten()
|
||||
|
||||
if !o.Local {
|
||||
b = b.
|
||||
LabelSelectorParam(o.Selector).
|
||||
b.LabelSelectorParam(o.Selector).
|
||||
ResourceTypeOrNameArgs(o.All, o.Resources...).
|
||||
Latest()
|
||||
} else {
|
||||
b = b.Local()
|
||||
}
|
||||
|
||||
o.Infos, err = b.Do().Infos()
|
||||
|
@ -143,6 +143,7 @@ func (o *ImageOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []st
|
||||
|
||||
includeUninitialized := cmdutil.ShouldIncludeUninitialized(cmd, false)
|
||||
builder := f.NewBuilder().
|
||||
LocalParam(o.Local).
|
||||
ContinueOnError().
|
||||
NamespaceParam(cmdNamespace).DefaultNamespace().
|
||||
FilenameParam(enforceNamespace, &o.FilenameOptions).
|
||||
@ -150,8 +151,7 @@ func (o *ImageOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []st
|
||||
Flatten()
|
||||
|
||||
if !o.Local {
|
||||
builder = builder.
|
||||
LabelSelectorParam(o.Selector).
|
||||
builder.LabelSelectorParam(o.Selector).
|
||||
ResourceTypeOrNameArgs(o.All, o.Resources...).
|
||||
Latest()
|
||||
} else {
|
||||
@ -161,8 +161,6 @@ func (o *ImageOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []st
|
||||
if len(o.Resources) > 0 {
|
||||
return resource.LocalResourceError
|
||||
}
|
||||
|
||||
builder = builder.Local()
|
||||
}
|
||||
|
||||
o.Infos, err = builder.Do().Infos()
|
||||
|
@ -145,6 +145,7 @@ func (o *ResourcesOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args
|
||||
|
||||
includeUninitialized := cmdutil.ShouldIncludeUninitialized(cmd, false)
|
||||
builder := f.NewBuilder().
|
||||
LocalParam(o.Local).
|
||||
ContinueOnError().
|
||||
NamespaceParam(cmdNamespace).DefaultNamespace().
|
||||
FilenameParam(enforceNamespace, &o.FilenameOptions).
|
||||
@ -152,19 +153,18 @@ func (o *ResourcesOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args
|
||||
Flatten()
|
||||
|
||||
if !o.Local {
|
||||
builder = builder.
|
||||
LabelSelectorParam(o.Selector).
|
||||
builder.LabelSelectorParam(o.Selector).
|
||||
ResourceTypeOrNameArgs(o.All, args...).
|
||||
Latest()
|
||||
} else {
|
||||
// if a --local flag was provided, and a resource was specified in the form
|
||||
// <resource>/<name>, fail immediately as --local cannot query the api server
|
||||
// for the specified resource.
|
||||
// TODO: this should be in the builder - if someone specifies tuples, fail when
|
||||
// local is true
|
||||
if len(args) > 0 {
|
||||
return resource.LocalResourceError
|
||||
}
|
||||
|
||||
builder = builder.Local()
|
||||
}
|
||||
|
||||
o.Infos, err = builder.Do().Infos()
|
||||
|
@ -129,6 +129,7 @@ func (o *SelectorOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args [
|
||||
|
||||
includeUninitialized := cmdutil.ShouldIncludeUninitialized(cmd, false)
|
||||
o.builder = f.NewBuilder().
|
||||
LocalParam(o.local).
|
||||
ContinueOnError().
|
||||
NamespaceParam(cmdNamespace).DefaultNamespace().
|
||||
FilenameParam(enforceNamespace, &o.fileOptions).
|
||||
@ -136,7 +137,7 @@ func (o *SelectorOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args [
|
||||
Flatten()
|
||||
|
||||
if !o.local {
|
||||
o.builder = o.builder.
|
||||
o.builder.
|
||||
ResourceTypeOrNameArgs(o.all, o.resources...).
|
||||
Latest()
|
||||
} else {
|
||||
@ -146,8 +147,6 @@ func (o *SelectorOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args [
|
||||
if len(o.resources) > 0 {
|
||||
return resource.LocalResourceError
|
||||
}
|
||||
|
||||
o.builder = o.builder.Local()
|
||||
}
|
||||
|
||||
o.PrintObject = func(obj runtime.Object) error {
|
||||
|
@ -129,7 +129,9 @@ func (saConfig *serviceAccountConfig) Complete(f cmdutil.Factory, cmd *cobra.Com
|
||||
saConfig.serviceAccountName = args[len(args)-1]
|
||||
resources := args[:len(args)-1]
|
||||
includeUninitialized := cmdutil.ShouldIncludeUninitialized(cmd, false)
|
||||
builder := f.NewBuilder().ContinueOnError().
|
||||
builder := f.NewBuilder().
|
||||
LocalParam(saConfig.local).
|
||||
ContinueOnError().
|
||||
NamespaceParam(cmdNamespace).DefaultNamespace().
|
||||
FilenameParam(enforceNamespace, &saConfig.fileNameOptions).
|
||||
IncludeUninitialized(includeUninitialized).
|
||||
@ -137,8 +139,6 @@ func (saConfig *serviceAccountConfig) Complete(f cmdutil.Factory, cmd *cobra.Com
|
||||
if !saConfig.local {
|
||||
builder.ResourceTypeOrNameArgs(saConfig.all, resources...).
|
||||
Latest()
|
||||
} else {
|
||||
builder = builder.Local()
|
||||
}
|
||||
saConfig.infos, err = builder.Do().Infos()
|
||||
if err != nil {
|
||||
|
@ -125,7 +125,14 @@ func (o *SubjectOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []
|
||||
}
|
||||
|
||||
includeUninitialized := cmdutil.ShouldIncludeUninitialized(cmd, false)
|
||||
builder := f.NewBuilder()
|
||||
builder := f.NewBuilder().
|
||||
LocalParam(o.Local).
|
||||
ContinueOnError().
|
||||
NamespaceParam(cmdNamespace).DefaultNamespace().
|
||||
FilenameParam(enforceNamespace, &o.FilenameOptions).
|
||||
IncludeUninitialized(includeUninitialized).
|
||||
Flatten()
|
||||
|
||||
if o.Local {
|
||||
// if a --local flag was provided, and a resource was specified in the form
|
||||
// <resource>/<name>, fail immediately as --local cannot query the api server
|
||||
@ -133,16 +140,7 @@ func (o *SubjectOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []
|
||||
if len(args) > 0 {
|
||||
return resource.LocalResourceError
|
||||
}
|
||||
builder = builder.Local()
|
||||
}
|
||||
builder = builder.
|
||||
ContinueOnError().
|
||||
NamespaceParam(cmdNamespace).DefaultNamespace().
|
||||
FilenameParam(enforceNamespace, &o.FilenameOptions).
|
||||
IncludeUninitialized(includeUninitialized).
|
||||
Flatten()
|
||||
|
||||
if !o.Local {
|
||||
} else {
|
||||
builder = builder.
|
||||
LabelSelectorParam(o.Selector).
|
||||
ResourceTypeOrNameArgs(o.All, args...).
|
||||
|
@ -244,6 +244,7 @@ type TestFactory struct {
|
||||
Command string
|
||||
TmpDir string
|
||||
CategoryExpander categories.CategoryExpander
|
||||
SkipDiscovery bool
|
||||
|
||||
ClientForMappingFunc func(mapping *meta.RESTMapping) (resource.RESTClient, error)
|
||||
UnstructuredClientForMappingFunc func(mapping *meta.RESTMapping) (resource.RESTClient, error)
|
||||
@ -282,10 +283,9 @@ func (f *FakeFactory) FlagSet() *pflag.FlagSet {
|
||||
}
|
||||
|
||||
func (f *FakeFactory) Object() (meta.RESTMapper, runtime.ObjectTyper) {
|
||||
return legacyscheme.Registry.RESTMapper(), f.tf.Typer
|
||||
}
|
||||
|
||||
func (f *FakeFactory) UnstructuredObject() (meta.RESTMapper, runtime.ObjectTyper) {
|
||||
if f.tf.SkipDiscovery {
|
||||
return legacyscheme.Registry.RESTMapper(), f.tf.Typer
|
||||
}
|
||||
groupResources := testDynamicResources()
|
||||
mapper := discovery.NewRESTMapper(groupResources, meta.InterfacesForUnstructuredConversion(legacyscheme.Registry.InterfacesFor))
|
||||
typer := discovery.NewUnstructuredObjectTyper(groupResources)
|
||||
@ -519,7 +519,6 @@ func (f *FakeFactory) PrinterForMapping(cmd *cobra.Command, isLocal bool, output
|
||||
|
||||
func (f *FakeFactory) NewBuilder() *resource.Builder {
|
||||
mapper, typer := f.Object()
|
||||
unstructuredMapper, unstructuredTyper := f.UnstructuredObject()
|
||||
|
||||
return resource.NewBuilder(
|
||||
&resource.Mapper{
|
||||
@ -529,8 +528,8 @@ func (f *FakeFactory) NewBuilder() *resource.Builder {
|
||||
Decoder: f.Decoder(true),
|
||||
},
|
||||
&resource.Mapper{
|
||||
RESTMapper: unstructuredMapper,
|
||||
ObjectTyper: unstructuredTyper,
|
||||
RESTMapper: mapper,
|
||||
ObjectTyper: typer,
|
||||
ClientMapper: resource.ClientMapperFunc(f.UnstructuredClientForMapping),
|
||||
Decoder: unstructured.UnstructuredJSONScheme,
|
||||
},
|
||||
@ -605,10 +604,9 @@ type fakeAPIFactory struct {
|
||||
}
|
||||
|
||||
func (f *fakeAPIFactory) Object() (meta.RESTMapper, runtime.ObjectTyper) {
|
||||
return testapi.Default.RESTMapper(), legacyscheme.Scheme
|
||||
}
|
||||
|
||||
func (f *fakeAPIFactory) UnstructuredObject() (meta.RESTMapper, runtime.ObjectTyper) {
|
||||
if f.tf.SkipDiscovery {
|
||||
return testapi.Default.RESTMapper(), legacyscheme.Scheme
|
||||
}
|
||||
groupResources := testDynamicResources()
|
||||
mapper := discovery.NewRESTMapper(
|
||||
groupResources,
|
||||
@ -800,11 +798,7 @@ func (f *fakeAPIFactory) LogsForObject(object, options runtime.Object, timeout t
|
||||
}
|
||||
return c.Core().Pods(f.tf.Namespace).GetLogs(t.Name, opts), nil
|
||||
default:
|
||||
fqKinds, _, err := legacyscheme.Scheme.ObjectKinds(object)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return nil, fmt.Errorf("cannot get the logs from %v", fqKinds[0])
|
||||
return nil, fmt.Errorf("cannot get the logs from %T", object)
|
||||
}
|
||||
}
|
||||
|
||||
@ -813,11 +807,7 @@ func (f *fakeAPIFactory) AttachablePodForObject(object runtime.Object, timeout t
|
||||
case *api.Pod:
|
||||
return t, nil
|
||||
default:
|
||||
gvks, _, err := legacyscheme.Scheme.ObjectKinds(object)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return nil, fmt.Errorf("cannot attach to %v: not implemented", gvks[0])
|
||||
return nil, fmt.Errorf("cannot attach to %T: not implemented", object)
|
||||
}
|
||||
}
|
||||
|
||||
@ -865,7 +855,6 @@ func (f *fakeAPIFactory) PrinterForMapping(cmd *cobra.Command, isLocal bool, out
|
||||
|
||||
func (f *fakeAPIFactory) NewBuilder() *resource.Builder {
|
||||
mapper, typer := f.Object()
|
||||
unstructuredMapper, unstructuredTyper := f.UnstructuredObject()
|
||||
|
||||
return resource.NewBuilder(
|
||||
&resource.Mapper{
|
||||
@ -875,8 +864,8 @@ func (f *fakeAPIFactory) NewBuilder() *resource.Builder {
|
||||
Decoder: f.Decoder(true),
|
||||
},
|
||||
&resource.Mapper{
|
||||
RESTMapper: unstructuredMapper,
|
||||
ObjectTyper: unstructuredTyper,
|
||||
RESTMapper: mapper,
|
||||
ObjectTyper: typer,
|
||||
ClientMapper: resource.ClientMapperFunc(f.UnstructuredClientForMapping),
|
||||
Decoder: unstructured.UnstructuredJSONScheme,
|
||||
},
|
||||
@ -953,6 +942,46 @@ func testDynamicResources() []*discovery.APIGroupResources {
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Group: metav1.APIGroup{
|
||||
Name: "apps",
|
||||
Versions: []metav1.GroupVersionForDiscovery{
|
||||
{Version: "v1beta1"},
|
||||
{Version: "v1beta2"},
|
||||
{Version: "v1"},
|
||||
},
|
||||
PreferredVersion: metav1.GroupVersionForDiscovery{Version: "v1"},
|
||||
},
|
||||
VersionedResources: map[string][]metav1.APIResource{
|
||||
"v1beta1": {
|
||||
{Name: "deployments", Namespaced: true, Kind: "Deployment"},
|
||||
},
|
||||
"v1beta2": {
|
||||
{Name: "deployments", Namespaced: true, Kind: "Deployment"},
|
||||
},
|
||||
"v1": {
|
||||
{Name: "deployments", Namespaced: true, Kind: "Deployment"},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Group: metav1.APIGroup{
|
||||
Name: "autoscaling",
|
||||
Versions: []metav1.GroupVersionForDiscovery{
|
||||
{Version: "v1"},
|
||||
{Version: "v2beta1"},
|
||||
},
|
||||
PreferredVersion: metav1.GroupVersionForDiscovery{Version: "v2beta1"},
|
||||
},
|
||||
VersionedResources: map[string][]metav1.APIResource{
|
||||
"v1": {
|
||||
{Name: "horizontalpodautoscalers", Namespaced: true, Kind: "HorizontalPodAutoscaler"},
|
||||
},
|
||||
"v2beta1": {
|
||||
{Name: "horizontalpodautoscalers", Namespaced: true, Kind: "HorizontalPodAutoscaler"},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Group: metav1.APIGroup{
|
||||
Name: "storage.k8s.io",
|
||||
|
@ -107,7 +107,7 @@ func (o *EditOptions) Complete(f cmdutil.Factory, out, errOut io.Writer, args []
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
mapper, _ := f.UnstructuredObject()
|
||||
mapper, _ := f.Object()
|
||||
b := f.NewBuilder().Unstructured()
|
||||
if o.EditMode == NormalEditMode || o.EditMode == ApplyEditMode {
|
||||
// when do normal edit or apply edit we need to always retrieve the latest resource from server
|
||||
|
@ -189,11 +189,7 @@ type ClientAccessFactory interface {
|
||||
type ObjectMappingFactory interface {
|
||||
// Returns interfaces for dealing with arbitrary runtime.Objects.
|
||||
Object() (meta.RESTMapper, runtime.ObjectTyper)
|
||||
// Returns interfaces for dealing with arbitrary
|
||||
// runtime.Unstructured. This performs API calls to discover types.
|
||||
UnstructuredObject() (meta.RESTMapper, runtime.ObjectTyper)
|
||||
// Returns interface for expanding categories like `all`.
|
||||
// TODO: this should probably return an error if the full expander can't be loaded.
|
||||
CategoryExpander() categories.CategoryExpander
|
||||
// Returns a RESTClient for working with the specified RESTMapping or an error. This is intended
|
||||
// for working with arbitrary resources and is not guaranteed to point to a Kubernetes APIServer.
|
||||
|
@ -28,7 +28,6 @@ import (
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/kubernetes/pkg/api/legacyscheme"
|
||||
"k8s.io/kubernetes/pkg/kubectl/plugins"
|
||||
"k8s.io/kubernetes/pkg/kubectl/resource"
|
||||
"k8s.io/kubernetes/pkg/printers"
|
||||
@ -52,12 +51,8 @@ func (f *ring2Factory) PrinterForCommand(cmd *cobra.Command, isLocal bool, outpu
|
||||
var mapper meta.RESTMapper
|
||||
var typer runtime.ObjectTyper
|
||||
|
||||
if isLocal {
|
||||
mapper = legacyscheme.Registry.RESTMapper()
|
||||
typer = legacyscheme.Scheme
|
||||
} else {
|
||||
mapper, typer = f.objectMappingFactory.UnstructuredObject()
|
||||
}
|
||||
mapper, typer = f.objectMappingFactory.Object()
|
||||
|
||||
// TODO: used by the custom column implementation and the name implementation, break this dependency
|
||||
decoders := []runtime.Decoder{f.clientAccessFactory.Decoder(true), unstructured.UnstructuredJSONScheme}
|
||||
encoder := f.clientAccessFactory.JSONEncoder()
|
||||
@ -131,12 +126,6 @@ func (f *ring2Factory) PrintObject(cmd *cobra.Command, isLocal bool, mapper meta
|
||||
_, typer := f.objectMappingFactory.Object()
|
||||
gvks, _, err := typer.ObjectKinds(obj)
|
||||
|
||||
// fall back to an unstructured object if we get something unregistered
|
||||
if runtime.IsNotRegisteredError(err) {
|
||||
_, typer := f.objectMappingFactory.UnstructuredObject()
|
||||
gvks, _, err = typer.ObjectKinds(obj)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -178,7 +167,6 @@ func (f *ring2Factory) NewBuilder() *resource.Builder {
|
||||
mapper, typer := f.objectMappingFactory.Object()
|
||||
|
||||
unstructuredClientMapperFunc := resource.ClientMapperFunc(f.objectMappingFactory.UnstructuredClientForMapping)
|
||||
unstructuredMapper, unstructuredTyper := f.objectMappingFactory.Object()
|
||||
|
||||
categoryExpander := f.objectMappingFactory.CategoryExpander()
|
||||
|
||||
@ -190,8 +178,8 @@ func (f *ring2Factory) NewBuilder() *resource.Builder {
|
||||
Decoder: f.clientAccessFactory.Decoder(true),
|
||||
},
|
||||
&resource.Mapper{
|
||||
RESTMapper: unstructuredMapper,
|
||||
ObjectTyper: unstructuredTyper,
|
||||
RESTMapper: mapper,
|
||||
ObjectTyper: typer,
|
||||
ClientMapper: unstructuredClientMapperFunc,
|
||||
Decoder: unstructured.UnstructuredJSONScheme,
|
||||
},
|
||||
|
@ -73,33 +73,15 @@ 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) objectLoader() (meta.RESTMapper, runtime.ObjectTyper, error) {
|
||||
mapper := legacyscheme.Registry.RESTMapper()
|
||||
discoveryClient, err := f.clientAccessFactory.DiscoveryClient()
|
||||
if err != nil {
|
||||
glog.V(5).Infof("Object loader was unable to retrieve a discovery client: %v", err)
|
||||
return mapper, legacyscheme.Scheme, nil
|
||||
}
|
||||
mapper = meta.FirstHitRESTMapper{
|
||||
MultiRESTMapper: meta.MultiRESTMapper{
|
||||
discovery.NewDeferredDiscoveryRESTMapper(discoveryClient, legacyscheme.Registry.InterfacesFor),
|
||||
legacyscheme.Registry.RESTMapper(), // hardcoded fall back
|
||||
},
|
||||
}
|
||||
|
||||
// wrap with shortcuts, they require a discoveryClient
|
||||
mapper = NewShortcutExpander(mapper, discoveryClient)
|
||||
return mapper, legacyscheme.Scheme, nil
|
||||
}
|
||||
|
||||
// TODO: unstructured and structured discovery should both gracefully degrade in the presence
|
||||
// of errors, and it should be possible to get access to the unstructured object typers no matter
|
||||
// whether the server responds or not. Make the legacy scheme recognize object typer, then we can
|
||||
// safely fall back to the built in restmapper as a last resort.
|
||||
func (f *ring1Factory) unstructuredObjectLoader() (meta.RESTMapper, runtime.ObjectTyper, error) {
|
||||
discoveryClient, err := f.clientAccessFactory.DiscoveryClient()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
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(), legacyscheme.Scheme, nil
|
||||
}
|
||||
|
||||
groupResources, err := discovery.GetAPIGroupResources(discoveryClient)
|
||||
@ -108,12 +90,14 @@ func (f *ring1Factory) unstructuredObjectLoader() (meta.RESTMapper, runtime.Obje
|
||||
groupResources, err = discovery.GetAPIGroupResources(discoveryClient)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
glog.V(3).Infof("Unable to retrieve API resources, falling back to hardcoded types: %v", err)
|
||||
return legacyscheme.Registry.RESTMapper(), legacyscheme.Scheme, nil
|
||||
}
|
||||
|
||||
// allow conversion between typed and unstructured objects
|
||||
interfaces := meta.InterfacesForUnstructuredConversion(legacyscheme.Registry.InterfacesFor)
|
||||
mapper := discovery.NewDeferredDiscoveryRESTMapper(discoveryClient, meta.VersionInterfacesFunc(interfaces))
|
||||
// TODO: should this also indicate it recognizes typed objects?
|
||||
typer := discovery.NewUnstructuredObjectTyper(groupResources)
|
||||
expander := NewShortcutExpander(mapper, discoveryClient)
|
||||
return expander, typer, err
|
||||
@ -123,10 +107,6 @@ func (f *ring1Factory) Object() (meta.RESTMapper, runtime.ObjectTyper) {
|
||||
return NewLazyObjectLoader(f.objectLoader)
|
||||
}
|
||||
|
||||
func (f *ring1Factory) UnstructuredObject() (meta.RESTMapper, runtime.ObjectTyper) {
|
||||
return NewLazyObjectLoader(f.unstructuredObjectLoader)
|
||||
}
|
||||
|
||||
func (f *ring1Factory) CategoryExpander() categories.CategoryExpander {
|
||||
legacyExpander := categories.LegacyCategoryExpander
|
||||
|
||||
|
@ -177,6 +177,14 @@ func (b *Builder) Unstructured() *Builder {
|
||||
return b
|
||||
}
|
||||
|
||||
// LocalParam calls Local() if local is true.
|
||||
func (b *Builder) LocalParam(local bool) *Builder {
|
||||
if local {
|
||||
b.Local()
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
// Local will avoid asking the server for results.
|
||||
func (b *Builder) Local() *Builder {
|
||||
mapper := *b.mapper
|
||||
|
Loading…
Reference in New Issue
Block a user