diff --git a/staging/src/k8s.io/apiextensions-apiserver/pkg/registry/customresource/tableconvertor/BUILD b/staging/src/k8s.io/apiextensions-apiserver/pkg/registry/customresource/tableconvertor/BUILD index 0eb833b5fd8..01cdba16bc9 100644 --- a/staging/src/k8s.io/apiextensions-apiserver/pkg/registry/customresource/tableconvertor/BUILD +++ b/staging/src/k8s.io/apiextensions-apiserver/pkg/registry/customresource/tableconvertor/BUILD @@ -37,6 +37,7 @@ go_test( embed = [":go_default_library"], deps = [ "//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", + "//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1/unstructured:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1beta1:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/util/diff:go_default_library", diff --git a/staging/src/k8s.io/apiextensions-apiserver/pkg/registry/customresource/tableconvertor/tableconvertor_test.go b/staging/src/k8s.io/apiextensions-apiserver/pkg/registry/customresource/tableconvertor/tableconvertor_test.go index 98b47486793..eab0beb000b 100644 --- a/staging/src/k8s.io/apiextensions-apiserver/pkg/registry/customresource/tableconvertor/tableconvertor_test.go +++ b/staging/src/k8s.io/apiextensions-apiserver/pkg/registry/customresource/tableconvertor/tableconvertor_test.go @@ -24,6 +24,7 @@ import ( "time" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" metav1beta1 "k8s.io/apimachinery/pkg/apis/meta/v1beta1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/util/diff" @@ -201,6 +202,225 @@ func Test_convertor_ConvertToTable(t *testing.T) { }, }, }, + { + name: "Return table with additional column containing multiple string values", + fields: fields{ + headers: []metav1.TableColumnDefinition{ + {Name: "name", Type: "string"}, + {Name: "valueOnly", Type: "string"}, + {Name: "single1", Type: "string"}, + {Name: "single2", Type: "string"}, + {Name: "multi", Type: "string"}, + }, + additionalColumns: []*jsonpath.JSONPath{ + newJSONPath("valueOnly", "{.spec.servers[0].hosts[0]}"), + newJSONPath("single1", "{.spec.servers[0].hosts}"), + newJSONPath("single2", "{.spec.servers[1].hosts}"), + newJSONPath("multi", "{.spec.servers[*].hosts}"), + }, + }, + args: args{ + obj: &unstructured.Unstructured{ + Object: map[string]interface{}{ + "apiVersion": "example.istio.io/v1alpha1", + "kind": "Blah", + "metadata": map[string]interface{}{ + "name": "blah", + }, + "spec": map[string]interface{}{ + "servers": []map[string]interface{}{ + {"hosts": []string{"foo"}}, + {"hosts": []string{"bar", "baz"}}, + }, + }, + }, + }, + tableOptions: nil, + }, + want: &metav1.Table{ + ColumnDefinitions: []metav1.TableColumnDefinition{ + {Name: "name", Type: "string"}, + {Name: "valueOnly", Type: "string"}, + {Name: "single1", Type: "string"}, + {Name: "single2", Type: "string"}, + {Name: "multi", Type: "string"}, + }, + Rows: []metav1.TableRow{ + { + Cells: []interface{}{ + "blah", + "foo", + `["foo"]`, + `["bar","baz"]`, + `["foo"]`, // TODO: TableConverter should be changed so that the response is this: `["foo"] ["bar","baz"]`, + }, + Object: runtime.RawExtension{ + Object: &unstructured.Unstructured{ + Object: map[string]interface{}{ + "apiVersion": "example.istio.io/v1alpha1", + "kind": "Blah", + "metadata": map[string]interface{}{ + "name": "blah", + }, + "spec": map[string]interface{}{ + "servers": []map[string]interface{}{ + {"hosts": []string{"foo"}}, + {"hosts": []string{"bar", "baz"}}, + }, + }, + }, + }, + }, + }, + }, + }, + }, + { + name: "Return table with additional column containing multiple integer values as string", + fields: fields{ + headers: []metav1.TableColumnDefinition{ + {Name: "name", Type: "string"}, + {Name: "valueOnly", Type: "string"}, + {Name: "single1", Type: "string"}, + {Name: "single2", Type: "string"}, + {Name: "multi", Type: "string"}, + }, + additionalColumns: []*jsonpath.JSONPath{ + newJSONPath("valueOnly", "{.spec.foo[0].bar[0]}"), + newJSONPath("single1", "{.spec.foo[0].bar}"), + newJSONPath("single2", "{.spec.foo[1].bar}"), + newJSONPath("multi", "{.spec.foo[*].bar}"), + }, + }, + args: args{ + obj: &unstructured.Unstructured{ + Object: map[string]interface{}{ + "apiVersion": "example.istio.io/v1alpha1", + "kind": "Blah", + "metadata": map[string]interface{}{ + "name": "blah", + }, + "spec": map[string]interface{}{ + "foo": []map[string]interface{}{ + {"bar": []int64{1}}, + {"bar": []int64{2, 3}}, + }, + }, + }, + }, + tableOptions: nil, + }, + want: &metav1.Table{ + ColumnDefinitions: []metav1.TableColumnDefinition{ + {Name: "name", Type: "string"}, + {Name: "valueOnly", Type: "string"}, + {Name: "single1", Type: "string"}, + {Name: "single2", Type: "string"}, + {Name: "multi", Type: "string"}, + }, + Rows: []metav1.TableRow{ + { + Cells: []interface{}{ + "blah", + "1", + "[1]", + "[2,3]", + "[1]", // TODO: TableConverter should be changed so that the response is this: `[1] [2,3]`, + }, + Object: runtime.RawExtension{ + Object: &unstructured.Unstructured{ + Object: map[string]interface{}{ + "apiVersion": "example.istio.io/v1alpha1", + "kind": "Blah", + "metadata": map[string]interface{}{ + "name": "blah", + }, + "spec": map[string]interface{}{ + "foo": []map[string]interface{}{ + {"bar": []int64{1}}, + {"bar": []int64{2, 3}}, + }, + }, + }, + }, + }, + }, + }, + }, + }, + { + name: "Return table with additional column containing multiple integer values", + fields: fields{ + headers: []metav1.TableColumnDefinition{ + {Name: "name", Type: "string"}, + {Name: "valueOnly", Type: "integer"}, + {Name: "single1", Type: "integer"}, + {Name: "single2", Type: "integer"}, + {Name: "multi", Type: "integer"}, + }, + additionalColumns: []*jsonpath.JSONPath{ + newJSONPath("valueOnly", "{.spec.foo[0].bar[0]}"), + newJSONPath("single1", "{.spec.foo[0].bar}"), + newJSONPath("single2", "{.spec.foo[1].bar}"), + newJSONPath("multi", "{.spec.foo[*].bar}"), + }, + }, + args: args{ + obj: &unstructured.Unstructured{ + Object: map[string]interface{}{ + "apiVersion": "example.istio.io/v1alpha1", + "kind": "Blah", + "metadata": map[string]interface{}{ + "name": "blah", + }, + "spec": map[string]interface{}{ + "foo": []map[string]interface{}{ + {"bar": []int64{1}}, + {"bar": []int64{2, 3}}, + }, + }, + }, + }, + tableOptions: nil, + }, + want: &metav1.Table{ + ColumnDefinitions: []metav1.TableColumnDefinition{ + {Name: "name", Type: "string"}, + {Name: "valueOnly", Type: "integer"}, + {Name: "single1", Type: "integer"}, + {Name: "single2", Type: "integer"}, + {Name: "multi", Type: "integer"}, + }, + Rows: []metav1.TableRow{ + { + Cells: []interface{}{ + "blah", + int64(1), + nil, // TODO: Seems like this should either return some data or return an error, not just be nil + nil, // TODO: Seems like this should either return some data or return an error, not just be nil + nil, // TODO: Seems like this should either return some data or return an error, not just be nil + }, + Object: runtime.RawExtension{ + Object: &unstructured.Unstructured{ + Object: map[string]interface{}{ + "apiVersion": "example.istio.io/v1alpha1", + "kind": "Blah", + "metadata": map[string]interface{}{ + "name": "blah", + }, + "spec": map[string]interface{}{ + "foo": []map[string]interface{}{ + {"bar": []int64{1}}, + {"bar": []int64{2, 3}}, + }, + }, + }, + }, + }, + }, + }, + }, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { @@ -219,3 +439,9 @@ func Test_convertor_ConvertToTable(t *testing.T) { }) } } + +func newJSONPath(name string, jsonPathExpression string) *jsonpath.JSONPath { + jp := jsonpath.New(name) + _ = jp.Parse(jsonPathExpression) + return jp +}