Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 61673c4

Browse files
committed
make kubectl get generic with respect to objects
1 parent 7fe9bd4 commit 61673c4

16 files changed

Lines changed: 411 additions & 395 deletions

pkg/api/meta/help.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,14 @@ import (
2626

2727
// IsListType returns true if the provided Object has a slice called Items
2828
func IsListType(obj runtime.Object) bool {
29+
// if we're a runtime.Unstructured, check to see if we have an `items` key
30+
// This is a list type for recognition, but other Items type methods will fail on it
31+
// and give you errors.
32+
if unstructured, ok := obj.(*runtime.Unstructured); ok {
33+
_, ok := unstructured.Object["items"]
34+
return ok
35+
}
36+
2937
_, err := GetItemsPtr(obj)
3038
return err == nil
3139
}
@@ -39,6 +47,7 @@ func GetItemsPtr(list runtime.Object) (interface{}, error) {
3947
if err != nil {
4048
return nil, err
4149
}
50+
4251
items := v.FieldByName("Items")
4352
if !items.IsValid() {
4453
return nil, fmt.Errorf("no Items field in %#v", list)
@@ -117,6 +126,13 @@ func SetList(list runtime.Object, objects []runtime.Object) error {
117126
slice := reflect.MakeSlice(items.Type(), len(objects), len(objects))
118127
for i := range objects {
119128
dest := slice.Index(i)
129+
130+
// check to see if you're directly assignable
131+
if reflect.TypeOf(objects[i]).AssignableTo(dest.Type()) {
132+
dest.Set(reflect.ValueOf(objects[i]))
133+
continue
134+
}
135+
120136
src, err := conversion.EnforcePtr(objects[i])
121137
if err != nil {
122138
return err

pkg/api/meta/help_test.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,27 @@ func TestSetListToRuntimeObjectArray(t *testing.T) {
229229
}
230230
}
231231

232+
func TestSetListToMatchingType(t *testing.T) {
233+
pl := &runtime.UnstructuredList{}
234+
list := []runtime.Object{
235+
&runtime.Unstructured{Object: map[string]interface{}{"foo": 1}},
236+
&runtime.Unstructured{Object: map[string]interface{}{"foo": 2}},
237+
&runtime.Unstructured{Object: map[string]interface{}{"foo": 3}},
238+
}
239+
err := meta.SetList(pl, list)
240+
if err != nil {
241+
t.Fatalf("Unexpected error %v", err)
242+
}
243+
if e, a := len(list), len(pl.Items); e != a {
244+
t.Fatalf("Expected %v, got %v", e, a)
245+
}
246+
for i := range list {
247+
if e, a := list[i], pl.Items[i]; e != a {
248+
t.Fatalf("%d: unmatched: %s", i, diff.ObjectDiff(e, a))
249+
}
250+
}
251+
}
252+
232253
func TestSetExtractListRoundTrip(t *testing.T) {
233254
fuzzer := fuzz.New().NilChance(0).NumElements(1, 5)
234255
for i := 0; i < 5; i++ {

pkg/kubectl/cmd/BUILD

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -182,11 +182,9 @@ go_test(
182182
"//pkg/kubectl/cmd/util:go_default_library",
183183
"//pkg/kubectl/resource:go_default_library",
184184
"//pkg/runtime:go_default_library",
185-
"//pkg/runtime/serializer:go_default_library",
186185
"//pkg/runtime/serializer/json:go_default_library",
187186
"//pkg/runtime/serializer/streaming:go_default_library",
188187
"//pkg/types:go_default_library",
189-
"//pkg/util/diff:go_default_library",
190188
"//pkg/util/intstr:go_default_library",
191189
"//pkg/util/strings:go_default_library",
192190
"//pkg/util/term:go_default_library",

pkg/kubectl/cmd/delete_test.go

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -28,16 +28,12 @@ import (
2828
"k8s.io/kubernetes/pkg/apimachinery/registered"
2929
"k8s.io/kubernetes/pkg/client/restclient"
3030
"k8s.io/kubernetes/pkg/client/restclient/fake"
31+
"k8s.io/kubernetes/pkg/client/typed/dynamic"
3132
cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing"
3233
"k8s.io/kubernetes/pkg/kubectl/resource"
33-
"k8s.io/kubernetes/pkg/runtime"
34-
"k8s.io/kubernetes/pkg/runtime/serializer"
3534
)
3635

37-
var unstructuredSerializer = serializer.NegotiatedSerializerWrapper(runtime.SerializerInfo{
38-
MediaType: "application/json",
39-
EncodesAsText: true,
40-
Serializer: runtime.UnstructuredJSONScheme})
36+
var unstructuredSerializer = dynamic.ContentConfig().NegotiatedSerializer
4137

4238
func TestDeleteObjectByTuple(t *testing.T) {
4339
_, _, rc := testData()

pkg/kubectl/cmd/get.go

Lines changed: 43 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,10 @@ func RunGet(f cmdutil.Factory, out, errOut io.Writer, cmd *cobra.Command, args [
149149
selector := cmdutil.GetFlagString(cmd, "selector")
150150
allNamespaces := cmdutil.GetFlagBool(cmd, "all-namespaces")
151151
showKind := cmdutil.GetFlagBool(cmd, "show-kind")
152-
mapper, typer := f.Object()
152+
mapper, typer, err := f.UnstructuredObject()
153+
if err != nil {
154+
return err
155+
}
153156
printAll := false
154157
filterFuncs := f.DefaultResourceFilterFunc()
155158
filterOpts := f.DefaultResourceFilterOptions(cmd, allNamespaces)
@@ -196,7 +199,7 @@ func RunGet(f cmdutil.Factory, out, errOut io.Writer, cmd *cobra.Command, args [
196199
// handle watch separately since we cannot watch multiple resource types
197200
isWatch, isWatchOnly := cmdutil.GetFlagBool(cmd, "watch"), cmdutil.GetFlagBool(cmd, "watch-only")
198201
if isWatch || isWatchOnly {
199-
r := resource.NewBuilder(mapper, typer, resource.ClientMapperFunc(f.ClientForMapping), f.Decoder(true)).
202+
r := resource.NewBuilder(mapper, typer, resource.ClientMapperFunc(f.UnstructuredClientForMapping), runtime.UnstructuredJSONScheme).
200203
NamespaceParam(cmdNamespace).DefaultNamespace().AllNamespaces(allNamespaces).
201204
FilenameParam(enforceNamespace, &options.FilenameOptions).
202205
SelectorParam(selector).
@@ -281,7 +284,7 @@ func RunGet(f cmdutil.Factory, out, errOut io.Writer, cmd *cobra.Command, args [
281284
return nil
282285
}
283286

284-
r := resource.NewBuilder(mapper, typer, resource.ClientMapperFunc(f.ClientForMapping), f.Decoder(true)).
287+
r := resource.NewBuilder(mapper, typer, resource.ClientMapperFunc(f.UnstructuredClientForMapping), runtime.UnstructuredJSONScheme).
285288
NamespaceParam(cmdNamespace).DefaultNamespace().AllNamespaces(allNamespaces).
286289
FilenameParam(enforceNamespace, &options.FilenameOptions).
287290
SelectorParam(selector).
@@ -302,18 +305,10 @@ func RunGet(f cmdutil.Factory, out, errOut io.Writer, cmd *cobra.Command, args [
302305
}
303306

304307
if generic {
305-
clientConfig, err := f.ClientConfig()
306-
if err != nil {
307-
return err
308-
}
309-
310-
// the outermost object will be converted to the output-version, but inner
311-
// objects can use their mappings
312-
version, err := cmdutil.OutputVersion(cmd, clientConfig.GroupVersion)
313-
if err != nil {
314-
return err
315-
}
316-
308+
// we flattened the data from the builder, so we have individual items, but now we'd like to either:
309+
// 1. if there is more than one item, combine them all into a single list
310+
// 2. if there is a single item and that item is a list, leave it as its specific list
311+
// 3. if there is a single item and it is not a a list, leave it as a single item
317312
var errs []error
318313
singular := false
319314
infos, err := r.IntoSingular(&singular).Infos()
@@ -332,9 +327,22 @@ func RunGet(f cmdutil.Factory, out, errOut io.Writer, cmd *cobra.Command, args [
332327
res = infos[0].ResourceMapping().Resource
333328
}
334329

335-
obj, err := resource.AsVersionedObject(infos, !singular, version, f.JSONEncoder())
336-
if err != nil {
337-
return err
330+
var obj runtime.Object
331+
if singular {
332+
obj = infos[0].Object
333+
} else {
334+
// we have more than one item, so coerce all items into a list
335+
list := &runtime.UnstructuredList{
336+
Object: map[string]interface{}{
337+
"kind": "List",
338+
"apiVersion": "v1",
339+
"metadata": map[string]interface{}{},
340+
},
341+
}
342+
for _, info := range infos {
343+
list.Items = append(list.Items, info.Object.(*runtime.Unstructured))
344+
}
345+
obj = list
338346
}
339347

340348
isList := meta.IsListType(obj)
@@ -343,11 +351,24 @@ func RunGet(f cmdutil.Factory, out, errOut io.Writer, cmd *cobra.Command, args [
343351
if err != nil {
344352
return err
345353
}
346-
filteredObj, err := cmdutil.ObjectListToVersionedObject(items, version)
347-
if err != nil {
348-
return err
354+
355+
// take the filtered items and create a new list for display
356+
list := &runtime.UnstructuredList{
357+
Object: map[string]interface{}{
358+
"kind": "List",
359+
"apiVersion": "v1",
360+
"metadata": map[string]interface{}{},
361+
},
362+
}
363+
if listMeta, err := meta.ListAccessor(obj); err == nil {
364+
list.Object["selfLink"] = listMeta.GetSelfLink()
365+
list.Object["resourceVersion"] = listMeta.GetResourceVersion()
349366
}
350-
if err := printer.PrintObj(filteredObj, out); err != nil {
367+
368+
for _, item := range items {
369+
list.Items = append(list.Items, item.(*runtime.Unstructured))
370+
}
371+
if err := printer.PrintObj(list, out); err != nil {
351372
errs = append(errs, err)
352373
}
353374

@@ -390,24 +411,6 @@ func RunGet(f cmdutil.Factory, out, errOut io.Writer, cmd *cobra.Command, args [
390411
}
391412
var sorter *kubectl.RuntimeSort
392413
if len(sorting) > 0 && len(objs) > 1 {
393-
clientConfig, err := f.ClientConfig()
394-
if err != nil {
395-
return err
396-
}
397-
398-
version, err := cmdutil.OutputVersion(cmd, clientConfig.GroupVersion)
399-
if err != nil {
400-
return err
401-
}
402-
403-
for ix := range infos {
404-
objs[ix], err = infos[ix].Mapping.ConvertToVersion(infos[ix].Object, version)
405-
if err != nil {
406-
allErrs = append(allErrs, err)
407-
continue
408-
}
409-
}
410-
411414
// TODO: questionable
412415
if sorter, err = kubectl.SortObjects(f.Decoder(true), objs, sorting); err != nil {
413416
return err

0 commit comments

Comments
 (0)