Merge pull request #77448 from smarterclayton/api_serve

Support meta.k8s.io/v1 Table and PartialObjectMetadata requests to the API

Kubernetes-commit: 274876ef9af526575f480c977f7dd7c4bb26e760
This commit is contained in:
Kubernetes Publisher 2019-05-10 21:30:37 -07:00
commit ecab80d4d8
6 changed files with 213 additions and 69 deletions

2
Godeps/Godeps.json generated
View File

@ -400,7 +400,7 @@
}, },
{ {
"ImportPath": "k8s.io/apimachinery", "ImportPath": "k8s.io/apimachinery",
"Rev": "ad85901afca0" "Rev": "5b67e417bf61"
}, },
{ {
"ImportPath": "k8s.io/client-go", "ImportPath": "k8s.io/client-go",

4
go.mod
View File

@ -59,7 +59,7 @@ require (
gopkg.in/yaml.v2 v2.2.1 gopkg.in/yaml.v2 v2.2.1
gotest.tools v2.2.0+incompatible // indirect gotest.tools v2.2.0+incompatible // indirect
k8s.io/api v0.0.0-20190511023547-e63b5755afac k8s.io/api v0.0.0-20190511023547-e63b5755afac
k8s.io/apimachinery v0.0.0-20190511023455-ad85901afca0 k8s.io/apimachinery v0.0.0-20190511063452-5b67e417bf61
k8s.io/client-go v0.0.0-20190511023711-c6f3777976ad k8s.io/client-go v0.0.0-20190511023711-c6f3777976ad
k8s.io/component-base v0.0.0-20190511024024-91ee9e34fdd1 k8s.io/component-base v0.0.0-20190511024024-91ee9e34fdd1
k8s.io/klog v0.3.0 k8s.io/klog v0.3.0
@ -75,7 +75,7 @@ replace (
golang.org/x/sys => golang.org/x/sys v0.0.0-20190209173611-3b5209105503 golang.org/x/sys => golang.org/x/sys v0.0.0-20190209173611-3b5209105503
golang.org/x/tools => golang.org/x/tools v0.0.0-20190313210603-aa82965741a9 golang.org/x/tools => golang.org/x/tools v0.0.0-20190313210603-aa82965741a9
k8s.io/api => k8s.io/api v0.0.0-20190511023547-e63b5755afac k8s.io/api => k8s.io/api v0.0.0-20190511023547-e63b5755afac
k8s.io/apimachinery => k8s.io/apimachinery v0.0.0-20190511023455-ad85901afca0 k8s.io/apimachinery => k8s.io/apimachinery v0.0.0-20190511063452-5b67e417bf61
k8s.io/client-go => k8s.io/client-go v0.0.0-20190511023711-c6f3777976ad k8s.io/client-go => k8s.io/client-go v0.0.0-20190511023711-c6f3777976ad
k8s.io/component-base => k8s.io/component-base v0.0.0-20190511024024-91ee9e34fdd1 k8s.io/component-base => k8s.io/component-base v0.0.0-20190511024024-91ee9e34fdd1
) )

2
go.sum
View File

@ -193,7 +193,7 @@ gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo= gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo=
gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
k8s.io/api v0.0.0-20190511023547-e63b5755afac/go.mod h1:f265Ep4XvHtyggfaaNhtP0AtAFilBaXq2fPjm5kYxwI= k8s.io/api v0.0.0-20190511023547-e63b5755afac/go.mod h1:f265Ep4XvHtyggfaaNhtP0AtAFilBaXq2fPjm5kYxwI=
k8s.io/apimachinery v0.0.0-20190511023455-ad85901afca0/go.mod h1:5CBnzrKYGHzv9ZsSKmQ8wHt4XI4/TUBPDwYM9FlZMyw= k8s.io/apimachinery v0.0.0-20190511063452-5b67e417bf61/go.mod h1:5CBnzrKYGHzv9ZsSKmQ8wHt4XI4/TUBPDwYM9FlZMyw=
k8s.io/client-go v0.0.0-20190511023711-c6f3777976ad/go.mod h1:+kqLjErve3/VoGTdnrw4Lu8D315nxEVQs1QEq8/uJ2E= k8s.io/client-go v0.0.0-20190511023711-c6f3777976ad/go.mod h1:+kqLjErve3/VoGTdnrw4Lu8D315nxEVQs1QEq8/uJ2E=
k8s.io/component-base v0.0.0-20190511024024-91ee9e34fdd1/go.mod h1:hlLSedoHFjaibpkg18jYZ0v6lpuhbLAVfenuqtu3Hrk= k8s.io/component-base v0.0.0-20190511024024-91ee9e34fdd1/go.mod h1:hlLSedoHFjaibpkg18jYZ0v6lpuhbLAVfenuqtu3Hrk=
k8s.io/klog v0.3.0 h1:0VPpR+sizsiivjIfIAQH/rl8tan6jvWkS7lU+0di3lE= k8s.io/klog v0.3.0 h1:0VPpR+sizsiivjIfIAQH/rl8tan6jvWkS7lU+0di3lE=

View File

@ -1749,14 +1749,14 @@ func TestGetPretty(t *testing.T) {
pretty bool pretty bool
}{ }{
{accept: runtime.ContentTypeJSON}, {accept: runtime.ContentTypeJSON},
{accept: runtime.ContentTypeJSON + ";pretty=0"}, {accept: "application/json;pretty=0"},
{accept: runtime.ContentTypeJSON, userAgent: "kubectl"}, {accept: runtime.ContentTypeJSON, userAgent: "kubectl"},
{accept: runtime.ContentTypeJSON, params: url.Values{"pretty": {"0"}}}, {accept: runtime.ContentTypeJSON, params: url.Values{"pretty": {"0"}}},
{pretty: true, accept: runtime.ContentTypeJSON, userAgent: "curl"}, {pretty: true, accept: runtime.ContentTypeJSON, userAgent: "curl"},
{pretty: true, accept: runtime.ContentTypeJSON, userAgent: "Mozilla/5.0"}, {pretty: true, accept: runtime.ContentTypeJSON, userAgent: "Mozilla/5.0"},
{pretty: true, accept: runtime.ContentTypeJSON, userAgent: "Wget"}, {pretty: true, accept: runtime.ContentTypeJSON, userAgent: "Wget"},
{pretty: true, accept: runtime.ContentTypeJSON + ";pretty=1"}, {pretty: true, accept: "application/json;pretty=1"},
{pretty: true, accept: runtime.ContentTypeJSON, params: url.Values{"pretty": {"1"}}}, {pretty: true, accept: runtime.ContentTypeJSON, params: url.Values{"pretty": {"1"}}},
{pretty: true, accept: runtime.ContentTypeJSON, params: url.Values{"pretty": {"true"}}}, {pretty: true, accept: runtime.ContentTypeJSON, params: url.Values{"pretty": {"true"}}},
} }
@ -1818,14 +1818,28 @@ func TestGetTable(t *testing.T) {
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
partial := meta.AsPartialObjectMetadata(m) var encodedV1Beta1Body []byte
partial.GetObjectKind().SetGroupVersionKind(metav1beta1.SchemeGroupVersion.WithKind("PartialObjectMetadata")) {
encodedBody, err := runtime.Encode(metainternalversion.Codecs.LegacyCodec(metav1beta1.SchemeGroupVersion), partial) partial := meta.AsPartialObjectMetadata(m)
if err != nil { partial.GetObjectKind().SetGroupVersionKind(metav1beta1.SchemeGroupVersion.WithKind("PartialObjectMetadata"))
t.Fatal(err) encodedBody, err := runtime.Encode(metainternalversion.Codecs.LegacyCodec(metav1beta1.SchemeGroupVersion), partial)
if err != nil {
t.Fatal(err)
}
// the codec includes a trailing newline that is not present during decode
encodedV1Beta1Body = bytes.TrimSpace(encodedBody)
}
var encodedV1Body []byte
{
partial := meta.AsPartialObjectMetadata(m)
partial.GetObjectKind().SetGroupVersionKind(metav1.SchemeGroupVersion.WithKind("PartialObjectMetadata"))
encodedBody, err := runtime.Encode(metainternalversion.Codecs.LegacyCodec(metav1.SchemeGroupVersion), partial)
if err != nil {
t.Fatal(err)
}
// the codec includes a trailing newline that is not present during decode
encodedV1Body = bytes.TrimSpace(encodedBody)
} }
// the codec includes a trailing newline that is not present during decode
encodedBody = bytes.TrimSpace(encodedBody)
metaDoc := metav1.ObjectMeta{}.SwaggerDoc() metaDoc := metav1.ObjectMeta{}.SwaggerDoc()
@ -1838,16 +1852,36 @@ func TestGetTable(t *testing.T) {
item bool item bool
}{ }{
{ {
accept: runtime.ContentTypeJSON + ";as=Table;v=v1;g=meta.k8s.io", accept: "application/json;as=Table;v=v1alpha1;g=meta.k8s.io",
statusCode: http.StatusNotAcceptable, statusCode: http.StatusNotAcceptable,
}, },
{ {
accept: runtime.ContentTypeProtobuf + ";as=Table;v=v1beta1;g=meta.k8s.io", accept: runtime.ContentTypeProtobuf + ";as=Table;v=v1beta1;g=meta.k8s.io",
statusCode: http.StatusNotAcceptable, statusCode: http.StatusNotAcceptable,
}, },
{
accept: runtime.ContentTypeProtobuf + ";as=Table;v=v1;g=meta.k8s.io",
statusCode: http.StatusNotAcceptable,
},
{ {
item: true, item: true,
accept: runtime.ContentTypeJSON + ";as=Table;v=v1beta1;g=meta.k8s.io", accept: "application/json;as=Table;v=v1;g=meta.k8s.io",
expected: &metav1.Table{
TypeMeta: metav1.TypeMeta{Kind: "Table", APIVersion: "meta.k8s.io/v1"},
ListMeta: metav1.ListMeta{ResourceVersion: "10", SelfLink: "/blah"},
ColumnDefinitions: []metav1.TableColumnDefinition{
{Name: "Name", Type: "string", Format: "name", Description: metaDoc["name"]},
{Name: "Created At", Type: "date", Description: metaDoc["creationTimestamp"]},
},
Rows: []metav1.TableRow{
{Cells: []interface{}{"foo1", now.Time.UTC().Format(time.RFC3339)}, Object: runtime.RawExtension{Raw: encodedV1Body}},
},
},
},
{
item: true,
accept: "application/json;as=Table;v=v1beta1;g=meta.k8s.io",
expected: &metav1beta1.Table{ expected: &metav1beta1.Table{
TypeMeta: metav1.TypeMeta{Kind: "Table", APIVersion: "meta.k8s.io/v1beta1"}, TypeMeta: metav1.TypeMeta{Kind: "Table", APIVersion: "meta.k8s.io/v1beta1"},
ListMeta: metav1.ListMeta{ResourceVersion: "10", SelfLink: "/blah"}, ListMeta: metav1.ListMeta{ResourceVersion: "10", SelfLink: "/blah"},
@ -1856,7 +1890,7 @@ func TestGetTable(t *testing.T) {
{Name: "Created At", Type: "date", Description: metaDoc["creationTimestamp"]}, {Name: "Created At", Type: "date", Description: metaDoc["creationTimestamp"]},
}, },
Rows: []metav1beta1.TableRow{ Rows: []metav1beta1.TableRow{
{Cells: []interface{}{"foo1", now.Time.UTC().Format(time.RFC3339)}, Object: runtime.RawExtension{Raw: encodedBody}}, {Cells: []interface{}{"foo1", now.Time.UTC().Format(time.RFC3339)}, Object: runtime.RawExtension{Raw: encodedV1Beta1Body}},
}, },
}, },
}, },
@ -1864,7 +1898,7 @@ func TestGetTable(t *testing.T) {
item: true, item: true,
accept: strings.Join([]string{ accept: strings.Join([]string{
runtime.ContentTypeProtobuf + ";as=Table;v=v1beta1;g=meta.k8s.io", runtime.ContentTypeProtobuf + ";as=Table;v=v1beta1;g=meta.k8s.io",
runtime.ContentTypeJSON + ";as=Table;v=v1beta1;g=meta.k8s.io", "application/json;as=Table;v=v1beta1;g=meta.k8s.io",
}, ","), }, ","),
expected: &metav1beta1.Table{ expected: &metav1beta1.Table{
TypeMeta: metav1.TypeMeta{Kind: "Table", APIVersion: "meta.k8s.io/v1beta1"}, TypeMeta: metav1.TypeMeta{Kind: "Table", APIVersion: "meta.k8s.io/v1beta1"},
@ -1874,13 +1908,13 @@ func TestGetTable(t *testing.T) {
{Name: "Created At", Type: "date", Description: metaDoc["creationTimestamp"]}, {Name: "Created At", Type: "date", Description: metaDoc["creationTimestamp"]},
}, },
Rows: []metav1beta1.TableRow{ Rows: []metav1beta1.TableRow{
{Cells: []interface{}{"foo1", now.Time.UTC().Format(time.RFC3339)}, Object: runtime.RawExtension{Raw: encodedBody}}, {Cells: []interface{}{"foo1", now.Time.UTC().Format(time.RFC3339)}, Object: runtime.RawExtension{Raw: encodedV1Beta1Body}},
}, },
}, },
}, },
{ {
item: true, item: true,
accept: runtime.ContentTypeJSON + ";as=Table;v=v1beta1;g=meta.k8s.io", accept: "application/json;as=Table;v=v1beta1;g=meta.k8s.io",
params: url.Values{"includeObject": []string{"Metadata"}}, params: url.Values{"includeObject": []string{"Metadata"}},
expected: &metav1beta1.Table{ expected: &metav1beta1.Table{
TypeMeta: metav1.TypeMeta{Kind: "Table", APIVersion: "meta.k8s.io/v1beta1"}, TypeMeta: metav1.TypeMeta{Kind: "Table", APIVersion: "meta.k8s.io/v1beta1"},
@ -1890,12 +1924,12 @@ func TestGetTable(t *testing.T) {
{Name: "Created At", Type: "date", Description: metaDoc["creationTimestamp"]}, {Name: "Created At", Type: "date", Description: metaDoc["creationTimestamp"]},
}, },
Rows: []metav1beta1.TableRow{ Rows: []metav1beta1.TableRow{
{Cells: []interface{}{"foo1", now.Time.UTC().Format(time.RFC3339)}, Object: runtime.RawExtension{Raw: encodedBody}}, {Cells: []interface{}{"foo1", now.Time.UTC().Format(time.RFC3339)}, Object: runtime.RawExtension{Raw: encodedV1Beta1Body}},
}, },
}, },
}, },
{ {
accept: runtime.ContentTypeJSON + ";as=Table;v=v1beta1;g=meta.k8s.io", accept: "application/json;as=Table;v=v1beta1;g=meta.k8s.io",
params: url.Values{"includeObject": []string{"Metadata"}}, params: url.Values{"includeObject": []string{"Metadata"}},
expected: &metav1beta1.Table{ expected: &metav1beta1.Table{
TypeMeta: metav1.TypeMeta{Kind: "Table", APIVersion: "meta.k8s.io/v1beta1"}, TypeMeta: metav1.TypeMeta{Kind: "Table", APIVersion: "meta.k8s.io/v1beta1"},
@ -1905,7 +1939,7 @@ func TestGetTable(t *testing.T) {
{Name: "Created At", Type: "date", Description: metaDoc["creationTimestamp"]}, {Name: "Created At", Type: "date", Description: metaDoc["creationTimestamp"]},
}, },
Rows: []metav1beta1.TableRow{ Rows: []metav1beta1.TableRow{
{Cells: []interface{}{"foo1", now.Time.UTC().Format(time.RFC3339)}, Object: runtime.RawExtension{Raw: encodedBody}}, {Cells: []interface{}{"foo1", now.Time.UTC().Format(time.RFC3339)}, Object: runtime.RawExtension{Raw: encodedV1Beta1Body}},
}, },
}, },
}, },
@ -1996,6 +2030,13 @@ func TestWatchTable(t *testing.T) {
// the codec includes a trailing newline that is not present during decode // the codec includes a trailing newline that is not present during decode
encodedBody = bytes.TrimSpace(encodedBody) encodedBody = bytes.TrimSpace(encodedBody)
encodedBodyV1, err := runtime.Encode(metainternalversion.Codecs.LegacyCodec(metav1.SchemeGroupVersion), partial)
if err != nil {
t.Fatal(err)
}
// the codec includes a trailing newline that is not present during decode
encodedBodyV1 = bytes.TrimSpace(encodedBodyV1)
metaDoc := metav1.ObjectMeta{}.SwaggerDoc() metaDoc := metav1.ObjectMeta{}.SwaggerDoc()
s := metainternalversion.Codecs.SupportedMediaTypes()[0].Serializer s := metainternalversion.Codecs.SupportedMediaTypes()[0].Serializer
@ -2011,11 +2052,11 @@ func TestWatchTable(t *testing.T) {
item bool item bool
}{ }{
{ {
accept: runtime.ContentTypeJSON + ";as=Table;v=v1;g=meta.k8s.io", accept: "application/json;as=Table;v=v1alpha1;g=meta.k8s.io",
statusCode: http.StatusNotAcceptable, statusCode: http.StatusNotAcceptable,
}, },
{ {
accept: runtime.ContentTypeJSON + ";as=Table;v=v1beta1;g=meta.k8s.io", accept: "application/json;as=Table;v=v1beta1;g=meta.k8s.io",
send: func(w *watch.FakeWatcher) { send: func(w *watch.FakeWatcher) {
w.Add(&obj) w.Add(&obj)
}, },
@ -2039,7 +2080,7 @@ func TestWatchTable(t *testing.T) {
}, },
}, },
{ {
accept: runtime.ContentTypeJSON + ";as=Table;v=v1beta1;g=meta.k8s.io", accept: "application/json;as=Table;v=v1beta1;g=meta.k8s.io",
send: func(w *watch.FakeWatcher) { send: func(w *watch.FakeWatcher) {
w.Add(&obj) w.Add(&obj)
w.Modify(&obj) w.Modify(&obj)
@ -2075,6 +2116,43 @@ func TestWatchTable(t *testing.T) {
}, },
}, },
}, },
{
accept: "application/json;as=Table;v=v1;g=meta.k8s.io",
send: func(w *watch.FakeWatcher) {
w.Add(&obj)
w.Modify(&obj)
},
expected: []*metav1.WatchEvent{
{
Type: "ADDED",
Object: runtime.RawExtension{
Raw: []byte(strings.TrimSpace(runtime.EncodeOrDie(s, &metav1.Table{
TypeMeta: metav1.TypeMeta{Kind: "Table", APIVersion: "meta.k8s.io/v1"},
ListMeta: metav1.ListMeta{ResourceVersion: "10", SelfLink: "/blah"},
ColumnDefinitions: []metav1beta1.TableColumnDefinition{
{Name: "Name", Type: "string", Format: "name", Description: metaDoc["name"]},
{Name: "Created At", Type: "date", Description: metaDoc["creationTimestamp"]},
},
Rows: []metav1.TableRow{
{Cells: []interface{}{"foo1", time.Unix(1, 0).UTC().Format(time.RFC3339)}, Object: runtime.RawExtension{Raw: encodedBodyV1}},
},
}))),
},
},
{
Type: "MODIFIED",
Object: runtime.RawExtension{
Raw: []byte(strings.TrimSpace(runtime.EncodeOrDie(s, &metav1.Table{
TypeMeta: metav1.TypeMeta{Kind: "Table", APIVersion: "meta.k8s.io/v1"},
ListMeta: metav1.ListMeta{ResourceVersion: "10", SelfLink: "/blah"},
Rows: []metav1.TableRow{
{Cells: []interface{}{"foo1", time.Unix(1, 0).UTC().Format(time.RFC3339)}, Object: runtime.RawExtension{Raw: encodedBodyV1}},
},
}))),
},
},
},
},
} }
for i, test := range tests { for i, test := range tests {
t.Run(fmt.Sprintf("%d", i), func(t *testing.T) { t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {
@ -2122,6 +2200,7 @@ func TestWatchTable(t *testing.T) {
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
defer resp.Body.Close()
if test.statusCode != 0 { if test.statusCode != 0 {
if resp.StatusCode != test.statusCode { if resp.StatusCode != test.statusCode {
t.Fatalf("%d: unexpected response: %#v", i, resp) t.Fatalf("%d: unexpected response: %#v", i, resp)
@ -2228,46 +2307,72 @@ func TestGetPartialObjectMetadata(t *testing.T) {
statusCode int statusCode int
}{ }{
{ {
accept: runtime.ContentTypeJSON + ";as=PartialObjectMetadata;v=v1;g=meta.k8s.io", accept: "application/json;as=PartialObjectMetadata;v=v1alpha1;g=meta.k8s.io",
statusCode: http.StatusNotAcceptable, statusCode: http.StatusNotAcceptable,
}, },
{ {
accept: runtime.ContentTypeJSON + ";as=PartialObjectMetadata;v=v1;g=meta.k8s.io, application/json", accept: "application/json;as=PartialObjectMetadata;v=v1alpha1;g=meta.k8s.io, application/json",
expectKind: schema.GroupVersionKind{Kind: "Simple", Group: testGroupVersion.Group, Version: testGroupVersion.Version}, expectKind: schema.GroupVersionKind{Kind: "Simple", Group: testGroupVersion.Group, Version: testGroupVersion.Version},
}, },
{ {
accept: runtime.ContentTypeJSON + ";as=PartialObjectMetadata;v=v1beta1;g=meta.k8s.io, application/json", accept: "application/json;as=PartialObjectMetadata;v=v1beta1;g=meta.k8s.io, application/json",
expectKind: schema.GroupVersionKind{Kind: "PartialObjectMetadata", Group: "meta.k8s.io", Version: "v1beta1"}, expectKind: schema.GroupVersionKind{Kind: "PartialObjectMetadata", Group: "meta.k8s.io", Version: "v1beta1"},
}, },
{ {
list: true, list: true,
accept: runtime.ContentTypeJSON + ";as=PartialObjectMetadata;v=v1beta1;g=meta.k8s.io", accept: "application/json;as=PartialObjectMetadata;v=v1beta1;g=meta.k8s.io",
statusCode: http.StatusNotAcceptable, statusCode: http.StatusNotAcceptable,
}, },
// verify preferred version overrides supported version
{
accept: "application/json;as=PartialObjectMetadata;v=v1beta1;g=meta.k8s.io, application/json;as=PartialObjectMetadata;v=v1;g=meta.k8s.io, application/json",
expectKind: schema.GroupVersionKind{Kind: "PartialObjectMetadata", Group: "meta.k8s.io", Version: "v1beta1"},
},
{
accept: "application/json;as=PartialObjectMetadata;v=v1;g=meta.k8s.io, application/json;as=PartialObjectMetadata;v=v1beta1;g=meta.k8s.io, application/json",
expectKind: schema.GroupVersionKind{Kind: "PartialObjectMetadata", Group: "meta.k8s.io", Version: "v1"},
},
{
accept: "application/json;as=PartialObjectMetadata;v=v1beta1;g=meta.k8s.io, application/json;as=PartialObjectMetadata;v=v1;g=meta.k8s.io",
expectKind: schema.GroupVersionKind{Kind: "PartialObjectMetadata", Group: "meta.k8s.io", Version: "v1beta1"},
},
{
accept: "application/json;as=PartialObjectMetadata;v=v1;g=meta.k8s.io, application/json;as=PartialObjectMetadata;v=v1beta1;g=meta.k8s.io",
expectKind: schema.GroupVersionKind{Kind: "PartialObjectMetadata", Group: "meta.k8s.io", Version: "v1"},
},
{ {
list: true, list: true,
accept: runtime.ContentTypeJSON + ";as=PartialObjectMetadata;v=v1;g=meta.k8s.io, application/json", accept: "application/json;as=PartialObjectMetadata;v=v1alpha1;g=meta.k8s.io, application/json",
expectKind: schema.GroupVersionKind{Kind: "SimpleList", Group: testGroupVersion.Group, Version: testGroupVersion.Version}, expectKind: schema.GroupVersionKind{Kind: "SimpleList", Group: testGroupVersion.Group, Version: testGroupVersion.Version},
}, },
{ {
list: true, list: true,
accept: runtime.ContentTypeJSON + ";as=PartialObjectMetadataList;v=v1beta1;g=meta.k8s.io, application/json", accept: "application/json;as=PartialObjectMetadataList;v=v1beta1;g=meta.k8s.io, application/json",
expectKind: schema.GroupVersionKind{Kind: "PartialObjectMetadataList", Group: "meta.k8s.io", Version: "v1beta1"}, expectKind: schema.GroupVersionKind{Kind: "PartialObjectMetadataList", Group: "meta.k8s.io", Version: "v1beta1"},
}, },
{ {
accept: runtime.ContentTypeJSON + ";as=PartialObjectMetadataList;v=v1beta1;g=meta.k8s.io", accept: "application/json;as=PartialObjectMetadataList;v=v1beta1;g=meta.k8s.io",
statusCode: http.StatusNotAcceptable, statusCode: http.StatusNotAcceptable,
}, },
{ {
accept: runtime.ContentTypeJSON + ";as=PartialObjectMetadata;v=v1beta1;g=meta.k8s.io", accept: "application/json;as=PartialObjectMetadata;v=v1beta1;g=meta.k8s.io",
expected: &metav1beta1.PartialObjectMetadata{ expected: &metav1beta1.PartialObjectMetadata{
ObjectMeta: metav1.ObjectMeta{Name: "foo1", Namespace: "ns1", CreationTimestamp: now, UID: types.UID("abcdef0123")}, ObjectMeta: metav1.ObjectMeta{Name: "foo1", Namespace: "ns1", CreationTimestamp: now, UID: types.UID("abcdef0123")},
}, },
expectKind: schema.GroupVersionKind{Kind: "PartialObjectMetadata", Group: "meta.k8s.io", Version: "v1beta1"}, expectKind: schema.GroupVersionKind{Kind: "PartialObjectMetadata", Group: "meta.k8s.io", Version: "v1beta1"},
}, },
{
accept: "application/json;as=PartialObjectMetadata;v=v1;g=meta.k8s.io",
expected: &metav1.PartialObjectMetadata{
ObjectMeta: metav1.ObjectMeta{Name: "foo1", Namespace: "ns1", CreationTimestamp: now, UID: types.UID("abcdef0123")},
},
expectKind: schema.GroupVersionKind{Kind: "PartialObjectMetadata", Group: "meta.k8s.io", Version: "v1"},
},
{ {
list: true, list: true,
accept: runtime.ContentTypeJSON + ";as=PartialObjectMetadataList;v=v1beta1;g=meta.k8s.io", accept: "application/json;as=PartialObjectMetadataList;v=v1beta1;g=meta.k8s.io",
expected: &metav1beta1.PartialObjectMetadataList{ expected: &metav1beta1.PartialObjectMetadataList{
ListMeta: metav1.ListMeta{ ListMeta: metav1.ListMeta{
ResourceVersion: "10", ResourceVersion: "10",

View File

@ -49,18 +49,18 @@ func transformObject(ctx context.Context, obj runtime.Object, opts interface{},
case target == nil: case target == nil:
return obj, nil return obj, nil
case target.Kind == "PartialObjectMetadata" && target.GroupVersion() == metav1beta1.SchemeGroupVersion: case target.Kind == "PartialObjectMetadata":
return asV1Beta1PartialObjectMetadata(obj) return asPartialObjectMetadata(obj, target.GroupVersion())
case target.Kind == "PartialObjectMetadataList" && target.GroupVersion() == metav1beta1.SchemeGroupVersion: case target.Kind == "PartialObjectMetadataList":
return asV1Beta1PartialObjectMetadataList(obj) return asPartialObjectMetadataList(obj, target.GroupVersion())
case target.Kind == "Table" && target.GroupVersion() == metav1beta1.SchemeGroupVersion: case target.Kind == "Table":
options, ok := opts.(*metav1beta1.TableOptions) options, ok := opts.(*metav1beta1.TableOptions)
if !ok { if !ok {
return nil, fmt.Errorf("unexpected TableOptions, got %T", opts) return nil, fmt.Errorf("unexpected TableOptions, got %T", opts)
} }
return asV1Beta1Table(ctx, obj, options, scope) return asTable(ctx, obj, options, scope, target.GroupVersion())
default: default:
accepted, _ := negotiation.MediaTypesForSerializer(metainternalversion.Codecs) accepted, _ := negotiation.MediaTypesForSerializer(metainternalversion.Codecs)
@ -74,7 +74,7 @@ func transformObject(ctx context.Context, obj runtime.Object, opts interface{},
func optionsForTransform(mediaType negotiation.MediaTypeOptions, req *http.Request) (interface{}, error) { func optionsForTransform(mediaType negotiation.MediaTypeOptions, req *http.Request) (interface{}, error) {
switch target := mediaType.Convert; { switch target := mediaType.Convert; {
case target == nil: case target == nil:
case target.Kind == "Table" && target.GroupVersion() == metav1beta1.SchemeGroupVersion: case target.Kind == "Table" && (target.GroupVersion() == metav1beta1.SchemeGroupVersion || target.GroupVersion() == metav1.SchemeGroupVersion):
opts := &metav1beta1.TableOptions{} opts := &metav1beta1.TableOptions{}
if err := metav1beta1.ParameterCodec.DecodeParameters(req.URL.Query(), metav1beta1.SchemeGroupVersion, opts); err != nil { if err := metav1beta1.ParameterCodec.DecodeParameters(req.URL.Query(), metav1beta1.SchemeGroupVersion, opts); err != nil {
return nil, err return nil, err
@ -95,9 +95,8 @@ func optionsForTransform(mediaType negotiation.MediaTypeOptions, req *http.Reque
func targetEncodingForTransform(scope *RequestScope, mediaType negotiation.MediaTypeOptions, req *http.Request) (schema.GroupVersionKind, runtime.NegotiatedSerializer, bool) { func targetEncodingForTransform(scope *RequestScope, mediaType negotiation.MediaTypeOptions, req *http.Request) (schema.GroupVersionKind, runtime.NegotiatedSerializer, bool) {
switch target := mediaType.Convert; { switch target := mediaType.Convert; {
case target == nil: case target == nil:
case target.Kind == "PartialObjectMetadata" && target.GroupVersion() == metav1beta1.SchemeGroupVersion, case (target.Kind == "PartialObjectMetadata" || target.Kind == "PartialObjectMetadataList" || target.Kind == "Table") &&
target.Kind == "PartialObjectMetadataList" && target.GroupVersion() == metav1beta1.SchemeGroupVersion, (target.GroupVersion() == metav1beta1.SchemeGroupVersion || target.GroupVersion() == metav1.SchemeGroupVersion):
target.Kind == "Table" && target.GroupVersion() == metav1beta1.SchemeGroupVersion:
return *target, metainternalversion.Codecs, true return *target, metainternalversion.Codecs, true
} }
return scope.Kind, scope.Serializer, false return scope.Kind, scope.Serializer, false
@ -142,31 +141,39 @@ func (e errNotAcceptable) Status() metav1.Status {
} }
} }
func asV1Beta1Table(ctx context.Context, result runtime.Object, opts *metav1beta1.TableOptions, scope *RequestScope) (runtime.Object, error) { func asTable(ctx context.Context, result runtime.Object, opts *metav1beta1.TableOptions, scope *RequestScope, groupVersion schema.GroupVersion) (runtime.Object, error) {
table, err := scope.TableConvertor.ConvertToTable(ctx, result, opts) switch groupVersion {
case metav1beta1.SchemeGroupVersion, metav1.SchemeGroupVersion:
default:
return nil, newNotAcceptableError(fmt.Sprintf("no Table exists in group version %s", groupVersion))
}
obj, err := scope.TableConvertor.ConvertToTable(ctx, result, opts)
if err != nil { if err != nil {
return nil, err return nil, err
} }
table := (*metav1.Table)(obj)
for i := range table.Rows { for i := range table.Rows {
item := &table.Rows[i] item := &table.Rows[i]
switch opts.IncludeObject { switch opts.IncludeObject {
case metav1beta1.IncludeObject: case metav1.IncludeObject:
item.Object.Object, err = scope.Convertor.ConvertToVersion(item.Object.Object, scope.Kind.GroupVersion()) item.Object.Object, err = scope.Convertor.ConvertToVersion(item.Object.Object, scope.Kind.GroupVersion())
if err != nil { if err != nil {
return nil, err return nil, err
} }
// TODO: rely on defaulting for the value here? // TODO: rely on defaulting for the value here?
case metav1beta1.IncludeMetadata, "": case metav1.IncludeMetadata, "":
m, err := meta.Accessor(item.Object.Object) m, err := meta.Accessor(item.Object.Object)
if err != nil { if err != nil {
return nil, err return nil, err
} }
// TODO: turn this into an internal type and do conversion in order to get object kind automatically set? // TODO: turn this into an internal type and do conversion in order to get object kind automatically set?
partial := meta.AsPartialObjectMetadata(m) partial := meta.AsPartialObjectMetadata(m)
partial.GetObjectKind().SetGroupVersionKind(metav1beta1.SchemeGroupVersion.WithKind("PartialObjectMetadata")) partial.GetObjectKind().SetGroupVersionKind(groupVersion.WithKind("PartialObjectMetadata"))
item.Object.Object = partial item.Object.Object = partial
case metav1beta1.IncludeNone: case metav1.IncludeNone:
item.Object.Object = nil item.Object.Object = nil
default: default:
err = errors.NewBadRequest(fmt.Sprintf("unrecognized includeObject value: %q", opts.IncludeObject)) err = errors.NewBadRequest(fmt.Sprintf("unrecognized includeObject value: %q", opts.IncludeObject))
@ -177,42 +184,74 @@ func asV1Beta1Table(ctx context.Context, result runtime.Object, opts *metav1beta
return table, nil return table, nil
} }
func asV1Beta1PartialObjectMetadata(result runtime.Object) (runtime.Object, error) { func asPartialObjectMetadata(result runtime.Object, groupVersion schema.GroupVersion) (runtime.Object, error) {
if meta.IsListType(result) { if meta.IsListType(result) {
err := newNotAcceptableError(fmt.Sprintf("you requested PartialObjectMetadata, but the requested object is a list (%T)", result)) err := newNotAcceptableError(fmt.Sprintf("you requested PartialObjectMetadata, but the requested object is a list (%T)", result))
return nil, err return nil, err
} }
switch groupVersion {
case metav1beta1.SchemeGroupVersion, metav1.SchemeGroupVersion:
default:
return nil, newNotAcceptableError(fmt.Sprintf("no PartialObjectMetadataList exists in group version %s", groupVersion))
}
m, err := meta.Accessor(result) m, err := meta.Accessor(result)
if err != nil { if err != nil {
return nil, err return nil, err
} }
partial := meta.AsPartialObjectMetadata(m) partial := meta.AsPartialObjectMetadata(m)
partial.GetObjectKind().SetGroupVersionKind(metav1beta1.SchemeGroupVersion.WithKind("PartialObjectMetadata")) partial.GetObjectKind().SetGroupVersionKind(groupVersion.WithKind("PartialObjectMetadata"))
return partial, nil return partial, nil
} }
func asV1Beta1PartialObjectMetadataList(result runtime.Object) (runtime.Object, error) { func asPartialObjectMetadataList(result runtime.Object, groupVersion schema.GroupVersion) (runtime.Object, error) {
if !meta.IsListType(result) { li, ok := result.(metav1.ListInterface)
if !ok {
return nil, newNotAcceptableError(fmt.Sprintf("you requested PartialObjectMetadataList, but the requested object is not a list (%T)", result)) return nil, newNotAcceptableError(fmt.Sprintf("you requested PartialObjectMetadataList, but the requested object is not a list (%T)", result))
} }
list := &metav1beta1.PartialObjectMetadataList{}
if li, ok := result.(metav1.ListInterface); ok { gvk := groupVersion.WithKind("PartialObjectMetadata")
switch {
case groupVersion == metav1beta1.SchemeGroupVersion:
list := &metav1beta1.PartialObjectMetadataList{}
err := meta.EachListItem(result, func(obj runtime.Object) error {
m, err := meta.Accessor(obj)
if err != nil {
return err
}
partial := meta.AsPartialObjectMetadata(m)
partial.GetObjectKind().SetGroupVersionKind(gvk)
list.Items = append(list.Items, partial)
return nil
})
if err != nil {
return nil, err
}
list.SelfLink = li.GetSelfLink() list.SelfLink = li.GetSelfLink()
list.ResourceVersion = li.GetResourceVersion() list.ResourceVersion = li.GetResourceVersion()
list.Continue = li.GetContinue() list.Continue = li.GetContinue()
} return list, nil
err := meta.EachListItem(result, func(obj runtime.Object) error {
m, err := meta.Accessor(obj) case groupVersion == metav1.SchemeGroupVersion:
list := &metav1.PartialObjectMetadataList{}
err := meta.EachListItem(result, func(obj runtime.Object) error {
m, err := meta.Accessor(obj)
if err != nil {
return err
}
partial := meta.AsPartialObjectMetadata(m)
partial.GetObjectKind().SetGroupVersionKind(gvk)
list.Items = append(list.Items, partial)
return nil
})
if err != nil { if err != nil {
return err return nil, err
} }
partial := meta.AsPartialObjectMetadata(m) list.SelfLink = li.GetSelfLink()
partial.GetObjectKind().SetGroupVersionKind(metav1beta1.SchemeGroupVersion.WithKind("PartialObjectMetadata")) list.ResourceVersion = li.GetResourceVersion()
list.Items = append(list.Items, partial) list.Continue = li.GetContinue()
return nil return list, nil
})
if err != nil { default:
return nil, err return nil, newNotAcceptableError(fmt.Sprintf("no PartialObjectMetadataList exists in group version %s", groupVersion))
} }
return list, nil
} }

View File

@ -78,7 +78,7 @@ func (scope *RequestScope) err(err error, w http.ResponseWriter, req *http.Reque
func (scope *RequestScope) AllowsConversion(gvk schema.GroupVersionKind, mimeType, mimeSubType string) bool { func (scope *RequestScope) AllowsConversion(gvk schema.GroupVersionKind, mimeType, mimeSubType string) bool {
// TODO: this is temporary, replace with an abstraction calculated at endpoint installation time // TODO: this is temporary, replace with an abstraction calculated at endpoint installation time
if gvk.GroupVersion() == metav1beta1.SchemeGroupVersion { if gvk.GroupVersion() == metav1beta1.SchemeGroupVersion || gvk.GroupVersion() == metav1.SchemeGroupVersion {
switch gvk.Kind { switch gvk.Kind {
case "Table": case "Table":
return scope.TableConvertor != nil && return scope.TableConvertor != nil &&