blob: 442a991cc47c0ce5e6733cb8da0273042565e8ca [file] [log] [blame]
Zack Williamse940c7a2019-08-21 14:25:39 -07001/*
2Copyright 2014 The Kubernetes Authors.
3
4Licensed under the Apache License, Version 2.0 (the "License");
5you may not use this file except in compliance with the License.
6You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10Unless required by applicable law or agreed to in writing, software
11distributed under the License is distributed on an "AS IS" BASIS,
12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13See the License for the specific language governing permissions and
14limitations under the License.
15*/
16
17package reference
18
19import (
20 "errors"
21 "fmt"
Zack Williamse940c7a2019-08-21 14:25:39 -070022
23 "k8s.io/api/core/v1"
24 "k8s.io/apimachinery/pkg/api/meta"
25 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
26 "k8s.io/apimachinery/pkg/runtime"
27)
28
29var (
30 // Errors that could be returned by GetReference.
Scott Baker4a35a702019-11-26 08:17:33 -080031 ErrNilObject = errors.New("can't reference a nil object")
Zack Williamse940c7a2019-08-21 14:25:39 -070032)
33
34// GetReference returns an ObjectReference which refers to the given
35// object, or an error if the object doesn't follow the conventions
36// that would allow this.
37// TODO: should take a meta.Interface see http://issue.k8s.io/7127
38func GetReference(scheme *runtime.Scheme, obj runtime.Object) (*v1.ObjectReference, error) {
39 if obj == nil {
40 return nil, ErrNilObject
41 }
42 if ref, ok := obj.(*v1.ObjectReference); ok {
43 // Don't make a reference to a reference.
44 return ref, nil
45 }
46
Zack Williamse940c7a2019-08-21 14:25:39 -070047 // An object that implements only List has enough metadata to build a reference
48 var listMeta metav1.Common
49 objectMeta, err := meta.Accessor(obj)
50 if err != nil {
51 listMeta, err = meta.CommonAccessor(obj)
52 if err != nil {
53 return nil, err
54 }
55 } else {
56 listMeta = objectMeta
57 }
58
Scott Baker4a35a702019-11-26 08:17:33 -080059 gvk := obj.GetObjectKind().GroupVersionKind()
60
61 // If object meta doesn't contain data about kind and/or version,
62 // we are falling back to scheme.
63 //
64 // TODO: This doesn't work for CRDs, which are not registered in scheme.
65 if gvk.Empty() {
66 gvks, _, err := scheme.ObjectKinds(obj)
Zack Williamse940c7a2019-08-21 14:25:39 -070067 if err != nil {
68 return nil, err
69 }
Scott Baker4a35a702019-11-26 08:17:33 -080070 if len(gvks) == 0 || gvks[0].Empty() {
71 return nil, fmt.Errorf("unexpected gvks registered for object %T: %v", obj, gvks)
Zack Williamse940c7a2019-08-21 14:25:39 -070072 }
Scott Baker4a35a702019-11-26 08:17:33 -080073 // TODO: The same object can be registered for multiple group versions
74 // (although in practise this doesn't seem to be used).
75 // In such case, the version set may not be correct.
76 gvk = gvks[0]
Zack Williamse940c7a2019-08-21 14:25:39 -070077 }
78
Scott Baker4a35a702019-11-26 08:17:33 -080079 kind := gvk.Kind
80 version := gvk.GroupVersion().String()
81
Zack Williamse940c7a2019-08-21 14:25:39 -070082 // only has list metadata
83 if objectMeta == nil {
84 return &v1.ObjectReference{
85 Kind: kind,
86 APIVersion: version,
87 ResourceVersion: listMeta.GetResourceVersion(),
88 }, nil
89 }
90
91 return &v1.ObjectReference{
92 Kind: kind,
93 APIVersion: version,
94 Name: objectMeta.GetName(),
95 Namespace: objectMeta.GetNamespace(),
96 UID: objectMeta.GetUID(),
97 ResourceVersion: objectMeta.GetResourceVersion(),
98 }, nil
99}
100
101// GetPartialReference is exactly like GetReference, but allows you to set the FieldPath.
102func GetPartialReference(scheme *runtime.Scheme, obj runtime.Object, fieldPath string) (*v1.ObjectReference, error) {
103 ref, err := GetReference(scheme, obj)
104 if err != nil {
105 return nil, err
106 }
107 ref.FieldPath = fieldPath
108 return ref, nil
109}