mirror of https://github.com/k3s-io/k3s
Unify unstructured and versioned object in resource.Builder
resource.Builder should be aware of both paths, and the caller is responsible for determining the different path via use.pull/6/head
parent
98e0c69907
commit
0229fd4bd1
|
@ -183,11 +183,28 @@ func (f *ring2Factory) PrintResourceInfoForCommand(cmd *cobra.Command, info *res
|
||||||
// NewBuilder returns a new resource builder for structured api objects.
|
// NewBuilder returns a new resource builder for structured api objects.
|
||||||
func (f *ring2Factory) NewBuilder() *resource.Builder {
|
func (f *ring2Factory) NewBuilder() *resource.Builder {
|
||||||
clientMapperFunc := resource.ClientMapperFunc(f.objectMappingFactory.ClientForMapping)
|
clientMapperFunc := resource.ClientMapperFunc(f.objectMappingFactory.ClientForMapping)
|
||||||
|
|
||||||
mapper, typer := f.objectMappingFactory.Object()
|
mapper, typer := f.objectMappingFactory.Object()
|
||||||
|
|
||||||
|
unstructuredClientMapperFunc := resource.ClientMapperFunc(f.objectMappingFactory.UnstructuredClientForMapping)
|
||||||
|
unstructuredMapper, unstructuredTyper, _ := f.objectMappingFactory.UnstructuredObject()
|
||||||
|
|
||||||
categoryExpander := f.objectMappingFactory.CategoryExpander()
|
categoryExpander := f.objectMappingFactory.CategoryExpander()
|
||||||
|
|
||||||
return resource.NewBuilder(mapper, categoryExpander, typer, clientMapperFunc, f.clientAccessFactory.Decoder(true))
|
return resource.NewBuilder(
|
||||||
|
&resource.Mapper{
|
||||||
|
RESTMapper: mapper,
|
||||||
|
ObjectTyper: typer,
|
||||||
|
ClientMapper: clientMapperFunc,
|
||||||
|
Decoder: f.clientAccessFactory.Decoder(true),
|
||||||
|
},
|
||||||
|
&resource.Mapper{
|
||||||
|
RESTMapper: unstructuredMapper,
|
||||||
|
ObjectTyper: unstructuredTyper,
|
||||||
|
ClientMapper: unstructuredClientMapperFunc,
|
||||||
|
Decoder: unstructured.UnstructuredJSONScheme,
|
||||||
|
},
|
||||||
|
categoryExpander,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// PluginLoader loads plugins from a path set by the KUBECTL_PLUGINS_PATH env var.
|
// PluginLoader loads plugins from a path set by the KUBECTL_PLUGINS_PATH env var.
|
||||||
|
|
|
@ -108,7 +108,9 @@ func (f *ring1Factory) UnstructuredObject() (meta.RESTMapper, runtime.ObjectType
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
mapper := discovery.NewDeferredDiscoveryRESTMapper(discoveryClient, meta.InterfacesForUnstructured)
|
// allow conversion between typed and unstructured objects
|
||||||
|
interfaces := meta.InterfacesForUnstructuredConversion(legacyscheme.Registry.InterfacesFor)
|
||||||
|
mapper := discovery.NewDeferredDiscoveryRESTMapper(discoveryClient, meta.VersionInterfacesFunc(interfaces))
|
||||||
typer := discovery.NewUnstructuredObjectTyper(groupResources)
|
typer := discovery.NewUnstructuredObjectTyper(groupResources)
|
||||||
expander, err := NewShortcutExpander(mapper, discoveryClient)
|
expander, err := NewShortcutExpander(mapper, discoveryClient)
|
||||||
return expander, typer, err
|
return expander, typer, err
|
||||||
|
|
|
@ -543,7 +543,16 @@ func TestDiscoveryReplaceAliases(t *testing.T) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Unable to create shortcut expander, err = %s", err.Error())
|
t.Fatalf("Unable to create shortcut expander, err = %s", err.Error())
|
||||||
}
|
}
|
||||||
b := resource.NewBuilder(mapper, categories.LegacyCategoryExpander, legacyscheme.Scheme, fakeClient(), testapi.Default.Codec())
|
b := resource.NewBuilder(
|
||||||
|
&resource.Mapper{
|
||||||
|
RESTMapper: mapper,
|
||||||
|
ObjectTyper: legacyscheme.Scheme,
|
||||||
|
ClientMapper: fakeClient(),
|
||||||
|
Decoder: testapi.Default.Codec(),
|
||||||
|
},
|
||||||
|
nil,
|
||||||
|
categories.LegacyCategoryExpander,
|
||||||
|
)
|
||||||
|
|
||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
replaced := b.ReplaceAliases(test.arg)
|
replaced := b.ReplaceAliases(test.arg)
|
||||||
|
|
|
@ -26,9 +26,7 @@ import (
|
||||||
|
|
||||||
"k8s.io/apimachinery/pkg/api/meta"
|
"k8s.io/apimachinery/pkg/api/meta"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
|
||||||
"k8s.io/apimachinery/pkg/labels"
|
"k8s.io/apimachinery/pkg/labels"
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
|
||||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||||
utilerrors "k8s.io/apimachinery/pkg/util/errors"
|
utilerrors "k8s.io/apimachinery/pkg/util/errors"
|
||||||
"k8s.io/apimachinery/pkg/util/sets"
|
"k8s.io/apimachinery/pkg/util/sets"
|
||||||
|
@ -46,6 +44,7 @@ const defaultHttpGetAttempts int = 3
|
||||||
// over using the Visitor interface.
|
// over using the Visitor interface.
|
||||||
type Builder struct {
|
type Builder struct {
|
||||||
mapper *Mapper
|
mapper *Mapper
|
||||||
|
unstructured *Mapper
|
||||||
categoryExpander categories.CategoryExpander
|
categoryExpander categories.CategoryExpander
|
||||||
|
|
||||||
errs []error
|
errs []error
|
||||||
|
@ -118,9 +117,10 @@ type resourceTuple struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewBuilder creates a builder that operates on generic objects.
|
// NewBuilder creates a builder that operates on generic objects.
|
||||||
func NewBuilder(mapper meta.RESTMapper, categoryExpander categories.CategoryExpander, typer runtime.ObjectTyper, clientMapper ClientMapper, decoder runtime.Decoder) *Builder {
|
func NewBuilder(mapper, unstructured *Mapper, categoryExpander categories.CategoryExpander) *Builder {
|
||||||
return &Builder{
|
return &Builder{
|
||||||
mapper: &Mapper{typer, mapper, clientMapper, decoder},
|
mapper: mapper,
|
||||||
|
unstructured: unstructured,
|
||||||
categoryExpander: categoryExpander,
|
categoryExpander: categoryExpander,
|
||||||
requireObject: true,
|
requireObject: true,
|
||||||
}
|
}
|
||||||
|
@ -166,23 +166,31 @@ func (b *Builder) FilenameParam(enforceNamespace bool, filenameOptions *Filename
|
||||||
return b
|
return b
|
||||||
}
|
}
|
||||||
|
|
||||||
// Local wraps the builder's clientMapper in a DisabledClientMapperForMapping
|
// Unstructured updates the builder so that it will request and send unstructured
|
||||||
func (b *Builder) Local(mapperFunc ClientMapperFunc) *Builder {
|
// objects by default. Calling this method resets Local().
|
||||||
b.mapper.ClientMapper = DisabledClientForMapping{ClientMapper: ClientMapperFunc(mapperFunc)}
|
func (b *Builder) Unstructured() *Builder {
|
||||||
|
if b.unstructured == nil {
|
||||||
|
b.errs = append(b.errs, fmt.Errorf("no unstructured builder provided"))
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
b.mapper = b.unstructured
|
||||||
return b
|
return b
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unstructured updates the builder's ClientMapper, RESTMapper,
|
// Local will avoid asking the server for results.
|
||||||
// ObjectTyper, and codec for working with unstructured api objects
|
func (b *Builder) Local() *Builder {
|
||||||
func (b *Builder) Unstructured(mapperFunc ClientMapperFunc, mapper meta.RESTMapper, typer runtime.ObjectTyper) *Builder {
|
mapper := *b.mapper
|
||||||
b.mapper.RESTMapper = mapper
|
mapper.ClientMapper = DisabledClientForMapping{ClientMapper: mapper.ClientMapper}
|
||||||
b.mapper.ObjectTyper = typer
|
b.mapper = &mapper
|
||||||
b.mapper.Decoder = unstructured.UnstructuredJSONScheme
|
|
||||||
b.mapper.ClientMapper = ClientMapperFunc(mapperFunc)
|
|
||||||
|
|
||||||
return b
|
return b
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Mapper returns a copy of the current mapper.
|
||||||
|
func (b *Builder) Mapper() *Mapper {
|
||||||
|
mapper := *b.mapper
|
||||||
|
return &mapper
|
||||||
|
}
|
||||||
|
|
||||||
// URL accepts a number of URLs directly.
|
// URL accepts a number of URLs directly.
|
||||||
func (b *Builder) URL(httpAttemptCount int, urls ...*url.URL) *Builder {
|
func (b *Builder) URL(httpAttemptCount int, urls ...*url.URL) *Builder {
|
||||||
for _, u := range urls {
|
for _, u := range urls {
|
||||||
|
@ -755,7 +763,13 @@ func (b *Builder) visitByResource() *Result {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
info := NewInfo(client, mapping, selectorNamespace, tuple.Name, b.export)
|
info := &Info{
|
||||||
|
Client: client,
|
||||||
|
Mapping: mapping,
|
||||||
|
Namespace: selectorNamespace,
|
||||||
|
Name: tuple.Name,
|
||||||
|
Export: b.export,
|
||||||
|
}
|
||||||
items = append(items, info)
|
items = append(items, info)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -814,7 +828,13 @@ func (b *Builder) visitByName() *Result {
|
||||||
|
|
||||||
visitors := []Visitor{}
|
visitors := []Visitor{}
|
||||||
for _, name := range b.names {
|
for _, name := range b.names {
|
||||||
info := NewInfo(client, mapping, selectorNamespace, name, b.export)
|
info := &Info{
|
||||||
|
Client: client,
|
||||||
|
Mapping: mapping,
|
||||||
|
Namespace: selectorNamespace,
|
||||||
|
Name: name,
|
||||||
|
Export: b.export,
|
||||||
|
}
|
||||||
visitors = append(visitors, info)
|
visitors = append(visitors, info)
|
||||||
}
|
}
|
||||||
result.visitor = VisitorList(visitors)
|
result.visitor = VisitorList(visitors)
|
||||||
|
@ -875,6 +895,7 @@ func (b *Builder) visitByPaths() *Result {
|
||||||
// for further iteration.
|
// for further iteration.
|
||||||
func (b *Builder) Do() *Result {
|
func (b *Builder) Do() *Result {
|
||||||
r := b.visitorResult()
|
r := b.visitorResult()
|
||||||
|
r.mapper = b.Mapper()
|
||||||
if r.err != nil {
|
if r.err != nil {
|
||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
|
|
|
@ -263,8 +263,25 @@ var aRC string = `
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
|
func newDefaultBuilder() *Builder {
|
||||||
|
return newDefaultBuilderWith(fakeClient())
|
||||||
|
}
|
||||||
|
|
||||||
|
func newDefaultBuilderWith(client ClientMapper) *Builder {
|
||||||
|
return NewBuilder(
|
||||||
|
&Mapper{
|
||||||
|
RESTMapper: restmapper,
|
||||||
|
ObjectTyper: scheme.Scheme,
|
||||||
|
ClientMapper: client,
|
||||||
|
Decoder: corev1Codec,
|
||||||
|
},
|
||||||
|
nil,
|
||||||
|
categories.LegacyCategoryExpander,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
func TestPathBuilderAndVersionedObjectNotDefaulted(t *testing.T) {
|
func TestPathBuilderAndVersionedObjectNotDefaulted(t *testing.T) {
|
||||||
b := NewBuilder(restmapper, categories.LegacyCategoryExpander, scheme.Scheme, fakeClient(), corev1Codec).
|
b := newDefaultBuilder().
|
||||||
FilenameParam(false, &FilenameOptions{Recursive: false, Filenames: []string{"../../../test/fixtures/pkg/kubectl/builder/kitten-rc.yaml"}})
|
FilenameParam(false, &FilenameOptions{Recursive: false, Filenames: []string{"../../../test/fixtures/pkg/kubectl/builder/kitten-rc.yaml"}})
|
||||||
|
|
||||||
test := &testVisitor{}
|
test := &testVisitor{}
|
||||||
|
@ -279,10 +296,11 @@ func TestPathBuilderAndVersionedObjectNotDefaulted(t *testing.T) {
|
||||||
if info.Name != "update-demo-kitten" || info.Namespace != "" || info.Object == nil {
|
if info.Name != "update-demo-kitten" || info.Namespace != "" || info.Object == nil {
|
||||||
t.Errorf("unexpected info: %#v", info)
|
t.Errorf("unexpected info: %#v", info)
|
||||||
}
|
}
|
||||||
version, ok := info.VersionedObject.(*v1.ReplicationController)
|
obj := info.AsVersioned()
|
||||||
|
version, ok := obj.(*v1.ReplicationController)
|
||||||
// versioned object does not have defaulting applied
|
// versioned object does not have defaulting applied
|
||||||
if info.VersionedObject == nil || !ok || version.Spec.Replicas != nil {
|
if obj == nil || !ok || version.Spec.Replicas != nil {
|
||||||
t.Errorf("unexpected versioned object: %#v", info.VersionedObject)
|
t.Errorf("unexpected versioned object: %#v", obj)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -303,8 +321,7 @@ func TestNodeBuilder(t *testing.T) {
|
||||||
w.Write([]byte(runtime.EncodeOrDie(corev1Codec, node)))
|
w.Write([]byte(runtime.EncodeOrDie(corev1Codec, node)))
|
||||||
}()
|
}()
|
||||||
|
|
||||||
b := NewBuilder(restmapper, categories.LegacyCategoryExpander, scheme.Scheme, fakeClient(), corev1Codec).
|
b := newDefaultBuilder().NamespaceParam("test").Stream(r, "STDIN")
|
||||||
NamespaceParam("test").Stream(r, "STDIN")
|
|
||||||
|
|
||||||
test := &testVisitor{}
|
test := &testVisitor{}
|
||||||
|
|
||||||
|
@ -367,7 +384,7 @@ func TestPathBuilderWithMultiple(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
b := NewBuilder(restmapper, categories.LegacyCategoryExpander, scheme.Scheme, fakeClient(), corev1Codec).
|
b := newDefaultBuilder().
|
||||||
FilenameParam(false, &FilenameOptions{Recursive: test.recursive, Filenames: []string{test.directory}}).
|
FilenameParam(false, &FilenameOptions{Recursive: test.recursive, Filenames: []string{test.directory}}).
|
||||||
NamespaceParam("test").DefaultNamespace()
|
NamespaceParam("test").DefaultNamespace()
|
||||||
|
|
||||||
|
@ -426,7 +443,7 @@ func TestPathBuilderWithMultipleInvalid(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
b := NewBuilder(restmapper, categories.LegacyCategoryExpander, scheme.Scheme, fakeClient(), corev1Codec).
|
b := newDefaultBuilder().
|
||||||
FilenameParam(false, &FilenameOptions{Recursive: test.recursive, Filenames: []string{test.directory}}).
|
FilenameParam(false, &FilenameOptions{Recursive: test.recursive, Filenames: []string{test.directory}}).
|
||||||
NamespaceParam("test").DefaultNamespace()
|
NamespaceParam("test").DefaultNamespace()
|
||||||
|
|
||||||
|
@ -441,7 +458,7 @@ func TestPathBuilderWithMultipleInvalid(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestDirectoryBuilder(t *testing.T) {
|
func TestDirectoryBuilder(t *testing.T) {
|
||||||
b := NewBuilder(restmapper, categories.LegacyCategoryExpander, scheme.Scheme, fakeClient(), corev1Codec).
|
b := newDefaultBuilder().
|
||||||
FilenameParam(false, &FilenameOptions{Recursive: false, Filenames: []string{"../../../examples/guestbook/legacy"}}).
|
FilenameParam(false, &FilenameOptions{Recursive: false, Filenames: []string{"../../../examples/guestbook/legacy"}}).
|
||||||
NamespaceParam("test").DefaultNamespace()
|
NamespaceParam("test").DefaultNamespace()
|
||||||
|
|
||||||
|
@ -472,7 +489,7 @@ func TestNamespaceOverride(t *testing.T) {
|
||||||
}))
|
}))
|
||||||
defer s.Close()
|
defer s.Close()
|
||||||
|
|
||||||
b := NewBuilder(restmapper, categories.LegacyCategoryExpander, scheme.Scheme, fakeClient(), corev1Codec).
|
b := newDefaultBuilder().
|
||||||
FilenameParam(false, &FilenameOptions{Recursive: false, Filenames: []string{s.URL}}).
|
FilenameParam(false, &FilenameOptions{Recursive: false, Filenames: []string{s.URL}}).
|
||||||
NamespaceParam("test")
|
NamespaceParam("test")
|
||||||
|
|
||||||
|
@ -483,7 +500,7 @@ func TestNamespaceOverride(t *testing.T) {
|
||||||
t.Fatalf("unexpected response: %v %#v", err, test.Infos)
|
t.Fatalf("unexpected response: %v %#v", err, test.Infos)
|
||||||
}
|
}
|
||||||
|
|
||||||
b = NewBuilder(restmapper, categories.LegacyCategoryExpander, scheme.Scheme, fakeClient(), corev1Codec).
|
b = newDefaultBuilder().
|
||||||
FilenameParam(true, &FilenameOptions{Recursive: false, Filenames: []string{s.URL}}).
|
FilenameParam(true, &FilenameOptions{Recursive: false, Filenames: []string{s.URL}}).
|
||||||
NamespaceParam("test")
|
NamespaceParam("test")
|
||||||
|
|
||||||
|
@ -503,7 +520,7 @@ func TestURLBuilder(t *testing.T) {
|
||||||
}))
|
}))
|
||||||
defer s.Close()
|
defer s.Close()
|
||||||
|
|
||||||
b := NewBuilder(restmapper, categories.LegacyCategoryExpander, scheme.Scheme, fakeClient(), corev1Codec).
|
b := newDefaultBuilder().
|
||||||
FilenameParam(false, &FilenameOptions{Recursive: false, Filenames: []string{s.URL}}).
|
FilenameParam(false, &FilenameOptions{Recursive: false, Filenames: []string{s.URL}}).
|
||||||
NamespaceParam("foo")
|
NamespaceParam("foo")
|
||||||
|
|
||||||
|
@ -532,7 +549,7 @@ func TestURLBuilderRequireNamespace(t *testing.T) {
|
||||||
}))
|
}))
|
||||||
defer s.Close()
|
defer s.Close()
|
||||||
|
|
||||||
b := NewBuilder(restmapper, categories.LegacyCategoryExpander, scheme.Scheme, fakeClient(), corev1Codec).
|
b := newDefaultBuilder().
|
||||||
FilenameParam(false, &FilenameOptions{Recursive: false, Filenames: []string{s.URL}}).
|
FilenameParam(false, &FilenameOptions{Recursive: false, Filenames: []string{s.URL}}).
|
||||||
NamespaceParam("test").RequireNamespace()
|
NamespaceParam("test").RequireNamespace()
|
||||||
|
|
||||||
|
@ -547,10 +564,9 @@ func TestURLBuilderRequireNamespace(t *testing.T) {
|
||||||
|
|
||||||
func TestResourceByName(t *testing.T) {
|
func TestResourceByName(t *testing.T) {
|
||||||
pods, _ := testData()
|
pods, _ := testData()
|
||||||
b := NewBuilder(restmapper, categories.LegacyCategoryExpander, scheme.Scheme, fakeClientWith("", t, map[string]string{
|
b := newDefaultBuilderWith(fakeClientWith("", t, map[string]string{
|
||||||
"/namespaces/test/pods/foo": runtime.EncodeOrDie(corev1Codec, &pods.Items[0]),
|
"/namespaces/test/pods/foo": runtime.EncodeOrDie(corev1Codec, &pods.Items[0]),
|
||||||
}), corev1Codec).
|
})).NamespaceParam("test")
|
||||||
NamespaceParam("test")
|
|
||||||
|
|
||||||
test := &testVisitor{}
|
test := &testVisitor{}
|
||||||
singleItemImplied := false
|
singleItemImplied := false
|
||||||
|
@ -580,12 +596,12 @@ func TestResourceByName(t *testing.T) {
|
||||||
|
|
||||||
func TestMultipleResourceByTheSameName(t *testing.T) {
|
func TestMultipleResourceByTheSameName(t *testing.T) {
|
||||||
pods, svcs := testData()
|
pods, svcs := testData()
|
||||||
b := NewBuilder(restmapper, categories.LegacyCategoryExpander, scheme.Scheme, fakeClientWith("", t, map[string]string{
|
b := newDefaultBuilderWith(fakeClientWith("", t, map[string]string{
|
||||||
"/namespaces/test/pods/foo": runtime.EncodeOrDie(corev1Codec, &pods.Items[0]),
|
"/namespaces/test/pods/foo": runtime.EncodeOrDie(corev1Codec, &pods.Items[0]),
|
||||||
"/namespaces/test/pods/baz": runtime.EncodeOrDie(corev1Codec, &pods.Items[1]),
|
"/namespaces/test/pods/baz": runtime.EncodeOrDie(corev1Codec, &pods.Items[1]),
|
||||||
"/namespaces/test/services/foo": runtime.EncodeOrDie(corev1Codec, &svcs.Items[0]),
|
"/namespaces/test/services/foo": runtime.EncodeOrDie(corev1Codec, &svcs.Items[0]),
|
||||||
"/namespaces/test/services/baz": runtime.EncodeOrDie(corev1Codec, &svcs.Items[0]),
|
"/namespaces/test/services/baz": runtime.EncodeOrDie(corev1Codec, &svcs.Items[0]),
|
||||||
}), corev1Codec).
|
})).
|
||||||
NamespaceParam("test")
|
NamespaceParam("test")
|
||||||
|
|
||||||
test := &testVisitor{}
|
test := &testVisitor{}
|
||||||
|
@ -632,11 +648,10 @@ func TestRequestModifier(t *testing.T) {
|
||||||
|
|
||||||
func TestResourceNames(t *testing.T) {
|
func TestResourceNames(t *testing.T) {
|
||||||
pods, svc := testData()
|
pods, svc := testData()
|
||||||
b := NewBuilder(restmapper, categories.LegacyCategoryExpander, scheme.Scheme, fakeClientWith("", t, map[string]string{
|
b := newDefaultBuilderWith(fakeClientWith("", t, map[string]string{
|
||||||
"/namespaces/test/pods/foo": runtime.EncodeOrDie(corev1Codec, &pods.Items[0]),
|
"/namespaces/test/pods/foo": runtime.EncodeOrDie(corev1Codec, &pods.Items[0]),
|
||||||
"/namespaces/test/services/baz": runtime.EncodeOrDie(corev1Codec, &svc.Items[0]),
|
"/namespaces/test/services/baz": runtime.EncodeOrDie(corev1Codec, &svc.Items[0]),
|
||||||
}), corev1Codec).
|
})).NamespaceParam("test")
|
||||||
NamespaceParam("test")
|
|
||||||
|
|
||||||
test := &testVisitor{}
|
test := &testVisitor{}
|
||||||
|
|
||||||
|
@ -660,11 +675,10 @@ func TestResourceNames(t *testing.T) {
|
||||||
|
|
||||||
func TestResourceNamesWithoutResource(t *testing.T) {
|
func TestResourceNamesWithoutResource(t *testing.T) {
|
||||||
pods, svc := testData()
|
pods, svc := testData()
|
||||||
b := NewBuilder(restmapper, categories.LegacyCategoryExpander, scheme.Scheme, fakeClientWith("", t, map[string]string{
|
b := newDefaultBuilderWith(fakeClientWith("", t, map[string]string{
|
||||||
"/namespaces/test/pods/foo": runtime.EncodeOrDie(corev1Codec, &pods.Items[0]),
|
"/namespaces/test/pods/foo": runtime.EncodeOrDie(corev1Codec, &pods.Items[0]),
|
||||||
"/namespaces/test/services/baz": runtime.EncodeOrDie(corev1Codec, &svc.Items[0]),
|
"/namespaces/test/services/baz": runtime.EncodeOrDie(corev1Codec, &svc.Items[0]),
|
||||||
}), corev1Codec).
|
})).NamespaceParam("test")
|
||||||
NamespaceParam("test")
|
|
||||||
|
|
||||||
test := &testVisitor{}
|
test := &testVisitor{}
|
||||||
|
|
||||||
|
@ -681,8 +695,7 @@ func TestResourceNamesWithoutResource(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestResourceByNameWithoutRequireObject(t *testing.T) {
|
func TestResourceByNameWithoutRequireObject(t *testing.T) {
|
||||||
b := NewBuilder(restmapper, categories.LegacyCategoryExpander, scheme.Scheme, fakeClientWith("", t, map[string]string{}), corev1Codec).
|
b := newDefaultBuilderWith(fakeClientWith("", t, map[string]string{})).NamespaceParam("test")
|
||||||
NamespaceParam("test")
|
|
||||||
|
|
||||||
test := &testVisitor{}
|
test := &testVisitor{}
|
||||||
singleItemImplied := false
|
singleItemImplied := false
|
||||||
|
@ -715,9 +728,9 @@ func TestResourceByNameWithoutRequireObject(t *testing.T) {
|
||||||
|
|
||||||
func TestResourceByNameAndEmptySelector(t *testing.T) {
|
func TestResourceByNameAndEmptySelector(t *testing.T) {
|
||||||
pods, _ := testData()
|
pods, _ := testData()
|
||||||
b := NewBuilder(restmapper, categories.LegacyCategoryExpander, scheme.Scheme, fakeClientWith("", t, map[string]string{
|
b := newDefaultBuilderWith(fakeClientWith("", t, map[string]string{
|
||||||
"/namespaces/test/pods/foo": runtime.EncodeOrDie(corev1Codec, &pods.Items[0]),
|
"/namespaces/test/pods/foo": runtime.EncodeOrDie(corev1Codec, &pods.Items[0]),
|
||||||
}), corev1Codec).
|
})).
|
||||||
NamespaceParam("test").
|
NamespaceParam("test").
|
||||||
LabelSelectorParam("").
|
LabelSelectorParam("").
|
||||||
ResourceTypeOrNameArgs(true, "pods", "foo")
|
ResourceTypeOrNameArgs(true, "pods", "foo")
|
||||||
|
@ -743,10 +756,10 @@ func TestResourceByNameAndEmptySelector(t *testing.T) {
|
||||||
func TestLabelSelector(t *testing.T) {
|
func TestLabelSelector(t *testing.T) {
|
||||||
pods, svc := testData()
|
pods, svc := testData()
|
||||||
labelKey := metav1.LabelSelectorQueryParam(corev1GV.String())
|
labelKey := metav1.LabelSelectorQueryParam(corev1GV.String())
|
||||||
b := NewBuilder(restmapper, categories.LegacyCategoryExpander, scheme.Scheme, fakeClientWith("", t, map[string]string{
|
b := newDefaultBuilderWith(fakeClientWith("", t, map[string]string{
|
||||||
"/namespaces/test/pods?" + labelKey + "=a%3Db": runtime.EncodeOrDie(corev1Codec, pods),
|
"/namespaces/test/pods?" + labelKey + "=a%3Db": runtime.EncodeOrDie(corev1Codec, pods),
|
||||||
"/namespaces/test/services?" + labelKey + "=a%3Db": runtime.EncodeOrDie(corev1Codec, svc),
|
"/namespaces/test/services?" + labelKey + "=a%3Db": runtime.EncodeOrDie(corev1Codec, svc),
|
||||||
}), corev1Codec).
|
})).
|
||||||
LabelSelectorParam("a=b").
|
LabelSelectorParam("a=b").
|
||||||
NamespaceParam("test").
|
NamespaceParam("test").
|
||||||
Flatten()
|
Flatten()
|
||||||
|
@ -774,7 +787,7 @@ func TestLabelSelector(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestLabelSelectorRequiresKnownTypes(t *testing.T) {
|
func TestLabelSelectorRequiresKnownTypes(t *testing.T) {
|
||||||
b := NewBuilder(restmapper, categories.LegacyCategoryExpander, scheme.Scheme, fakeClient(), corev1Codec).
|
b := newDefaultBuilder().
|
||||||
LabelSelectorParam("a=b").
|
LabelSelectorParam("a=b").
|
||||||
NamespaceParam("test").
|
NamespaceParam("test").
|
||||||
ResourceTypes("unknown")
|
ResourceTypes("unknown")
|
||||||
|
@ -787,10 +800,10 @@ func TestLabelSelectorRequiresKnownTypes(t *testing.T) {
|
||||||
func TestFieldSelector(t *testing.T) {
|
func TestFieldSelector(t *testing.T) {
|
||||||
pods, svc := testData()
|
pods, svc := testData()
|
||||||
fieldKey := metav1.FieldSelectorQueryParam(corev1GV.String())
|
fieldKey := metav1.FieldSelectorQueryParam(corev1GV.String())
|
||||||
b := NewBuilder(restmapper, categories.LegacyCategoryExpander, scheme.Scheme, fakeClientWith("", t, map[string]string{
|
b := newDefaultBuilderWith(fakeClientWith("", t, map[string]string{
|
||||||
"/namespaces/test/pods?" + fieldKey + "=a%3Db": runtime.EncodeOrDie(corev1Codec, pods),
|
"/namespaces/test/pods?" + fieldKey + "=a%3Db": runtime.EncodeOrDie(corev1Codec, pods),
|
||||||
"/namespaces/test/services?" + fieldKey + "=a%3Db": runtime.EncodeOrDie(corev1Codec, svc),
|
"/namespaces/test/services?" + fieldKey + "=a%3Db": runtime.EncodeOrDie(corev1Codec, svc),
|
||||||
}), corev1Codec).
|
})).
|
||||||
FieldSelectorParam("a=b").
|
FieldSelectorParam("a=b").
|
||||||
NamespaceParam("test").
|
NamespaceParam("test").
|
||||||
Flatten()
|
Flatten()
|
||||||
|
@ -818,7 +831,7 @@ func TestFieldSelector(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestFieldSelectorRequiresKnownTypes(t *testing.T) {
|
func TestFieldSelectorRequiresKnownTypes(t *testing.T) {
|
||||||
b := NewBuilder(restmapper, categories.LegacyCategoryExpander, scheme.Scheme, fakeClient(), corev1Codec).
|
b := newDefaultBuilder().
|
||||||
FieldSelectorParam("a=b").
|
FieldSelectorParam("a=b").
|
||||||
NamespaceParam("test").
|
NamespaceParam("test").
|
||||||
ResourceTypes("unknown")
|
ResourceTypes("unknown")
|
||||||
|
@ -829,7 +842,7 @@ func TestFieldSelectorRequiresKnownTypes(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSingleResourceType(t *testing.T) {
|
func TestSingleResourceType(t *testing.T) {
|
||||||
b := NewBuilder(restmapper, categories.LegacyCategoryExpander, scheme.Scheme, fakeClient(), corev1Codec).
|
b := newDefaultBuilder().
|
||||||
LabelSelectorParam("a=b").
|
LabelSelectorParam("a=b").
|
||||||
SingleResourceType().
|
SingleResourceType().
|
||||||
ResourceTypeOrNameArgs(true, "pods,services")
|
ResourceTypeOrNameArgs(true, "pods,services")
|
||||||
|
@ -898,8 +911,7 @@ func TestResourceTuple(t *testing.T) {
|
||||||
"/nodes/foo": runtime.EncodeOrDie(corev1Codec, &v1.Node{ObjectMeta: metav1.ObjectMeta{Name: "foo"}}),
|
"/nodes/foo": runtime.EncodeOrDie(corev1Codec, &v1.Node{ObjectMeta: metav1.ObjectMeta{Name: "foo"}}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
b := newDefaultBuilderWith(fakeClientWith(k, t, expectedRequests)).
|
||||||
b := NewBuilder(restmapper, categories.LegacyCategoryExpander, scheme.Scheme, fakeClientWith(k, t, expectedRequests), corev1Codec).
|
|
||||||
NamespaceParam("test").DefaultNamespace().
|
NamespaceParam("test").DefaultNamespace().
|
||||||
ResourceTypeOrNameArgs(true, testCase.args...).RequireObject(requireObject)
|
ResourceTypeOrNameArgs(true, testCase.args...).RequireObject(requireObject)
|
||||||
|
|
||||||
|
@ -930,7 +942,7 @@ func TestResourceTuple(t *testing.T) {
|
||||||
|
|
||||||
func TestStream(t *testing.T) {
|
func TestStream(t *testing.T) {
|
||||||
r, pods, rc := streamTestData()
|
r, pods, rc := streamTestData()
|
||||||
b := NewBuilder(restmapper, categories.LegacyCategoryExpander, scheme.Scheme, fakeClient(), corev1Codec).
|
b := newDefaultBuilder().
|
||||||
NamespaceParam("test").Stream(r, "STDIN").Flatten()
|
NamespaceParam("test").Stream(r, "STDIN").Flatten()
|
||||||
|
|
||||||
test := &testVisitor{}
|
test := &testVisitor{}
|
||||||
|
@ -947,7 +959,7 @@ func TestStream(t *testing.T) {
|
||||||
|
|
||||||
func TestYAMLStream(t *testing.T) {
|
func TestYAMLStream(t *testing.T) {
|
||||||
r, pods, rc := streamYAMLTestData()
|
r, pods, rc := streamYAMLTestData()
|
||||||
b := NewBuilder(restmapper, categories.LegacyCategoryExpander, scheme.Scheme, fakeClient(), corev1Codec).
|
b := newDefaultBuilder().
|
||||||
NamespaceParam("test").Stream(r, "STDIN").Flatten()
|
NamespaceParam("test").Stream(r, "STDIN").Flatten()
|
||||||
|
|
||||||
test := &testVisitor{}
|
test := &testVisitor{}
|
||||||
|
@ -964,7 +976,7 @@ func TestYAMLStream(t *testing.T) {
|
||||||
|
|
||||||
func TestMultipleObject(t *testing.T) {
|
func TestMultipleObject(t *testing.T) {
|
||||||
r, pods, svc := streamTestData()
|
r, pods, svc := streamTestData()
|
||||||
obj, err := NewBuilder(restmapper, categories.LegacyCategoryExpander, scheme.Scheme, fakeClient(), corev1Codec).
|
obj, err := newDefaultBuilder().
|
||||||
NamespaceParam("test").Stream(r, "STDIN").Flatten().
|
NamespaceParam("test").Stream(r, "STDIN").Flatten().
|
||||||
Do().Object()
|
Do().Object()
|
||||||
|
|
||||||
|
@ -986,7 +998,7 @@ func TestMultipleObject(t *testing.T) {
|
||||||
|
|
||||||
func TestContinueOnErrorVisitor(t *testing.T) {
|
func TestContinueOnErrorVisitor(t *testing.T) {
|
||||||
r, _, _ := streamTestData()
|
r, _, _ := streamTestData()
|
||||||
req := NewBuilder(restmapper, categories.LegacyCategoryExpander, scheme.Scheme, fakeClient(), corev1Codec).
|
req := newDefaultBuilder().
|
||||||
ContinueOnError().
|
ContinueOnError().
|
||||||
NamespaceParam("test").Stream(r, "STDIN").Flatten().
|
NamespaceParam("test").Stream(r, "STDIN").Flatten().
|
||||||
Do()
|
Do()
|
||||||
|
@ -1015,7 +1027,7 @@ func TestContinueOnErrorVisitor(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSingleItemImpliedObject(t *testing.T) {
|
func TestSingleItemImpliedObject(t *testing.T) {
|
||||||
obj, err := NewBuilder(restmapper, categories.LegacyCategoryExpander, scheme.Scheme, fakeClient(), corev1Codec).
|
obj, err := newDefaultBuilder().
|
||||||
NamespaceParam("test").DefaultNamespace().
|
NamespaceParam("test").DefaultNamespace().
|
||||||
FilenameParam(false, &FilenameOptions{Recursive: false, Filenames: []string{"../../../examples/guestbook/legacy/redis-master-controller.yaml"}}).
|
FilenameParam(false, &FilenameOptions{Recursive: false, Filenames: []string{"../../../examples/guestbook/legacy/redis-master-controller.yaml"}}).
|
||||||
Flatten().
|
Flatten().
|
||||||
|
@ -1035,7 +1047,7 @@ func TestSingleItemImpliedObject(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSingleItemImpliedObjectNoExtension(t *testing.T) {
|
func TestSingleItemImpliedObjectNoExtension(t *testing.T) {
|
||||||
obj, err := NewBuilder(restmapper, categories.LegacyCategoryExpander, scheme.Scheme, fakeClient(), corev1Codec).
|
obj, err := newDefaultBuilder().
|
||||||
NamespaceParam("test").DefaultNamespace().
|
NamespaceParam("test").DefaultNamespace().
|
||||||
FilenameParam(false, &FilenameOptions{Recursive: false, Filenames: []string{"../../../examples/pod"}}).
|
FilenameParam(false, &FilenameOptions{Recursive: false, Filenames: []string{"../../../examples/pod"}}).
|
||||||
Flatten().
|
Flatten().
|
||||||
|
@ -1057,7 +1069,7 @@ func TestSingleItemImpliedObjectNoExtension(t *testing.T) {
|
||||||
func TestSingleItemImpliedRootScopedObject(t *testing.T) {
|
func TestSingleItemImpliedRootScopedObject(t *testing.T) {
|
||||||
node := &v1.Node{ObjectMeta: metav1.ObjectMeta{Name: "test"}, Spec: v1.NodeSpec{ExternalID: "test"}}
|
node := &v1.Node{ObjectMeta: metav1.ObjectMeta{Name: "test"}, Spec: v1.NodeSpec{ExternalID: "test"}}
|
||||||
r := streamTestObject(node)
|
r := streamTestObject(node)
|
||||||
infos, err := NewBuilder(restmapper, categories.LegacyCategoryExpander, scheme.Scheme, fakeClient(), corev1Codec).
|
infos, err := newDefaultBuilder().
|
||||||
NamespaceParam("test").DefaultNamespace().
|
NamespaceParam("test").DefaultNamespace().
|
||||||
Stream(r, "STDIN").
|
Stream(r, "STDIN").
|
||||||
Flatten().
|
Flatten().
|
||||||
|
@ -1082,9 +1094,9 @@ func TestSingleItemImpliedRootScopedObject(t *testing.T) {
|
||||||
func TestListObject(t *testing.T) {
|
func TestListObject(t *testing.T) {
|
||||||
pods, _ := testData()
|
pods, _ := testData()
|
||||||
labelKey := metav1.LabelSelectorQueryParam(corev1GV.String())
|
labelKey := metav1.LabelSelectorQueryParam(corev1GV.String())
|
||||||
b := NewBuilder(restmapper, categories.LegacyCategoryExpander, scheme.Scheme, fakeClientWith("", t, map[string]string{
|
b := newDefaultBuilderWith(fakeClientWith("", t, map[string]string{
|
||||||
"/namespaces/test/pods?" + labelKey + "=a%3Db": runtime.EncodeOrDie(corev1Codec, pods),
|
"/namespaces/test/pods?" + labelKey + "=a%3Db": runtime.EncodeOrDie(corev1Codec, pods),
|
||||||
}), corev1Codec).
|
})).
|
||||||
LabelSelectorParam("a=b").
|
LabelSelectorParam("a=b").
|
||||||
NamespaceParam("test").
|
NamespaceParam("test").
|
||||||
ResourceTypeOrNameArgs(true, "pods").
|
ResourceTypeOrNameArgs(true, "pods").
|
||||||
|
@ -1115,10 +1127,10 @@ func TestListObject(t *testing.T) {
|
||||||
func TestListObjectWithDifferentVersions(t *testing.T) {
|
func TestListObjectWithDifferentVersions(t *testing.T) {
|
||||||
pods, svc := testData()
|
pods, svc := testData()
|
||||||
labelKey := metav1.LabelSelectorQueryParam(corev1GV.String())
|
labelKey := metav1.LabelSelectorQueryParam(corev1GV.String())
|
||||||
obj, err := NewBuilder(restmapper, categories.LegacyCategoryExpander, scheme.Scheme, fakeClientWith("", t, map[string]string{
|
obj, err := newDefaultBuilderWith(fakeClientWith("", t, map[string]string{
|
||||||
"/namespaces/test/pods?" + labelKey + "=a%3Db": runtime.EncodeOrDie(corev1Codec, pods),
|
"/namespaces/test/pods?" + labelKey + "=a%3Db": runtime.EncodeOrDie(corev1Codec, pods),
|
||||||
"/namespaces/test/services?" + labelKey + "=a%3Db": runtime.EncodeOrDie(corev1Codec, svc),
|
"/namespaces/test/services?" + labelKey + "=a%3Db": runtime.EncodeOrDie(corev1Codec, svc),
|
||||||
}), corev1Codec).
|
})).
|
||||||
LabelSelectorParam("a=b").
|
LabelSelectorParam("a=b").
|
||||||
NamespaceParam("test").
|
NamespaceParam("test").
|
||||||
ResourceTypeOrNameArgs(true, "pods,services").
|
ResourceTypeOrNameArgs(true, "pods,services").
|
||||||
|
@ -1141,12 +1153,12 @@ func TestListObjectWithDifferentVersions(t *testing.T) {
|
||||||
|
|
||||||
func TestWatch(t *testing.T) {
|
func TestWatch(t *testing.T) {
|
||||||
_, svc := testData()
|
_, svc := testData()
|
||||||
w, err := NewBuilder(restmapper, categories.LegacyCategoryExpander, scheme.Scheme, fakeClientWith("", t, map[string]string{
|
w, err := newDefaultBuilderWith(fakeClientWith("", t, map[string]string{
|
||||||
"/namespaces/test/services?fieldSelector=metadata.name%3Dredis-master&resourceVersion=12&watch=true": watchBody(watch.Event{
|
"/namespaces/test/services?fieldSelector=metadata.name%3Dredis-master&resourceVersion=12&watch=true": watchBody(watch.Event{
|
||||||
Type: watch.Added,
|
Type: watch.Added,
|
||||||
Object: &svc.Items[0],
|
Object: &svc.Items[0],
|
||||||
}),
|
}),
|
||||||
}), corev1Codec).
|
})).
|
||||||
NamespaceParam("test").DefaultNamespace().
|
NamespaceParam("test").DefaultNamespace().
|
||||||
FilenameParam(false, &FilenameOptions{Recursive: false, Filenames: []string{"../../../examples/guestbook/redis-master-service.yaml"}}).Flatten().
|
FilenameParam(false, &FilenameOptions{Recursive: false, Filenames: []string{"../../../examples/guestbook/redis-master-service.yaml"}}).Flatten().
|
||||||
Do().Watch("12")
|
Do().Watch("12")
|
||||||
|
@ -1173,7 +1185,7 @@ func TestWatch(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestWatchMultipleError(t *testing.T) {
|
func TestWatchMultipleError(t *testing.T) {
|
||||||
_, err := NewBuilder(restmapper, categories.LegacyCategoryExpander, scheme.Scheme, fakeClient(), corev1Codec).
|
_, err := newDefaultBuilder().
|
||||||
NamespaceParam("test").DefaultNamespace().
|
NamespaceParam("test").DefaultNamespace().
|
||||||
FilenameParam(false, &FilenameOptions{Recursive: false, Filenames: []string{"../../../examples/guestbook/legacy/redis-master-controller.yaml"}}).Flatten().
|
FilenameParam(false, &FilenameOptions{Recursive: false, Filenames: []string{"../../../examples/guestbook/legacy/redis-master-controller.yaml"}}).Flatten().
|
||||||
FilenameParam(false, &FilenameOptions{Recursive: false, Filenames: []string{"../../../examples/guestbook/legacy/redis-master-controller.yaml"}}).Flatten().
|
FilenameParam(false, &FilenameOptions{Recursive: false, Filenames: []string{"../../../examples/guestbook/legacy/redis-master-controller.yaml"}}).Flatten().
|
||||||
|
@ -1196,11 +1208,11 @@ func TestLatest(t *testing.T) {
|
||||||
ObjectMeta: metav1.ObjectMeta{Name: "baz", Namespace: "test", ResourceVersion: "15"},
|
ObjectMeta: metav1.ObjectMeta{Name: "baz", Namespace: "test", ResourceVersion: "15"},
|
||||||
}
|
}
|
||||||
|
|
||||||
b := NewBuilder(restmapper, categories.LegacyCategoryExpander, scheme.Scheme, fakeClientWith("", t, map[string]string{
|
b := newDefaultBuilderWith(fakeClientWith("", t, map[string]string{
|
||||||
"/namespaces/test/pods/foo": runtime.EncodeOrDie(corev1Codec, newPod),
|
"/namespaces/test/pods/foo": runtime.EncodeOrDie(corev1Codec, newPod),
|
||||||
"/namespaces/test/pods/bar": runtime.EncodeOrDie(corev1Codec, newPod2),
|
"/namespaces/test/pods/bar": runtime.EncodeOrDie(corev1Codec, newPod2),
|
||||||
"/namespaces/test/services/baz": runtime.EncodeOrDie(corev1Codec, newSvc),
|
"/namespaces/test/services/baz": runtime.EncodeOrDie(corev1Codec, newSvc),
|
||||||
}), corev1Codec).
|
})).
|
||||||
NamespaceParam("other").Stream(r, "STDIN").Flatten().Latest()
|
NamespaceParam("other").Stream(r, "STDIN").Flatten().Latest()
|
||||||
|
|
||||||
test := &testVisitor{}
|
test := &testVisitor{}
|
||||||
|
@ -1232,7 +1244,7 @@ func TestReceiveMultipleErrors(t *testing.T) {
|
||||||
w2.Write([]byte(runtime.EncodeOrDie(corev1Codec, &svc.Items[0])))
|
w2.Write([]byte(runtime.EncodeOrDie(corev1Codec, &svc.Items[0])))
|
||||||
}()
|
}()
|
||||||
|
|
||||||
b := NewBuilder(restmapper, categories.LegacyCategoryExpander, scheme.Scheme, fakeClient(), corev1Codec).
|
b := newDefaultBuilder().
|
||||||
Stream(r, "1").Stream(r2, "2").
|
Stream(r, "1").Stream(r2, "2").
|
||||||
ContinueOnError()
|
ContinueOnError()
|
||||||
|
|
||||||
|
|
|
@ -25,17 +25,7 @@ import (
|
||||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||||
)
|
)
|
||||||
|
|
||||||
// DisabledClientForMapping allows callers to avoid allowing remote calls when handling
|
// Mapper is a convenience struct for holding references to the interfaces
|
||||||
// resources.
|
|
||||||
type DisabledClientForMapping struct {
|
|
||||||
ClientMapper
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f DisabledClientForMapping) ClientForMapping(mapping *meta.RESTMapping) (RESTClient, error) {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Mapper is a convenience struct for holding references to the three interfaces
|
|
||||||
// needed to create Info for arbitrary objects.
|
// needed to create Info for arbitrary objects.
|
||||||
type Mapper struct {
|
type Mapper struct {
|
||||||
runtime.ObjectTyper
|
runtime.ObjectTyper
|
||||||
|
@ -44,17 +34,27 @@ type Mapper struct {
|
||||||
runtime.Decoder
|
runtime.Decoder
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AcceptUnrecognizedObjects will return a mapper that will tolerate objects
|
||||||
|
// that are not recognized by the RESTMapper, returning mappings that can
|
||||||
|
// perform minimal transformation. Allows working in disconnected mode, or with
|
||||||
|
// objects that the server does not recognize. Returned resource.Info objects
|
||||||
|
// may have empty resource fields and nil clients.
|
||||||
|
func (m *Mapper) AcceptUnrecognizedObjects() *Mapper {
|
||||||
|
copied := *m
|
||||||
|
copied.RESTMapper = NewRelaxedRESTMapper(m.RESTMapper)
|
||||||
|
copied.ClientMapper = NewRelaxedClientMapper(m.ClientMapper)
|
||||||
|
return &copied
|
||||||
|
}
|
||||||
|
|
||||||
// InfoForData creates an Info object for the given data. An error is returned
|
// InfoForData creates an Info object for the given data. An error is returned
|
||||||
// if any of the decoding or client lookup steps fail. Name and namespace will be
|
// if any of the decoding or client lookup steps fail. Name and namespace will be
|
||||||
// set into Info if the mapping's MetadataAccessor can retrieve them.
|
// set into Info if the mapping's MetadataAccessor can retrieve them.
|
||||||
func (m *Mapper) InfoForData(data []byte, source string) (*Info, error) {
|
func (m *Mapper) InfoForData(data []byte, source string) (*Info, error) {
|
||||||
versions := &runtime.VersionedObjects{}
|
obj, gvk, err := m.Decode(data, nil, nil)
|
||||||
_, gvk, err := m.Decode(data, nil, versions)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("unable to decode %q: %v", source, err)
|
return nil, fmt.Errorf("unable to decode %q: %v", source, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
obj, versioned := versions.Last(), versions.First()
|
|
||||||
mapping, err := m.RESTMapping(gvk.GroupKind(), gvk.Version)
|
mapping, err := m.RESTMapping(gvk.GroupKind(), gvk.Version)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("unable to recognize %q: %v", source, err)
|
return nil, fmt.Errorf("unable to recognize %q: %v", source, err)
|
||||||
|
@ -70,14 +70,15 @@ func (m *Mapper) InfoForData(data []byte, source string) (*Info, error) {
|
||||||
resourceVersion, _ := mapping.MetadataAccessor.ResourceVersion(obj)
|
resourceVersion, _ := mapping.MetadataAccessor.ResourceVersion(obj)
|
||||||
|
|
||||||
return &Info{
|
return &Info{
|
||||||
Mapping: mapping,
|
Client: client,
|
||||||
Client: client,
|
Mapping: mapping,
|
||||||
|
|
||||||
|
Source: source,
|
||||||
Namespace: namespace,
|
Namespace: namespace,
|
||||||
Name: name,
|
Name: name,
|
||||||
Source: source,
|
|
||||||
VersionedObject: versioned,
|
|
||||||
Object: obj,
|
|
||||||
ResourceVersion: resourceVersion,
|
ResourceVersion: resourceVersion,
|
||||||
|
|
||||||
|
Object: obj,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -99,6 +100,7 @@ func (m *Mapper) InfoForObject(obj runtime.Object, preferredGVKs []schema.GroupV
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("unable to recognize %v: %v", groupVersionKind, err)
|
return nil, fmt.Errorf("unable to recognize %v: %v", groupVersionKind, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
client, err := m.ClientForMapping(mapping)
|
client, err := m.ClientForMapping(mapping)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("unable to connect to a server to handle %q: %v", mapping.Resource, err)
|
return nil, fmt.Errorf("unable to connect to a server to handle %q: %v", mapping.Resource, err)
|
||||||
|
@ -107,13 +109,14 @@ func (m *Mapper) InfoForObject(obj runtime.Object, preferredGVKs []schema.GroupV
|
||||||
namespace, _ := mapping.MetadataAccessor.Namespace(obj)
|
namespace, _ := mapping.MetadataAccessor.Namespace(obj)
|
||||||
resourceVersion, _ := mapping.MetadataAccessor.ResourceVersion(obj)
|
resourceVersion, _ := mapping.MetadataAccessor.ResourceVersion(obj)
|
||||||
return &Info{
|
return &Info{
|
||||||
Mapping: mapping,
|
Client: client,
|
||||||
Client: client,
|
Mapping: mapping,
|
||||||
Namespace: namespace,
|
|
||||||
Name: name,
|
|
||||||
|
|
||||||
Object: obj,
|
Namespace: namespace,
|
||||||
|
Name: name,
|
||||||
ResourceVersion: resourceVersion,
|
ResourceVersion: resourceVersion,
|
||||||
|
|
||||||
|
Object: obj,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -152,3 +155,83 @@ func preferredObjectKind(possibilities []schema.GroupVersionKind, preferences []
|
||||||
// Just pick the first
|
// Just pick the first
|
||||||
return possibilities[0]
|
return possibilities[0]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DisabledClientForMapping allows callers to avoid allowing remote calls when handling
|
||||||
|
// resources.
|
||||||
|
type DisabledClientForMapping struct {
|
||||||
|
ClientMapper
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f DisabledClientForMapping) ClientForMapping(mapping *meta.RESTMapping) (RESTClient, error) {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewRelaxedClientMapper will return a nil mapping if the object is not a recognized resource.
|
||||||
|
func NewRelaxedClientMapper(mapper ClientMapper) ClientMapper {
|
||||||
|
return relaxedClientMapper{mapper}
|
||||||
|
}
|
||||||
|
|
||||||
|
type relaxedClientMapper struct {
|
||||||
|
ClientMapper
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f relaxedClientMapper) ClientForMapping(mapping *meta.RESTMapping) (RESTClient, error) {
|
||||||
|
if len(mapping.Resource) == 0 {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
return f.ClientMapper.ClientForMapping(mapping)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewRelaxedRESTMapper returns a RESTMapper that will tolerate mappings that don't exist in provided
|
||||||
|
// RESTMapper, returning a mapping that is a best effort against the current server. This allows objects
|
||||||
|
// that the server does not recognize to still be loaded.
|
||||||
|
func NewRelaxedRESTMapper(mapper meta.RESTMapper) meta.RESTMapper {
|
||||||
|
return relaxedMapper{mapper}
|
||||||
|
}
|
||||||
|
|
||||||
|
type relaxedMapper struct {
|
||||||
|
meta.RESTMapper
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m relaxedMapper) RESTMapping(gk schema.GroupKind, versions ...string) (*meta.RESTMapping, error) {
|
||||||
|
mapping, err := m.RESTMapper.RESTMapping(gk, versions...)
|
||||||
|
if err != nil && meta.IsNoMatchError(err) && len(versions) > 0 {
|
||||||
|
return &meta.RESTMapping{
|
||||||
|
GroupVersionKind: gk.WithVersion(versions[0]),
|
||||||
|
MetadataAccessor: meta.NewAccessor(),
|
||||||
|
Scope: meta.RESTScopeRoot,
|
||||||
|
ObjectConvertor: identityConvertor{},
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
return mapping, err
|
||||||
|
}
|
||||||
|
func (m relaxedMapper) RESTMappings(gk schema.GroupKind, versions ...string) ([]*meta.RESTMapping, error) {
|
||||||
|
mappings, err := m.RESTMapper.RESTMappings(gk, versions...)
|
||||||
|
if err != nil && meta.IsNoMatchError(err) && len(versions) > 0 {
|
||||||
|
return []*meta.RESTMapping{
|
||||||
|
{
|
||||||
|
GroupVersionKind: gk.WithVersion(versions[0]),
|
||||||
|
MetadataAccessor: meta.NewAccessor(),
|
||||||
|
Scope: meta.RESTScopeRoot,
|
||||||
|
ObjectConvertor: identityConvertor{},
|
||||||
|
},
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
return mappings, err
|
||||||
|
}
|
||||||
|
|
||||||
|
type identityConvertor struct{}
|
||||||
|
|
||||||
|
var _ runtime.ObjectConvertor = identityConvertor{}
|
||||||
|
|
||||||
|
func (c identityConvertor) Convert(in interface{}, out interface{}, context interface{}) error {
|
||||||
|
return fmt.Errorf("unable to convert objects across pointers")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c identityConvertor) ConvertToVersion(in runtime.Object, gv runtime.GroupVersioner) (out runtime.Object, err error) {
|
||||||
|
return in, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c identityConvertor) ConvertFieldLabel(version string, kind string, label string, value string) (string, string, error) {
|
||||||
|
return "", "", fmt.Errorf("unable to convert field labels")
|
||||||
|
}
|
||||||
|
|
|
@ -41,6 +41,7 @@ type Result struct {
|
||||||
singleItemImplied bool
|
singleItemImplied bool
|
||||||
targetsSingleItems bool
|
targetsSingleItems bool
|
||||||
|
|
||||||
|
mapper *Mapper
|
||||||
ignoreErrors []utilerrors.Matcher
|
ignoreErrors []utilerrors.Matcher
|
||||||
|
|
||||||
// populated by a call to Infos
|
// populated by a call to Infos
|
||||||
|
@ -74,6 +75,11 @@ func (r *Result) IgnoreErrors(fns ...ErrMatchFunc) *Result {
|
||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Mapper returns a copy of the builder's mapper.
|
||||||
|
func (r *Result) Mapper() *Mapper {
|
||||||
|
return r.mapper
|
||||||
|
}
|
||||||
|
|
||||||
// Err returns one or more errors (via a util.ErrorList) that occurred prior
|
// Err returns one or more errors (via a util.ErrorList) that occurred prior
|
||||||
// to visiting the elements in the visitor. To see all errors including those
|
// to visiting the elements in the visitor. To see all errors including those
|
||||||
// that occur during visitation, invoke Infos().
|
// that occur during visitation, invoke Infos().
|
||||||
|
|
|
@ -92,13 +92,15 @@ func (r *Selector) Visit(fn VisitorFunc) error {
|
||||||
resourceVersion, _ := accessor.ResourceVersion(list)
|
resourceVersion, _ := accessor.ResourceVersion(list)
|
||||||
nextContinueToken, _ := accessor.Continue(list)
|
nextContinueToken, _ := accessor.Continue(list)
|
||||||
info := &Info{
|
info := &Info{
|
||||||
Client: r.Client,
|
Client: r.Client,
|
||||||
Mapping: r.Mapping,
|
Mapping: r.Mapping,
|
||||||
Namespace: r.Namespace,
|
|
||||||
|
|
||||||
Object: list,
|
Namespace: r.Namespace,
|
||||||
ResourceVersion: resourceVersion,
|
ResourceVersion: resourceVersion,
|
||||||
|
|
||||||
|
Object: list,
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := fn(info, nil); err != nil {
|
if err := fn(info, nil); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -81,10 +81,6 @@ type Info struct {
|
||||||
// Optional, Source is the filename or URL to template file (.json or .yaml),
|
// Optional, Source is the filename or URL to template file (.json or .yaml),
|
||||||
// or stdin to use to handle the resource
|
// or stdin to use to handle the resource
|
||||||
Source string
|
Source string
|
||||||
// Optional, this is the provided object in a versioned type before defaulting
|
|
||||||
// and conversions into its corresponding internal type. This is useful for
|
|
||||||
// reflecting on user intent which may be lost after defaulting and conversions.
|
|
||||||
VersionedObject runtime.Object
|
|
||||||
// Optional, this is the most recent value returned by the server if available
|
// Optional, this is the most recent value returned by the server if available
|
||||||
Object runtime.Object
|
Object runtime.Object
|
||||||
// Optional, this is the most recent resource version the server knows about for
|
// Optional, this is the most recent resource version the server knows about for
|
||||||
|
@ -96,17 +92,6 @@ type Info struct {
|
||||||
Export bool
|
Export bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewInfo returns a new info object
|
|
||||||
func NewInfo(client RESTClient, mapping *meta.RESTMapping, namespace, name string, export bool) *Info {
|
|
||||||
return &Info{
|
|
||||||
Client: client,
|
|
||||||
Mapping: mapping,
|
|
||||||
Namespace: namespace,
|
|
||||||
Name: name,
|
|
||||||
Export: export,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Visit implements Visitor
|
// Visit implements Visitor
|
||||||
func (i *Info) Visit(fn VisitorFunc) error {
|
func (i *Info) Visit(fn VisitorFunc) error {
|
||||||
return fn(i, nil)
|
return fn(i, nil)
|
||||||
|
@ -388,10 +373,7 @@ func (v FlattenListVisitor) Visit(fn VisitorFunc) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fn(info, nil)
|
return fn(info, nil)
|
||||||
}
|
}
|
||||||
if errs := runtime.DecodeList(items, struct {
|
if errs := runtime.DecodeList(items, v.Mapper.Decoder); len(errs) > 0 {
|
||||||
runtime.ObjectTyper
|
|
||||||
runtime.Decoder
|
|
||||||
}{v.Mapper, v.Mapper.Decoder}); len(errs) > 0 {
|
|
||||||
return utilerrors.NewAggregate(errs)
|
return utilerrors.NewAggregate(errs)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,8 +21,24 @@ import (
|
||||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// InterfacesForUnstructuredConversion returns VersionInterfaces suitable for
|
||||||
|
// dealing with unstructured.Unstructured objects and supports conversion
|
||||||
|
// from typed objects (provided by parent) to untyped objects.
|
||||||
|
func InterfacesForUnstructuredConversion(parent VersionInterfacesFunc) VersionInterfacesFunc {
|
||||||
|
return func(version schema.GroupVersion) (*VersionInterfaces, error) {
|
||||||
|
if i, err := parent(version); err == nil {
|
||||||
|
return &VersionInterfaces{
|
||||||
|
ObjectConvertor: i.ObjectConvertor,
|
||||||
|
MetadataAccessor: NewAccessor(),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
return InterfacesForUnstructured(version)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// InterfacesForUnstructured returns VersionInterfaces suitable for
|
// InterfacesForUnstructured returns VersionInterfaces suitable for
|
||||||
// dealing with unstructured.Unstructured objects.
|
// dealing with unstructured.Unstructured objects. It will return errors for
|
||||||
|
// other conversions.
|
||||||
func InterfacesForUnstructured(schema.GroupVersion) (*VersionInterfaces, error) {
|
func InterfacesForUnstructured(schema.GroupVersion) (*VersionInterfaces, error) {
|
||||||
return &VersionInterfaces{
|
return &VersionInterfaces{
|
||||||
ObjectConvertor: &unstructured.UnstructuredObjectConverter{},
|
ObjectConvertor: &unstructured.UnstructuredObjectConverter{},
|
||||||
|
|
Loading…
Reference in New Issue