mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-31 15:25:57 +00:00
Move unstructured to its own package under v1
It is a versioned type.
This commit is contained in:
parent
bda57b8fb6
commit
8eb3e9a518
@ -20,6 +20,7 @@ import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
|
||||
"k8s.io/kubernetes/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/kubernetes/pkg/conversion"
|
||||
"k8s.io/kubernetes/pkg/runtime"
|
||||
)
|
||||
@ -29,7 +30,7 @@ func IsListType(obj runtime.Object) bool {
|
||||
// if we're a runtime.Unstructured, check to see if we have an `items` key
|
||||
// This is a list type for recognition, but other Items type methods will fail on it
|
||||
// and give you errors.
|
||||
if unstructured, ok := obj.(*runtime.Unstructured); ok {
|
||||
if unstructured, ok := obj.(*unstructured.Unstructured); ok {
|
||||
_, ok := unstructured.Object["items"]
|
||||
return ok
|
||||
}
|
||||
|
@ -17,7 +17,7 @@ limitations under the License.
|
||||
package meta
|
||||
|
||||
import (
|
||||
"k8s.io/kubernetes/pkg/runtime"
|
||||
"k8s.io/kubernetes/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/kubernetes/pkg/runtime/schema"
|
||||
)
|
||||
|
||||
@ -25,7 +25,7 @@ import (
|
||||
// dealing with runtime.Unstructured objects.
|
||||
func InterfacesForUnstructured(schema.GroupVersion) (*VersionInterfaces, error) {
|
||||
return &VersionInterfaces{
|
||||
ObjectConvertor: &runtime.UnstructuredObjectConverter{},
|
||||
ObjectConvertor: &unstructured.UnstructuredObjectConverter{},
|
||||
MetadataAccessor: NewAccessor(),
|
||||
}, nil
|
||||
}
|
||||
|
@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package runtime
|
||||
package unstructured
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
@ -26,13 +26,59 @@ import (
|
||||
|
||||
"github.com/golang/glog"
|
||||
|
||||
"k8s.io/kubernetes/pkg/api/meta/metatypes"
|
||||
metav1 "k8s.io/kubernetes/pkg/apis/meta/v1"
|
||||
"k8s.io/kubernetes/pkg/runtime"
|
||||
"k8s.io/kubernetes/pkg/runtime/schema"
|
||||
"k8s.io/kubernetes/pkg/types"
|
||||
"k8s.io/kubernetes/pkg/util/json"
|
||||
)
|
||||
|
||||
// Unstructured allows objects that do not have Golang structs registered to be manipulated
|
||||
// generically. This can be used to deal with the API objects from a plug-in. Unstructured
|
||||
// objects still have functioning TypeMeta features-- kind, version, etc.
|
||||
//
|
||||
// WARNING: This object has accessors for the v1 standard metadata. You *MUST NOT* use this
|
||||
// type if you are dealing with objects that are not in the server meta v1 schema.
|
||||
//
|
||||
// TODO: make the serialization part of this type distinct from the field accessors.
|
||||
type Unstructured struct {
|
||||
// Object is a JSON compatible map with string, float, int, bool, []interface{}, or
|
||||
// map[string]interface{}
|
||||
// children.
|
||||
Object map[string]interface{}
|
||||
}
|
||||
|
||||
var _ runtime.Unstructured = &Unstructured{}
|
||||
var _ runtime.Unstructured = &UnstructuredList{}
|
||||
|
||||
func (obj *Unstructured) GetObjectKind() schema.ObjectKind { return obj }
|
||||
func (obj *UnstructuredList) GetObjectKind() schema.ObjectKind { return obj }
|
||||
|
||||
func (obj *Unstructured) IsUnstructuredObject() {}
|
||||
func (obj *UnstructuredList) IsUnstructuredObject() {}
|
||||
|
||||
func (obj *Unstructured) IsList() bool {
|
||||
if obj.Object != nil {
|
||||
_, ok := obj.Object["items"]
|
||||
return ok
|
||||
}
|
||||
return false
|
||||
}
|
||||
func (obj *UnstructuredList) IsList() bool { return true }
|
||||
|
||||
func (obj *Unstructured) UnstructuredContent() map[string]interface{} {
|
||||
if obj.Object == nil {
|
||||
obj.Object = make(map[string]interface{})
|
||||
}
|
||||
return obj.Object
|
||||
}
|
||||
func (obj *UnstructuredList) UnstructuredContent() map[string]interface{} {
|
||||
if obj.Object == nil {
|
||||
obj.Object = make(map[string]interface{})
|
||||
}
|
||||
return obj.Object
|
||||
}
|
||||
|
||||
// MarshalJSON ensures that the unstructured object produces proper
|
||||
// JSON when passed to Go's standard JSON library.
|
||||
func (u *Unstructured) MarshalJSON() ([]byte, error) {
|
||||
@ -142,7 +188,7 @@ func (u *Unstructured) setNestedMap(value map[string]string, fields ...string) {
|
||||
setNestedMap(u.Object, value, fields...)
|
||||
}
|
||||
|
||||
func extractOwnerReference(src interface{}) metatypes.OwnerReference {
|
||||
func extractOwnerReference(src interface{}) metav1.OwnerReference {
|
||||
v := src.(map[string]interface{})
|
||||
controllerPtr, ok := (getNestedField(v, "controller")).(*bool)
|
||||
if !ok {
|
||||
@ -153,7 +199,7 @@ func extractOwnerReference(src interface{}) metatypes.OwnerReference {
|
||||
controllerPtr = &controller
|
||||
}
|
||||
}
|
||||
return metatypes.OwnerReference{
|
||||
return metav1.OwnerReference{
|
||||
Kind: getNestedString(v, "kind"),
|
||||
Name: getNestedString(v, "name"),
|
||||
APIVersion: getNestedString(v, "apiVersion"),
|
||||
@ -162,7 +208,7 @@ func extractOwnerReference(src interface{}) metatypes.OwnerReference {
|
||||
}
|
||||
}
|
||||
|
||||
func setOwnerReference(src metatypes.OwnerReference) map[string]interface{} {
|
||||
func setOwnerReference(src metav1.OwnerReference) map[string]interface{} {
|
||||
ret := make(map[string]interface{})
|
||||
controllerPtr := src.Controller
|
||||
if controllerPtr != nil {
|
||||
@ -202,20 +248,20 @@ func getOwnerReferences(object map[string]interface{}) ([]map[string]interface{}
|
||||
return ownerReferences, nil
|
||||
}
|
||||
|
||||
func (u *Unstructured) GetOwnerReferences() []metatypes.OwnerReference {
|
||||
func (u *Unstructured) GetOwnerReferences() []metav1.OwnerReference {
|
||||
original, err := getOwnerReferences(u.Object)
|
||||
if err != nil {
|
||||
glog.V(6).Info(err)
|
||||
return nil
|
||||
}
|
||||
ret := make([]metatypes.OwnerReference, 0, len(original))
|
||||
ret := make([]metav1.OwnerReference, 0, len(original))
|
||||
for i := 0; i < len(original); i++ {
|
||||
ret = append(ret, extractOwnerReference(original[i]))
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func (u *Unstructured) SetOwnerReferences(references []metatypes.OwnerReference) {
|
||||
func (u *Unstructured) SetOwnerReferences(references []metav1.OwnerReference) {
|
||||
var newReferences = make([]map[string]interface{}, 0, len(references))
|
||||
for i := 0; i < len(references); i++ {
|
||||
newReferences = append(newReferences, setOwnerReference(references[i]))
|
||||
@ -439,11 +485,11 @@ func (u *UnstructuredList) GroupVersionKind() schema.GroupVersionKind {
|
||||
// UnstructuredJSONScheme is capable of converting JSON data into the Unstructured
|
||||
// type, which can be used for generic access to objects without a predefined scheme.
|
||||
// TODO: move into serializer/json.
|
||||
var UnstructuredJSONScheme Codec = unstructuredJSONScheme{}
|
||||
var UnstructuredJSONScheme runtime.Codec = unstructuredJSONScheme{}
|
||||
|
||||
type unstructuredJSONScheme struct{}
|
||||
|
||||
func (s unstructuredJSONScheme) Decode(data []byte, _ *schema.GroupVersionKind, obj Object) (Object, *schema.GroupVersionKind, error) {
|
||||
func (s unstructuredJSONScheme) Decode(data []byte, _ *schema.GroupVersionKind, obj runtime.Object) (runtime.Object, *schema.GroupVersionKind, error) {
|
||||
var err error
|
||||
if obj != nil {
|
||||
err = s.decodeInto(data, obj)
|
||||
@ -457,13 +503,13 @@ func (s unstructuredJSONScheme) Decode(data []byte, _ *schema.GroupVersionKind,
|
||||
|
||||
gvk := obj.GetObjectKind().GroupVersionKind()
|
||||
if len(gvk.Kind) == 0 {
|
||||
return nil, &gvk, NewMissingKindErr(string(data))
|
||||
return nil, &gvk, runtime.NewMissingKindErr(string(data))
|
||||
}
|
||||
|
||||
return obj, &gvk, nil
|
||||
}
|
||||
|
||||
func (unstructuredJSONScheme) Encode(obj Object, w io.Writer) error {
|
||||
func (unstructuredJSONScheme) Encode(obj runtime.Object, w io.Writer) error {
|
||||
switch t := obj.(type) {
|
||||
case *Unstructured:
|
||||
return json.NewEncoder(w).Encode(t.Object)
|
||||
@ -475,7 +521,7 @@ func (unstructuredJSONScheme) Encode(obj Object, w io.Writer) error {
|
||||
t.Object["items"] = items
|
||||
defer func() { delete(t.Object, "items") }()
|
||||
return json.NewEncoder(w).Encode(t.Object)
|
||||
case *Unknown:
|
||||
case *runtime.Unknown:
|
||||
// TODO: Unstructured needs to deal with ContentType.
|
||||
_, err := w.Write(t.Raw)
|
||||
return err
|
||||
@ -484,7 +530,7 @@ func (unstructuredJSONScheme) Encode(obj Object, w io.Writer) error {
|
||||
}
|
||||
}
|
||||
|
||||
func (s unstructuredJSONScheme) decode(data []byte) (Object, error) {
|
||||
func (s unstructuredJSONScheme) decode(data []byte) (runtime.Object, error) {
|
||||
type detector struct {
|
||||
Items gojson.RawMessage
|
||||
}
|
||||
@ -505,16 +551,16 @@ func (s unstructuredJSONScheme) decode(data []byte) (Object, error) {
|
||||
return unstruct, err
|
||||
}
|
||||
|
||||
func (s unstructuredJSONScheme) decodeInto(data []byte, obj Object) error {
|
||||
func (s unstructuredJSONScheme) decodeInto(data []byte, obj runtime.Object) error {
|
||||
switch x := obj.(type) {
|
||||
case *Unstructured:
|
||||
return s.decodeToUnstructured(data, x)
|
||||
case *UnstructuredList:
|
||||
return s.decodeToList(data, x)
|
||||
case *VersionedObjects:
|
||||
case *runtime.VersionedObjects:
|
||||
o, err := s.decode(data)
|
||||
if err == nil {
|
||||
x.Objects = []Object{o}
|
||||
x.Objects = []runtime.Object{o}
|
||||
}
|
||||
return err
|
||||
default:
|
||||
@ -596,7 +642,7 @@ func (UnstructuredObjectConverter) Convert(in, out, context interface{}) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (UnstructuredObjectConverter) ConvertToVersion(in Object, target GroupVersioner) (Object, error) {
|
||||
func (UnstructuredObjectConverter) ConvertToVersion(in runtime.Object, target runtime.GroupVersioner) (runtime.Object, error) {
|
||||
if kind := in.GetObjectKind().GroupVersionKind(); !kind.Empty() {
|
||||
gvk, ok := target.KindForGroupVersionKinds([]schema.GroupVersionKind{kind})
|
||||
if !ok {
|
@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package runtime_test
|
||||
package unstructured_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
@ -29,6 +29,7 @@ import (
|
||||
"k8s.io/kubernetes/pkg/api/validation"
|
||||
"k8s.io/kubernetes/pkg/apimachinery/registered"
|
||||
metav1 "k8s.io/kubernetes/pkg/apis/meta/v1"
|
||||
"k8s.io/kubernetes/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/kubernetes/pkg/runtime"
|
||||
"k8s.io/kubernetes/pkg/types"
|
||||
)
|
||||
@ -49,7 +50,7 @@ func TestDecodeUnstructured(t *testing.T) {
|
||||
Raw: []byte(rawJson),
|
||||
ContentType: runtime.ContentTypeJSON,
|
||||
},
|
||||
&runtime.Unstructured{
|
||||
&unstructured.Unstructured{
|
||||
Object: map[string]interface{}{
|
||||
"kind": "Foo",
|
||||
"apiVersion": "Bar",
|
||||
@ -58,13 +59,13 @@ func TestDecodeUnstructured(t *testing.T) {
|
||||
},
|
||||
},
|
||||
}
|
||||
if errs := runtime.DecodeList(pl.Items, runtime.UnstructuredJSONScheme); len(errs) == 1 {
|
||||
if errs := runtime.DecodeList(pl.Items, unstructured.UnstructuredJSONScheme); len(errs) == 1 {
|
||||
t.Fatalf("unexpected error %v", errs)
|
||||
}
|
||||
if pod, ok := pl.Items[1].(*runtime.Unstructured); !ok || pod.Object["kind"] != "Pod" || pod.Object["metadata"].(map[string]interface{})["name"] != "test" {
|
||||
if pod, ok := pl.Items[1].(*unstructured.Unstructured); !ok || pod.Object["kind"] != "Pod" || pod.Object["metadata"].(map[string]interface{})["name"] != "test" {
|
||||
t.Errorf("object not converted: %#v", pl.Items[1])
|
||||
}
|
||||
if pod, ok := pl.Items[2].(*runtime.Unstructured); !ok || pod.Object["kind"] != "Pod" || pod.Object["metadata"].(map[string]interface{})["name"] != "test" {
|
||||
if pod, ok := pl.Items[2].(*unstructured.Unstructured); !ok || pod.Object["kind"] != "Pod" || pod.Object["metadata"].(map[string]interface{})["name"] != "test" {
|
||||
t.Errorf("object not converted: %#v", pl.Items[2])
|
||||
}
|
||||
}
|
||||
@ -76,21 +77,21 @@ func TestDecode(t *testing.T) {
|
||||
}{
|
||||
{
|
||||
json: []byte(`{"apiVersion": "test", "kind": "test_kind"}`),
|
||||
want: &runtime.Unstructured{
|
||||
want: &unstructured.Unstructured{
|
||||
Object: map[string]interface{}{"apiVersion": "test", "kind": "test_kind"},
|
||||
},
|
||||
},
|
||||
{
|
||||
json: []byte(`{"apiVersion": "test", "kind": "test_list", "items": []}`),
|
||||
want: &runtime.UnstructuredList{
|
||||
want: &unstructured.UnstructuredList{
|
||||
Object: map[string]interface{}{"apiVersion": "test", "kind": "test_list"},
|
||||
},
|
||||
},
|
||||
{
|
||||
json: []byte(`{"items": [{"metadata": {"name": "object1"}, "apiVersion": "test", "kind": "test_kind"}, {"metadata": {"name": "object2"}, "apiVersion": "test", "kind": "test_kind"}], "apiVersion": "test", "kind": "test_list"}`),
|
||||
want: &runtime.UnstructuredList{
|
||||
want: &unstructured.UnstructuredList{
|
||||
Object: map[string]interface{}{"apiVersion": "test", "kind": "test_list"},
|
||||
Items: []*runtime.Unstructured{
|
||||
Items: []*unstructured.Unstructured{
|
||||
{
|
||||
Object: map[string]interface{}{
|
||||
"metadata": map[string]interface{}{"name": "object1"},
|
||||
@ -111,7 +112,7 @@ func TestDecode(t *testing.T) {
|
||||
}
|
||||
|
||||
for _, tc := range tcs {
|
||||
got, _, err := runtime.UnstructuredJSONScheme.Decode(tc.json, nil, nil)
|
||||
got, _, err := unstructured.UnstructuredJSONScheme.Decode(tc.json, nil, nil)
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected error for %q: %v", string(tc.json), err)
|
||||
continue
|
||||
@ -124,7 +125,7 @@ func TestDecode(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestUnstructuredGetters(t *testing.T) {
|
||||
unstruct := runtime.Unstructured{
|
||||
unstruct := unstructured.Unstructured{
|
||||
Object: map[string]interface{}{
|
||||
"kind": "test_kind",
|
||||
"apiVersion": "test_version",
|
||||
@ -240,10 +241,10 @@ func TestUnstructuredGetters(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestUnstructuredSetters(t *testing.T) {
|
||||
unstruct := runtime.Unstructured{}
|
||||
unstruct := unstructured.Unstructured{}
|
||||
trueVar := true
|
||||
|
||||
want := runtime.Unstructured{
|
||||
want := unstructured.Unstructured{
|
||||
Object: map[string]interface{}{
|
||||
"kind": "test_kind",
|
||||
"apiVersion": "test_version",
|
||||
@ -325,7 +326,7 @@ func TestUnstructuredSetters(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestUnstructuredListGetters(t *testing.T) {
|
||||
unstruct := runtime.UnstructuredList{
|
||||
unstruct := unstructured.UnstructuredList{
|
||||
Object: map[string]interface{}{
|
||||
"kind": "test_kind",
|
||||
"apiVersion": "test_version",
|
||||
@ -354,9 +355,9 @@ func TestUnstructuredListGetters(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestUnstructuredListSetters(t *testing.T) {
|
||||
unstruct := runtime.UnstructuredList{}
|
||||
unstruct := unstructured.UnstructuredList{}
|
||||
|
||||
want := runtime.UnstructuredList{
|
||||
want := unstructured.UnstructuredList{
|
||||
Object: map[string]interface{}{
|
||||
"kind": "test_kind",
|
||||
"apiVersion": "test_version",
|
||||
@ -407,11 +408,11 @@ func TestDecodeNumbers(t *testing.T) {
|
||||
}
|
||||
|
||||
// Round-trip with unstructured codec
|
||||
unstructuredObj, err := runtime.Decode(runtime.UnstructuredJSONScheme, originalJSON)
|
||||
unstructuredObj, err := runtime.Decode(unstructured.UnstructuredJSONScheme, originalJSON)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
roundtripJSON, err := runtime.Encode(runtime.UnstructuredJSONScheme, unstructuredObj)
|
||||
roundtripJSON, err := runtime.Encode(unstructured.UnstructuredJSONScheme, unstructuredObj)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
@ -235,3 +235,17 @@ type SelfLinker interface {
|
||||
type Object interface {
|
||||
GetObjectKind() schema.ObjectKind
|
||||
}
|
||||
|
||||
// Unstructured objects store values as map[string]interface{}, with only values that can be serialized
|
||||
// to JSON allowed.
|
||||
type Unstructured interface {
|
||||
// IsUnstructuredObject is a marker interface to allow objects that can be serialized but not introspected
|
||||
// to bypass conversion.
|
||||
IsUnstructuredObject()
|
||||
// IsList returns true if this type is a list or matches the list convention - has an array called "items".
|
||||
IsList() bool
|
||||
// UnstructuredContent returns a non-nil, mutable map of the contents of this object. Values may be
|
||||
// []interface{}, map[string]interface{}, or any primitive type. Contents are typically serialized to
|
||||
// and from JSON.
|
||||
UnstructuredContent() map[string]interface{}
|
||||
}
|
||||
|
@ -30,9 +30,6 @@ func (obj *TypeMeta) GroupVersionKind() schema.GroupVersionKind {
|
||||
|
||||
func (obj *Unknown) GetObjectKind() schema.ObjectKind { return &obj.TypeMeta }
|
||||
|
||||
func (obj *Unstructured) GetObjectKind() schema.ObjectKind { return obj }
|
||||
func (obj *UnstructuredList) GetObjectKind() schema.ObjectKind { return obj }
|
||||
|
||||
// GetObjectKind implements Object for VersionedObjects, returning an empty ObjectKind
|
||||
// interface if no objects are provided, or the ObjectKind interface of the object in the
|
||||
// highest array position.
|
||||
|
@ -181,7 +181,7 @@ func (c *codec) Decode(data []byte, defaultGVK *schema.GroupVersionKind, into ru
|
||||
// conversion if necessary. Unversioned objects (according to the ObjectTyper) are output as is.
|
||||
func (c *codec) Encode(obj runtime.Object, w io.Writer) error {
|
||||
switch obj.(type) {
|
||||
case *runtime.Unknown, *runtime.Unstructured, *runtime.UnstructuredList:
|
||||
case *runtime.Unknown, runtime.Unstructured:
|
||||
return c.encoder.Encode(obj, w)
|
||||
}
|
||||
|
||||
|
@ -122,17 +122,6 @@ type Unknown struct {
|
||||
ContentType string `protobuf:"bytes,4,opt,name=contentType"`
|
||||
}
|
||||
|
||||
// Unstructured allows objects that do not have Golang structs registered to be manipulated
|
||||
// generically. This can be used to deal with the API objects from a plug-in. Unstructured
|
||||
// objects still have functioning TypeMeta features-- kind, version, etc.
|
||||
// TODO: Make this object have easy access to field based accessors and settors for
|
||||
// metadata and field mutatation.
|
||||
type Unstructured struct {
|
||||
// Object is a JSON compatible map with string, float, int, []interface{}, or map[string]interface{}
|
||||
// children.
|
||||
Object map[string]interface{}
|
||||
}
|
||||
|
||||
// VersionedObjects is used by Decoders to give callers a way to access all versions
|
||||
// of an object during the decoding process.
|
||||
type VersionedObjects struct {
|
||||
|
Loading…
Reference in New Issue
Block a user