Compare commits

..

5 Commits

Author SHA1 Message Date
Kubernetes Publisher
3db8bfc885 Fix Godeps.json to point to kubernetes-1.11.4 tags 2018-10-26 15:02:54 +00:00
Kubernetes Publisher
56e7a63b5e Merge pull request #68842 from wenjiaswe/automated-cherry-pick-of-#68530-upstream-release-1.11
Automated cherry pick of #68530: Rewrite finalURLTemplate used only for metrics of dynamic client

Kubernetes-commit: 011647662b54bd2904ca6eeae59c0e9b5aca83d3
2018-10-10 04:57:04 +00:00
Kubernetes Publisher
02543cdbce Merge pull request #68552 from the-redback/automated-cherry-pick-of-#66078-upstream-release-1.11
Automated cherry pick of #66078: fix dynamic client listing bug

Kubernetes-commit: 9b517e008b9604951f68c859b1d26d5e1a896597
2018-10-04 11:02:59 +00:00
Wenjia Zhang
014054a6d3 Rewrite finalURLTemplate used only for metrics because of dynamic client change
Kubernetes-commit: 2f25fd01640f37d206112da48ff8c3faf4e17275
2018-09-14 11:31:21 -07:00
David Eads
f7a93c0e74 fix dynamic client listing bug
updated bazel

Kubernetes-commit: 1f1711d311188dccd8c5bd6984b01445d8a61f53
2018-07-11 13:05:54 -04:00
5 changed files with 372 additions and 108 deletions

160
Godeps/Godeps.json generated
View File

@@ -268,323 +268,323 @@
},
{
"ImportPath": "k8s.io/api/admissionregistration/v1alpha1",
"Rev": "4e7be11eab3ffcfc1876898b8272df53785a9504"
"Rev": "37c5ce6f2f592fbbd798bb86a8814d0918b3abe1"
},
{
"ImportPath": "k8s.io/api/admissionregistration/v1beta1",
"Rev": "4e7be11eab3ffcfc1876898b8272df53785a9504"
"Rev": "37c5ce6f2f592fbbd798bb86a8814d0918b3abe1"
},
{
"ImportPath": "k8s.io/api/apps/v1",
"Rev": "4e7be11eab3ffcfc1876898b8272df53785a9504"
"Rev": "37c5ce6f2f592fbbd798bb86a8814d0918b3abe1"
},
{
"ImportPath": "k8s.io/api/apps/v1beta1",
"Rev": "4e7be11eab3ffcfc1876898b8272df53785a9504"
"Rev": "37c5ce6f2f592fbbd798bb86a8814d0918b3abe1"
},
{
"ImportPath": "k8s.io/api/apps/v1beta2",
"Rev": "4e7be11eab3ffcfc1876898b8272df53785a9504"
"Rev": "37c5ce6f2f592fbbd798bb86a8814d0918b3abe1"
},
{
"ImportPath": "k8s.io/api/authentication/v1",
"Rev": "4e7be11eab3ffcfc1876898b8272df53785a9504"
"Rev": "37c5ce6f2f592fbbd798bb86a8814d0918b3abe1"
},
{
"ImportPath": "k8s.io/api/authentication/v1beta1",
"Rev": "4e7be11eab3ffcfc1876898b8272df53785a9504"
"Rev": "37c5ce6f2f592fbbd798bb86a8814d0918b3abe1"
},
{
"ImportPath": "k8s.io/api/authorization/v1",
"Rev": "4e7be11eab3ffcfc1876898b8272df53785a9504"
"Rev": "37c5ce6f2f592fbbd798bb86a8814d0918b3abe1"
},
{
"ImportPath": "k8s.io/api/authorization/v1beta1",
"Rev": "4e7be11eab3ffcfc1876898b8272df53785a9504"
"Rev": "37c5ce6f2f592fbbd798bb86a8814d0918b3abe1"
},
{
"ImportPath": "k8s.io/api/autoscaling/v1",
"Rev": "4e7be11eab3ffcfc1876898b8272df53785a9504"
"Rev": "37c5ce6f2f592fbbd798bb86a8814d0918b3abe1"
},
{
"ImportPath": "k8s.io/api/autoscaling/v2beta1",
"Rev": "4e7be11eab3ffcfc1876898b8272df53785a9504"
"Rev": "37c5ce6f2f592fbbd798bb86a8814d0918b3abe1"
},
{
"ImportPath": "k8s.io/api/batch/v1",
"Rev": "4e7be11eab3ffcfc1876898b8272df53785a9504"
"Rev": "37c5ce6f2f592fbbd798bb86a8814d0918b3abe1"
},
{
"ImportPath": "k8s.io/api/batch/v1beta1",
"Rev": "4e7be11eab3ffcfc1876898b8272df53785a9504"
"Rev": "37c5ce6f2f592fbbd798bb86a8814d0918b3abe1"
},
{
"ImportPath": "k8s.io/api/batch/v2alpha1",
"Rev": "4e7be11eab3ffcfc1876898b8272df53785a9504"
"Rev": "37c5ce6f2f592fbbd798bb86a8814d0918b3abe1"
},
{
"ImportPath": "k8s.io/api/certificates/v1beta1",
"Rev": "4e7be11eab3ffcfc1876898b8272df53785a9504"
"Rev": "37c5ce6f2f592fbbd798bb86a8814d0918b3abe1"
},
{
"ImportPath": "k8s.io/api/core/v1",
"Rev": "4e7be11eab3ffcfc1876898b8272df53785a9504"
"Rev": "37c5ce6f2f592fbbd798bb86a8814d0918b3abe1"
},
{
"ImportPath": "k8s.io/api/events/v1beta1",
"Rev": "4e7be11eab3ffcfc1876898b8272df53785a9504"
"Rev": "37c5ce6f2f592fbbd798bb86a8814d0918b3abe1"
},
{
"ImportPath": "k8s.io/api/extensions/v1beta1",
"Rev": "4e7be11eab3ffcfc1876898b8272df53785a9504"
"Rev": "37c5ce6f2f592fbbd798bb86a8814d0918b3abe1"
},
{
"ImportPath": "k8s.io/api/imagepolicy/v1alpha1",
"Rev": "4e7be11eab3ffcfc1876898b8272df53785a9504"
"Rev": "37c5ce6f2f592fbbd798bb86a8814d0918b3abe1"
},
{
"ImportPath": "k8s.io/api/networking/v1",
"Rev": "4e7be11eab3ffcfc1876898b8272df53785a9504"
"Rev": "37c5ce6f2f592fbbd798bb86a8814d0918b3abe1"
},
{
"ImportPath": "k8s.io/api/policy/v1beta1",
"Rev": "4e7be11eab3ffcfc1876898b8272df53785a9504"
"Rev": "37c5ce6f2f592fbbd798bb86a8814d0918b3abe1"
},
{
"ImportPath": "k8s.io/api/rbac/v1",
"Rev": "4e7be11eab3ffcfc1876898b8272df53785a9504"
"Rev": "37c5ce6f2f592fbbd798bb86a8814d0918b3abe1"
},
{
"ImportPath": "k8s.io/api/rbac/v1alpha1",
"Rev": "4e7be11eab3ffcfc1876898b8272df53785a9504"
"Rev": "37c5ce6f2f592fbbd798bb86a8814d0918b3abe1"
},
{
"ImportPath": "k8s.io/api/rbac/v1beta1",
"Rev": "4e7be11eab3ffcfc1876898b8272df53785a9504"
"Rev": "37c5ce6f2f592fbbd798bb86a8814d0918b3abe1"
},
{
"ImportPath": "k8s.io/api/scheduling/v1alpha1",
"Rev": "4e7be11eab3ffcfc1876898b8272df53785a9504"
"Rev": "37c5ce6f2f592fbbd798bb86a8814d0918b3abe1"
},
{
"ImportPath": "k8s.io/api/scheduling/v1beta1",
"Rev": "4e7be11eab3ffcfc1876898b8272df53785a9504"
"Rev": "37c5ce6f2f592fbbd798bb86a8814d0918b3abe1"
},
{
"ImportPath": "k8s.io/api/settings/v1alpha1",
"Rev": "4e7be11eab3ffcfc1876898b8272df53785a9504"
"Rev": "37c5ce6f2f592fbbd798bb86a8814d0918b3abe1"
},
{
"ImportPath": "k8s.io/api/storage/v1",
"Rev": "4e7be11eab3ffcfc1876898b8272df53785a9504"
"Rev": "37c5ce6f2f592fbbd798bb86a8814d0918b3abe1"
},
{
"ImportPath": "k8s.io/api/storage/v1alpha1",
"Rev": "4e7be11eab3ffcfc1876898b8272df53785a9504"
"Rev": "37c5ce6f2f592fbbd798bb86a8814d0918b3abe1"
},
{
"ImportPath": "k8s.io/api/storage/v1beta1",
"Rev": "4e7be11eab3ffcfc1876898b8272df53785a9504"
"Rev": "37c5ce6f2f592fbbd798bb86a8814d0918b3abe1"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/api/equality",
"Rev": "def12e63c512da17043b4f0293f52d1006603d9f"
"Rev": "8ee1a638bafa4ae9691077e690cb45dd54f45111"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/api/errors",
"Rev": "def12e63c512da17043b4f0293f52d1006603d9f"
"Rev": "8ee1a638bafa4ae9691077e690cb45dd54f45111"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/api/meta",
"Rev": "def12e63c512da17043b4f0293f52d1006603d9f"
"Rev": "8ee1a638bafa4ae9691077e690cb45dd54f45111"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/api/resource",
"Rev": "def12e63c512da17043b4f0293f52d1006603d9f"
"Rev": "8ee1a638bafa4ae9691077e690cb45dd54f45111"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/api/testing",
"Rev": "def12e63c512da17043b4f0293f52d1006603d9f"
"Rev": "8ee1a638bafa4ae9691077e690cb45dd54f45111"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/api/testing/fuzzer",
"Rev": "def12e63c512da17043b4f0293f52d1006603d9f"
"Rev": "8ee1a638bafa4ae9691077e690cb45dd54f45111"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/api/testing/roundtrip",
"Rev": "def12e63c512da17043b4f0293f52d1006603d9f"
"Rev": "8ee1a638bafa4ae9691077e690cb45dd54f45111"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/apis/meta/fuzzer",
"Rev": "def12e63c512da17043b4f0293f52d1006603d9f"
"Rev": "8ee1a638bafa4ae9691077e690cb45dd54f45111"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/apis/meta/internalversion",
"Rev": "def12e63c512da17043b4f0293f52d1006603d9f"
"Rev": "8ee1a638bafa4ae9691077e690cb45dd54f45111"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/apis/meta/v1",
"Rev": "def12e63c512da17043b4f0293f52d1006603d9f"
"Rev": "8ee1a638bafa4ae9691077e690cb45dd54f45111"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured",
"Rev": "def12e63c512da17043b4f0293f52d1006603d9f"
"Rev": "8ee1a638bafa4ae9691077e690cb45dd54f45111"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/apis/meta/v1beta1",
"Rev": "def12e63c512da17043b4f0293f52d1006603d9f"
"Rev": "8ee1a638bafa4ae9691077e690cb45dd54f45111"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/conversion",
"Rev": "def12e63c512da17043b4f0293f52d1006603d9f"
"Rev": "8ee1a638bafa4ae9691077e690cb45dd54f45111"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/conversion/queryparams",
"Rev": "def12e63c512da17043b4f0293f52d1006603d9f"
"Rev": "8ee1a638bafa4ae9691077e690cb45dd54f45111"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/fields",
"Rev": "def12e63c512da17043b4f0293f52d1006603d9f"
"Rev": "8ee1a638bafa4ae9691077e690cb45dd54f45111"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/labels",
"Rev": "def12e63c512da17043b4f0293f52d1006603d9f"
"Rev": "8ee1a638bafa4ae9691077e690cb45dd54f45111"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/runtime",
"Rev": "def12e63c512da17043b4f0293f52d1006603d9f"
"Rev": "8ee1a638bafa4ae9691077e690cb45dd54f45111"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/runtime/schema",
"Rev": "def12e63c512da17043b4f0293f52d1006603d9f"
"Rev": "8ee1a638bafa4ae9691077e690cb45dd54f45111"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/runtime/serializer",
"Rev": "def12e63c512da17043b4f0293f52d1006603d9f"
"Rev": "8ee1a638bafa4ae9691077e690cb45dd54f45111"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/runtime/serializer/json",
"Rev": "def12e63c512da17043b4f0293f52d1006603d9f"
"Rev": "8ee1a638bafa4ae9691077e690cb45dd54f45111"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/runtime/serializer/protobuf",
"Rev": "def12e63c512da17043b4f0293f52d1006603d9f"
"Rev": "8ee1a638bafa4ae9691077e690cb45dd54f45111"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/runtime/serializer/recognizer",
"Rev": "def12e63c512da17043b4f0293f52d1006603d9f"
"Rev": "8ee1a638bafa4ae9691077e690cb45dd54f45111"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/runtime/serializer/streaming",
"Rev": "def12e63c512da17043b4f0293f52d1006603d9f"
"Rev": "8ee1a638bafa4ae9691077e690cb45dd54f45111"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/runtime/serializer/versioning",
"Rev": "def12e63c512da17043b4f0293f52d1006603d9f"
"Rev": "8ee1a638bafa4ae9691077e690cb45dd54f45111"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/selection",
"Rev": "def12e63c512da17043b4f0293f52d1006603d9f"
"Rev": "8ee1a638bafa4ae9691077e690cb45dd54f45111"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/types",
"Rev": "def12e63c512da17043b4f0293f52d1006603d9f"
"Rev": "8ee1a638bafa4ae9691077e690cb45dd54f45111"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/cache",
"Rev": "def12e63c512da17043b4f0293f52d1006603d9f"
"Rev": "8ee1a638bafa4ae9691077e690cb45dd54f45111"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/clock",
"Rev": "def12e63c512da17043b4f0293f52d1006603d9f"
"Rev": "8ee1a638bafa4ae9691077e690cb45dd54f45111"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/diff",
"Rev": "def12e63c512da17043b4f0293f52d1006603d9f"
"Rev": "8ee1a638bafa4ae9691077e690cb45dd54f45111"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/errors",
"Rev": "def12e63c512da17043b4f0293f52d1006603d9f"
"Rev": "8ee1a638bafa4ae9691077e690cb45dd54f45111"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/framer",
"Rev": "def12e63c512da17043b4f0293f52d1006603d9f"
"Rev": "8ee1a638bafa4ae9691077e690cb45dd54f45111"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/httpstream",
"Rev": "def12e63c512da17043b4f0293f52d1006603d9f"
"Rev": "8ee1a638bafa4ae9691077e690cb45dd54f45111"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/httpstream/spdy",
"Rev": "def12e63c512da17043b4f0293f52d1006603d9f"
"Rev": "8ee1a638bafa4ae9691077e690cb45dd54f45111"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/intstr",
"Rev": "def12e63c512da17043b4f0293f52d1006603d9f"
"Rev": "8ee1a638bafa4ae9691077e690cb45dd54f45111"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/json",
"Rev": "def12e63c512da17043b4f0293f52d1006603d9f"
"Rev": "8ee1a638bafa4ae9691077e690cb45dd54f45111"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/mergepatch",
"Rev": "def12e63c512da17043b4f0293f52d1006603d9f"
"Rev": "8ee1a638bafa4ae9691077e690cb45dd54f45111"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/net",
"Rev": "def12e63c512da17043b4f0293f52d1006603d9f"
"Rev": "8ee1a638bafa4ae9691077e690cb45dd54f45111"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/remotecommand",
"Rev": "def12e63c512da17043b4f0293f52d1006603d9f"
"Rev": "8ee1a638bafa4ae9691077e690cb45dd54f45111"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/runtime",
"Rev": "def12e63c512da17043b4f0293f52d1006603d9f"
"Rev": "8ee1a638bafa4ae9691077e690cb45dd54f45111"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/sets",
"Rev": "def12e63c512da17043b4f0293f52d1006603d9f"
"Rev": "8ee1a638bafa4ae9691077e690cb45dd54f45111"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/strategicpatch",
"Rev": "def12e63c512da17043b4f0293f52d1006603d9f"
"Rev": "8ee1a638bafa4ae9691077e690cb45dd54f45111"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/validation",
"Rev": "def12e63c512da17043b4f0293f52d1006603d9f"
"Rev": "8ee1a638bafa4ae9691077e690cb45dd54f45111"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/validation/field",
"Rev": "def12e63c512da17043b4f0293f52d1006603d9f"
"Rev": "8ee1a638bafa4ae9691077e690cb45dd54f45111"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/wait",
"Rev": "def12e63c512da17043b4f0293f52d1006603d9f"
"Rev": "8ee1a638bafa4ae9691077e690cb45dd54f45111"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/util/yaml",
"Rev": "def12e63c512da17043b4f0293f52d1006603d9f"
"Rev": "8ee1a638bafa4ae9691077e690cb45dd54f45111"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/version",
"Rev": "def12e63c512da17043b4f0293f52d1006603d9f"
"Rev": "8ee1a638bafa4ae9691077e690cb45dd54f45111"
},
{
"ImportPath": "k8s.io/apimachinery/pkg/watch",
"Rev": "def12e63c512da17043b4f0293f52d1006603d9f"
"Rev": "8ee1a638bafa4ae9691077e690cb45dd54f45111"
},
{
"ImportPath": "k8s.io/apimachinery/third_party/forked/golang/json",
"Rev": "def12e63c512da17043b4f0293f52d1006603d9f"
"Rev": "8ee1a638bafa4ae9691077e690cb45dd54f45111"
},
{
"ImportPath": "k8s.io/apimachinery/third_party/forked/golang/netutil",
"Rev": "def12e63c512da17043b4f0293f52d1006603d9f"
"Rev": "8ee1a638bafa4ae9691077e690cb45dd54f45111"
},
{
"ImportPath": "k8s.io/apimachinery/third_party/forked/golang/reflect",
"Rev": "def12e63c512da17043b4f0293f52d1006603d9f"
"Rev": "8ee1a638bafa4ae9691077e690cb45dd54f45111"
},
{
"ImportPath": "k8s.io/kube-openapi/pkg/util/proto",

View File

@@ -33,6 +33,10 @@ import (
)
func NewSimpleDynamicClient(scheme *runtime.Scheme, objects ...runtime.Object) *FakeDynamicClient {
// In order to use List with this client, you have to have the v1.List registered in your scheme. Neat thing though
// it does NOT have to be the *same* list
scheme.AddKnownTypeWithName(schema.GroupVersionKind{Group: "fake-dynamic-client-group", Version: "v1", Kind: "List"}, &unstructured.UnstructuredList{})
codecs := serializer.NewCodecFactory(scheme)
o := testing.NewObjectTracker(scheme, codecs.UniversalDecoder())
for _, obj := range objects {
@@ -272,11 +276,11 @@ func (c *dynamicResourceClient) List(opts metav1.ListOptions) (*unstructured.Uns
switch {
case len(c.namespace) == 0:
obj, err = c.client.Fake.
Invokes(testing.NewRootListAction(c.resource, schema.GroupVersionKind{Version: "v1", Kind: "List"}, opts), &metav1.Status{Status: "dynamic list fail"})
Invokes(testing.NewRootListAction(c.resource, schema.GroupVersionKind{Group: "fake-dynamic-client-group", Version: "v1", Kind: "" /*List is appended by the tracker automatically*/}, opts), &metav1.Status{Status: "dynamic list fail"})
case len(c.namespace) > 0:
obj, err = c.client.Fake.
Invokes(testing.NewListAction(c.resource, schema.GroupVersionKind{Version: "v1", Kind: "List"}, c.namespace, opts), &metav1.Status{Status: "dynamic list fail"})
Invokes(testing.NewListAction(c.resource, schema.GroupVersionKind{Group: "fake-dynamic-client-group", Version: "v1", Kind: "" /*List is appended by the tracker automatically*/}, c.namespace, opts), &metav1.Status{Status: "dynamic list fail"})
}
@@ -299,13 +303,14 @@ func (c *dynamicResourceClient) List(opts metav1.ListOptions) (*unstructured.Uns
}
list := &unstructured.UnstructuredList{}
for _, item := range entireList.Items {
for i := range entireList.Items {
item := &entireList.Items[i]
metadata, err := meta.Accessor(item)
if err != nil {
return nil, err
}
if label.Matches(labels.Set(metadata.GetLabels())) {
list.Items = append(list.Items, item)
list.Items = append(list.Items, *item)
}
}
return list, nil

View File

@@ -0,0 +1,66 @@
/*
Copyright 2018 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package fake
import (
"testing"
"k8s.io/apimachinery/pkg/api/equality"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/util/diff"
)
func newUnstructured(apiVersion, kind, namespace, name string) *unstructured.Unstructured {
return &unstructured.Unstructured{
Object: map[string]interface{}{
"apiVersion": apiVersion,
"kind": kind,
"metadata": map[string]interface{}{
"namespace": namespace,
"name": name,
},
},
}
}
func TestList(t *testing.T) {
scheme := runtime.NewScheme()
client := NewSimpleDynamicClient(scheme,
newUnstructured("group/version", "TheKind", "ns-foo", "name-foo"),
newUnstructured("group2/version", "TheKind", "ns-foo", "name2-foo"),
newUnstructured("group/version", "TheKind", "ns-foo", "name-bar"),
newUnstructured("group/version", "TheKind", "ns-foo", "name-baz"),
newUnstructured("group2/version", "TheKind", "ns-foo", "name2-baz"),
)
listFirst, err := client.Resource(schema.GroupVersionResource{Group: "group", Version: "version", Resource: "thekinds"}).List(metav1.ListOptions{})
if err != nil {
t.Fatal(err)
}
expected := []unstructured.Unstructured{
*newUnstructured("group/version", "TheKind", "ns-foo", "name-foo"),
*newUnstructured("group/version", "TheKind", "ns-foo", "name-bar"),
*newUnstructured("group/version", "TheKind", "ns-foo", "name-baz"),
}
if !equality.Semantic.DeepEqual(listFirst.Items, expected) {
t.Fatal(diff.ObjectGoPrintDiff(expected, listFirst.Items))
}
}

View File

@@ -455,17 +455,9 @@ func (r *Request) URL() *url.URL {
// finalURLTemplate is similar to URL(), but will make all specific parameter values equal
// - instead of name or namespace, "{name}" and "{namespace}" will be used, and all query
// parameters will be reset. This creates a copy of the request so as not to change the
// underlying object. This means some useful request info (like the types of field
// selectors in use) will be lost.
// TODO: preserve field selector keys
// parameters will be reset. This creates a copy of the url so as not to change the
// underlying object.
func (r Request) finalURLTemplate() url.URL {
if len(r.resourceName) != 0 {
r.resourceName = "{name}"
}
if r.namespaceSet && len(r.namespace) != 0 {
r.namespace = "{namespace}"
}
newParams := url.Values{}
v := []string{"{value}"}
for k := range r.params {
@@ -473,6 +465,59 @@ func (r Request) finalURLTemplate() url.URL {
}
r.params = newParams
url := r.URL()
segments := strings.Split(r.URL().Path, "/")
groupIndex := 0
index := 0
if r.URL() != nil && r.baseURL != nil && strings.Contains(r.URL().Path, r.baseURL.Path) {
groupIndex += len(strings.Split(r.baseURL.Path, "/"))
}
if groupIndex >= len(segments) {
return *url
}
const CoreGroupPrefix = "api"
const NamedGroupPrefix = "apis"
isCoreGroup := segments[groupIndex] == CoreGroupPrefix
isNamedGroup := segments[groupIndex] == NamedGroupPrefix
if isCoreGroup {
// checking the case of core group with /api/v1/... format
index = groupIndex + 2
} else if isNamedGroup {
// checking the case of named group with /apis/apps/v1/... format
index = groupIndex + 3
} else {
// this should not happen that the only two possibilities are /api... and /apis..., just want to put an
// outlet here in case more API groups are added in future if ever possible:
// https://kubernetes.io/docs/concepts/overview/kubernetes-api/#api-groups
// if a wrong API groups name is encountered, return the {prefix} for url.Path
url.Path = "/{prefix}"
url.RawQuery = ""
return *url
}
//switch segLength := len(segments) - index; segLength {
switch {
// case len(segments) - index == 1:
// resource (with no name) do nothing
case len(segments)-index == 2:
// /$RESOURCE/$NAME: replace $NAME with {name}
segments[index+1] = "{name}"
case len(segments)-index == 3:
if segments[index+2] == "finalize" || segments[index+2] == "status" {
// /$RESOURCE/$NAME/$SUBRESOURCE: replace $NAME with {name}
segments[index+1] = "{name}"
} else {
// /namespace/$NAMESPACE/$RESOURCE: replace $NAMESPACE with {namespace}
segments[index+1] = "{namespace}"
}
case len(segments)-index >= 4:
segments[index+1] = "{namespace}"
// /namespace/$NAMESPACE/$RESOURCE/$NAME: replace $NAMESPACE with {namespace}, $NAME with {name}
if segments[index+3] != "finalize" && segments[index+3] != "status" {
// /$RESOURCE/$NAME/$SUBRESOURCE: replace $NAME with {name}
segments[index+3] = "{name}"
}
}
url.Path = path.Join(segments...)
return *url
}

View File

@@ -340,21 +340,169 @@ func TestResultIntoWithNoBodyReturnsErr(t *testing.T) {
}
func TestURLTemplate(t *testing.T) {
uri, _ := url.Parse("http://localhost")
r := NewRequest(nil, "POST", uri, "", ContentConfig{GroupVersion: &schema.GroupVersion{Group: "test"}}, Serializers{}, nil, nil, 0)
r.Prefix("pre1").Resource("r1").Namespace("ns").Name("nm").Param("p0", "v0")
full := r.URL()
if full.String() != "http://localhost/pre1/namespaces/ns/r1/nm?p0=v0" {
t.Errorf("unexpected initial URL: %s", full)
uri, _ := url.Parse("http://localhost/some/base/url/path")
testCases := []struct {
Request *Request
ExpectedFullURL string
ExpectedFinalURL string
}{
{
// non dynamic client
Request: NewRequest(nil, "POST", uri, "", ContentConfig{GroupVersion: &schema.GroupVersion{Group: "test"}}, Serializers{}, nil, nil, 0).
Prefix("api", "v1").Resource("r1").Namespace("ns").Name("nm").Param("p0", "v0"),
ExpectedFullURL: "http://localhost/some/base/url/path/api/v1/namespaces/ns/r1/nm?p0=v0",
ExpectedFinalURL: "http://localhost/some/base/url/path/api/v1/namespaces/%7Bnamespace%7D/r1/%7Bname%7D?p0=%7Bvalue%7D",
},
{
// non dynamic client with wrong api group
Request: NewRequest(nil, "POST", uri, "", ContentConfig{GroupVersion: &schema.GroupVersion{Group: "test"}}, Serializers{}, nil, nil, 0).
Prefix("pre1", "v1").Resource("r1").Namespace("ns").Name("nm").Param("p0", "v0"),
ExpectedFullURL: "http://localhost/some/base/url/path/pre1/v1/namespaces/ns/r1/nm?p0=v0",
ExpectedFinalURL: "http://localhost/%7Bprefix%7D",
},
{
// dynamic client with core group + namespace + resourceResource (with name)
// /api/$RESOURCEVERSION/namespaces/$NAMESPACE/$RESOURCE/%NAME
Request: NewRequest(nil, "DELETE", uri, "", ContentConfig{GroupVersion: &schema.GroupVersion{Group: "test"}}, Serializers{}, nil, nil, 0).
Prefix("/api/v1/namespaces/ns/r1/name1"),
ExpectedFullURL: "http://localhost/some/base/url/path/api/v1/namespaces/ns/r1/name1",
ExpectedFinalURL: "http://localhost/some/base/url/path/api/v1/namespaces/%7Bnamespace%7D/r1/%7Bname%7D",
},
{
// dynamic client with named group + namespace + resourceResource (with name)
// /apis/$NAMEDGROUPNAME/$RESOURCEVERSION/namespaces/$NAMESPACE/$RESOURCE/%NAME
Request: NewRequest(nil, "DELETE", uri, "", ContentConfig{GroupVersion: &schema.GroupVersion{Group: "test"}}, Serializers{}, nil, nil, 0).
Prefix("/apis/g1/v1/namespaces/ns/r1/name1"),
ExpectedFullURL: "http://localhost/some/base/url/path/apis/g1/v1/namespaces/ns/r1/name1",
ExpectedFinalURL: "http://localhost/some/base/url/path/apis/g1/v1/namespaces/%7Bnamespace%7D/r1/%7Bname%7D",
},
{
// dynamic client with core group + namespace + resourceResource (with NO name)
// /api/$RESOURCEVERSION/namespaces/$NAMESPACE/$RESOURCE
Request: NewRequest(nil, "DELETE", uri, "", ContentConfig{GroupVersion: &schema.GroupVersion{Group: "test"}}, Serializers{}, nil, nil, 0).
Prefix("/api/v1/namespaces/ns/r1"),
ExpectedFullURL: "http://localhost/some/base/url/path/api/v1/namespaces/ns/r1",
ExpectedFinalURL: "http://localhost/some/base/url/path/api/v1/namespaces/%7Bnamespace%7D/r1",
},
{
// dynamic client with named group + namespace + resourceResource (with NO name)
// /apis/$NAMEDGROUPNAME/$RESOURCEVERSION/namespaces/$NAMESPACE/$RESOURCE
Request: NewRequest(nil, "DELETE", uri, "", ContentConfig{GroupVersion: &schema.GroupVersion{Group: "test"}}, Serializers{}, nil, nil, 0).
Prefix("/apis/g1/v1/namespaces/ns/r1"),
ExpectedFullURL: "http://localhost/some/base/url/path/apis/g1/v1/namespaces/ns/r1",
ExpectedFinalURL: "http://localhost/some/base/url/path/apis/g1/v1/namespaces/%7Bnamespace%7D/r1",
},
{
// dynamic client with core group + resourceResource (with name)
// /api/$RESOURCEVERSION/$RESOURCE/%NAME
Request: NewRequest(nil, "DELETE", uri, "", ContentConfig{GroupVersion: &schema.GroupVersion{Group: "test"}}, Serializers{}, nil, nil, 0).
Prefix("/api/v1/r1/name1"),
ExpectedFullURL: "http://localhost/some/base/url/path/api/v1/r1/name1",
ExpectedFinalURL: "http://localhost/some/base/url/path/api/v1/r1/%7Bname%7D",
},
{
// dynamic client with named group + resourceResource (with name)
// /apis/$NAMEDGROUPNAME/$RESOURCEVERSION/$RESOURCE/%NAME
Request: NewRequest(nil, "DELETE", uri, "", ContentConfig{GroupVersion: &schema.GroupVersion{Group: "test"}}, Serializers{}, nil, nil, 0).
Prefix("/apis/g1/v1/r1/name1"),
ExpectedFullURL: "http://localhost/some/base/url/path/apis/g1/v1/r1/name1",
ExpectedFinalURL: "http://localhost/some/base/url/path/apis/g1/v1/r1/%7Bname%7D",
},
{
// dynamic client with named group + namespace + resourceResource (with name) + subresource
// /apis/$NAMEDGROUPNAME/$RESOURCEVERSION/namespaces/$NAMESPACE/$RESOURCE/%NAME/$SUBRESOURCE
Request: NewRequest(nil, "DELETE", uri, "", ContentConfig{GroupVersion: &schema.GroupVersion{Group: "test"}}, Serializers{}, nil, nil, 0).
Prefix("/apis/namespaces/namespaces/namespaces/namespaces/namespaces/namespaces/finalize"),
ExpectedFullURL: "http://localhost/some/base/url/path/apis/namespaces/namespaces/namespaces/namespaces/namespaces/namespaces/finalize",
ExpectedFinalURL: "http://localhost/some/base/url/path/apis/namespaces/namespaces/namespaces/%7Bnamespace%7D/namespaces/%7Bname%7D/finalize",
},
{
// dynamic client with named group + namespace + resourceResource (with name)
// /apis/$NAMEDGROUPNAME/$RESOURCEVERSION/namespaces/$NAMESPACE/$RESOURCE/%NAME
Request: NewRequest(nil, "DELETE", uri, "", ContentConfig{GroupVersion: &schema.GroupVersion{Group: "test"}}, Serializers{}, nil, nil, 0).
Prefix("/apis/namespaces/namespaces/namespaces/namespaces/namespaces/namespaces"),
ExpectedFullURL: "http://localhost/some/base/url/path/apis/namespaces/namespaces/namespaces/namespaces/namespaces/namespaces",
ExpectedFinalURL: "http://localhost/some/base/url/path/apis/namespaces/namespaces/namespaces/%7Bnamespace%7D/namespaces/%7Bname%7D",
},
{
// dynamic client with named group + namespace + resourceResource (with NO name) + subresource
// /apis/$NAMEDGROUPNAME/$RESOURCEVERSION/namespaces/$NAMESPACE/$RESOURCE/%SUBRESOURCE
Request: NewRequest(nil, "DELETE", uri, "", ContentConfig{GroupVersion: &schema.GroupVersion{Group: "test"}}, Serializers{}, nil, nil, 0).
Prefix("/apis/namespaces/namespaces/namespaces/namespaces/namespaces/finalize"),
ExpectedFullURL: "http://localhost/some/base/url/path/apis/namespaces/namespaces/namespaces/namespaces/namespaces/finalize",
ExpectedFinalURL: "http://localhost/some/base/url/path/apis/namespaces/namespaces/namespaces/%7Bnamespace%7D/namespaces/finalize",
},
{
// dynamic client with named group + namespace + resourceResource (with NO name) + subresource
// /apis/$NAMEDGROUPNAME/$RESOURCEVERSION/namespaces/$NAMESPACE/$RESOURCE/%SUBRESOURCE
Request: NewRequest(nil, "DELETE", uri, "", ContentConfig{GroupVersion: &schema.GroupVersion{Group: "test"}}, Serializers{}, nil, nil, 0).
Prefix("/apis/namespaces/namespaces/namespaces/namespaces/namespaces/status"),
ExpectedFullURL: "http://localhost/some/base/url/path/apis/namespaces/namespaces/namespaces/namespaces/namespaces/status",
ExpectedFinalURL: "http://localhost/some/base/url/path/apis/namespaces/namespaces/namespaces/%7Bnamespace%7D/namespaces/status",
},
{
// dynamic client with named group + namespace + resourceResource (with no name)
// /apis/$NAMEDGROUPNAME/$RESOURCEVERSION/namespaces/$NAMESPACE/$RESOURCE/%NAME
Request: NewRequest(nil, "DELETE", uri, "", ContentConfig{GroupVersion: &schema.GroupVersion{Group: "test"}}, Serializers{}, nil, nil, 0).
Prefix("/apis/namespaces/namespaces/namespaces/namespaces/namespaces"),
ExpectedFullURL: "http://localhost/some/base/url/path/apis/namespaces/namespaces/namespaces/namespaces/namespaces",
ExpectedFinalURL: "http://localhost/some/base/url/path/apis/namespaces/namespaces/namespaces/%7Bnamespace%7D/namespaces",
},
{
// dynamic client with named group + resourceResource (with name) + subresource
// /apis/$NAMEDGROUPNAME/$RESOURCEVERSION/namespaces/$NAMESPACE/$RESOURCE/%NAME
Request: NewRequest(nil, "DELETE", uri, "", ContentConfig{GroupVersion: &schema.GroupVersion{Group: "test"}}, Serializers{}, nil, nil, 0).
Prefix("/apis/namespaces/namespaces/namespaces/namespaces/finalize"),
ExpectedFullURL: "http://localhost/some/base/url/path/apis/namespaces/namespaces/namespaces/namespaces/finalize",
ExpectedFinalURL: "http://localhost/some/base/url/path/apis/namespaces/namespaces/namespaces/%7Bname%7D/finalize",
},
{
// dynamic client with named group + resourceResource (with name) + subresource
// /apis/$NAMEDGROUPNAME/$RESOURCEVERSION/namespaces/$NAMESPACE/$RESOURCE/%NAME
Request: NewRequest(nil, "DELETE", uri, "", ContentConfig{GroupVersion: &schema.GroupVersion{Group: "test"}}, Serializers{}, nil, nil, 0).
Prefix("/apis/namespaces/namespaces/namespaces/namespaces/status"),
ExpectedFullURL: "http://localhost/some/base/url/path/apis/namespaces/namespaces/namespaces/namespaces/status",
ExpectedFinalURL: "http://localhost/some/base/url/path/apis/namespaces/namespaces/namespaces/%7Bname%7D/status",
},
{
// dynamic client with named group + resourceResource (with name)
// /apis/$NAMEDGROUPNAME/$RESOURCEVERSION/$RESOURCE/%NAME
Request: NewRequest(nil, "DELETE", uri, "", ContentConfig{GroupVersion: &schema.GroupVersion{Group: "test"}}, Serializers{}, nil, nil, 0).
Prefix("/apis/namespaces/namespaces/namespaces/namespaces"),
ExpectedFullURL: "http://localhost/some/base/url/path/apis/namespaces/namespaces/namespaces/namespaces",
ExpectedFinalURL: "http://localhost/some/base/url/path/apis/namespaces/namespaces/namespaces/%7Bname%7D",
},
{
// dynamic client with named group + resourceResource (with no name)
// /apis/$NAMEDGROUPNAME/$RESOURCEVERSION/$RESOURCE/%NAME
Request: NewRequest(nil, "DELETE", uri, "", ContentConfig{GroupVersion: &schema.GroupVersion{Group: "test"}}, Serializers{}, nil, nil, 0).
Prefix("/apis/namespaces/namespaces/namespaces"),
ExpectedFullURL: "http://localhost/some/base/url/path/apis/namespaces/namespaces/namespaces",
ExpectedFinalURL: "http://localhost/some/base/url/path/apis/namespaces/namespaces/namespaces",
},
{
// dynamic client with wrong api group + namespace + resourceResource (with name) + subresource
// /apis/$NAMEDGROUPNAME/$RESOURCEVERSION/namespaces/$NAMESPACE/$RESOURCE/%NAME/$SUBRESOURCE
Request: NewRequest(nil, "DELETE", uri, "", ContentConfig{GroupVersion: &schema.GroupVersion{Group: "test"}}, Serializers{}, nil, nil, 0).
Prefix("/pre1/namespaces/namespaces/namespaces/namespaces/namespaces/namespaces/finalize"),
ExpectedFullURL: "http://localhost/some/base/url/path/pre1/namespaces/namespaces/namespaces/namespaces/namespaces/namespaces/finalize",
ExpectedFinalURL: "http://localhost/%7Bprefix%7D",
},
}
actualURL := r.finalURLTemplate()
actual := actualURL.String()
expected := "http://localhost/pre1/namespaces/%7Bnamespace%7D/r1/%7Bname%7D?p0=%7Bvalue%7D"
if actual != expected {
t.Errorf("unexpected URL template: %s %s", actual, expected)
}
if r.URL().String() != full.String() {
t.Errorf("creating URL template changed request: %s -> %s", full.String(), r.URL().String())
for i, testCase := range testCases {
r := testCase.Request
full := r.URL()
if full.String() != testCase.ExpectedFullURL {
t.Errorf("%d: unexpected initial URL: %s %s", i, full, testCase.ExpectedFullURL)
}
actualURL := r.finalURLTemplate()
actual := actualURL.String()
if actual != testCase.ExpectedFinalURL {
t.Errorf("%d: unexpected URL template: %s %s", i, actual, testCase.ExpectedFinalURL)
}
if r.URL().String() != full.String() {
t.Errorf("%d, creating URL template changed request: %s -> %s", i, full.String(), r.URL().String())
}
}
}