diff --git a/pkg/api/ref.go b/pkg/api/ref.go index 2af43ebb3d1..67330f90057 100644 --- a/pkg/api/ref.go +++ b/pkg/api/ref.go @@ -19,7 +19,8 @@ package api import ( "errors" "fmt" - "regexp" + "net/url" + "strings" "github.com/GoogleCloudPlatform/kubernetes/pkg/api/meta" "github.com/GoogleCloudPlatform/kubernetes/pkg/runtime" @@ -31,8 +32,6 @@ var ( ErrNoSelfLink = errors.New("selfLink was empty, can't make reference") ) -var versionFromSelfLink = regexp.MustCompile("/api/([^/]*)/") - // ForTesting_ReferencesAllowBlankSelfLinks can be set to true in tests to avoid // "ErrNoSelfLink" errors. var ForTesting_ReferencesAllowBlankSelfLinks = false @@ -40,6 +39,7 @@ var ForTesting_ReferencesAllowBlankSelfLinks = false // GetReference returns an ObjectReference which refers to the given // object, or an error if the object doesn't follow the conventions // that would allow this. +// TODO: should take a meta.Interface see https://github.com/GoogleCloudPlatform/kubernetes/issues/7127 func GetReference(obj runtime.Object) (*ObjectReference, error) { if obj == nil { return nil, ErrNilObject @@ -52,23 +52,41 @@ func GetReference(obj runtime.Object) (*ObjectReference, error) { if err != nil { return nil, err } - _, kind, err := Scheme.ObjectVersionAndKind(obj) - if err != nil { - return nil, err - } - version := "" - parsedSelfLink := versionFromSelfLink.FindStringSubmatch(meta.SelfLink()) - if len(parsedSelfLink) < 2 { - if ForTesting_ReferencesAllowBlankSelfLinks { - version = "testing" - } else if meta.SelfLink() == "" { - return nil, ErrNoSelfLink - } else { - return nil, fmt.Errorf("unexpected self link format: '%v'; got version '%v'", meta.SelfLink(), version) + + // if the object referenced is actually persisted, we can just get kind from meta + // if we are building an object reference to something not yet persisted, we should fallback to scheme + kind := meta.Kind() + if kind == "" { + _, kind, err = Scheme.ObjectVersionAndKind(obj) + if err != nil { + return nil, err } - } else { - version = parsedSelfLink[1] } + + // if the object referenced is actually persisted, we can also get version from meta + version := meta.APIVersion() + if version == "" { + selfLink := meta.SelfLink() + if selfLink == "" { + if ForTesting_ReferencesAllowBlankSelfLinks { + version = "testing" + } else { + return nil, ErrNoSelfLink + } + } else { + selfLinkUrl, err := url.Parse(selfLink) + if err != nil { + return nil, err + } + // example paths: ///* + parts := strings.Split(selfLinkUrl.Path, "/") + if len(parts) < 3 { + return nil, fmt.Errorf("unexpected self link format: '%v'; got version '%v'", selfLink, version) + } + version = parts[2] + } + } + return &ObjectReference{ Kind: kind, APIVersion: version, diff --git a/pkg/api/ref_test.go b/pkg/api/ref_test.go index f57d3883c8c..39bb59ffd60 100644 --- a/pkg/api/ref_test.go +++ b/pkg/api/ref_test.go @@ -27,6 +27,13 @@ type FakeAPIObject struct{} func (*FakeAPIObject) IsAnAPIObject() {} +type ExtensionAPIObject struct { + TypeMeta + ObjectMeta +} + +func (*ExtensionAPIObject) IsAnAPIObject() {} + func TestGetReference(t *testing.T) { table := map[string]struct { obj runtime.Object @@ -66,6 +73,26 @@ func TestGetReference(t *testing.T) { ResourceVersion: "42", }, }, + "extensionAPIObject": { + obj: &ExtensionAPIObject{ + TypeMeta: TypeMeta{ + Kind: "ExtensionAPIObject", + }, + ObjectMeta: ObjectMeta{ + Name: "foo", + UID: "bar", + ResourceVersion: "42", + SelfLink: "/custom_prefix/version1/extensions/foo", + }, + }, + ref: &ObjectReference{ + Kind: "ExtensionAPIObject", + APIVersion: "version1", + Name: "foo", + UID: "bar", + ResourceVersion: "42", + }, + }, "badSelfLink": { obj: &ServiceList{ ListMeta: ListMeta{ @@ -90,7 +117,7 @@ func TestGetReference(t *testing.T) { for name, item := range table { ref, err := GetPartialReference(item.obj, item.fieldPath) if e, a := item.shouldErr, (err != nil); e != a { - t.Errorf("%v: expected %v, got %v", name, e, a) + t.Errorf("%v: expected %v, got %v, err %v", name, e, a, err) continue } if e, a := item.ref, ref; !reflect.DeepEqual(e, a) { diff --git a/pkg/kubelet/container/ref_test.go b/pkg/kubelet/container/ref_test.go index 90413ef2c62..d1f09742053 100644 --- a/pkg/kubelet/container/ref_test.go +++ b/pkg/kubelet/container/ref_test.go @@ -86,6 +86,8 @@ func TestGenerateContainerRef(t *testing.T) { noSelfLinkPod = okPod defaultedSelfLinkPod = okPod ) + noSelfLinkPod.Kind = "" + noSelfLinkPod.APIVersion = "" noSelfLinkPod.ObjectMeta.SelfLink = "" defaultedSelfLinkPod.ObjectMeta.SelfLink = "/api/v1beta1/pods/ok"