mirror of https://github.com/k3s-io/k3s
Merge pull request #24751 from krousey/meta_unstructured
Automatic merge from submit-queue Redo Unstructured to have accessor methods Add accessor methods that implement pkg/api/unversioned.ObjectKind, pkg/api/meta.Object, pkg/api/meta.Type and pkg/api/meta.List. Removed the convenience fields since writing to them was not reflected in serialized JSON.pull/6/head
commit
bc010d76cc
|
@ -177,3 +177,5 @@ type RESTMapper interface {
|
||||||
AliasesForResource(resource string) ([]string, bool)
|
AliasesForResource(resource string) ([]string, bool)
|
||||||
ResourceSingularizer(resource string) (singular string, err error)
|
ResourceSingularizer(resource string) (singular string, err error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var _ Object = &runtime.Unstructured{}
|
||||||
|
|
|
@ -157,12 +157,12 @@ func (rc *ResourceClient) Create(obj *runtime.Unstructured) (*runtime.Unstructur
|
||||||
// Update updates the provided resource.
|
// Update updates the provided resource.
|
||||||
func (rc *ResourceClient) Update(obj *runtime.Unstructured) (*runtime.Unstructured, error) {
|
func (rc *ResourceClient) Update(obj *runtime.Unstructured) (*runtime.Unstructured, error) {
|
||||||
result := new(runtime.Unstructured)
|
result := new(runtime.Unstructured)
|
||||||
if len(obj.Name) == 0 {
|
if len(obj.GetName()) == 0 {
|
||||||
return result, errors.New("object missing name")
|
return result, errors.New("object missing name")
|
||||||
}
|
}
|
||||||
err := rc.namespace(rc.cl.Put()).
|
err := rc.namespace(rc.cl.Put()).
|
||||||
Resource(rc.resource.Name).
|
Resource(rc.resource.Name).
|
||||||
Name(obj.Name).
|
Name(obj.GetName()).
|
||||||
Body(obj).
|
Body(obj).
|
||||||
Do().
|
Do().
|
||||||
Into(result)
|
Into(result)
|
||||||
|
|
|
@ -45,11 +45,6 @@ func getListJSON(version, kind string, items ...[]byte) []byte {
|
||||||
|
|
||||||
func getObject(version, kind, name string) *runtime.Unstructured {
|
func getObject(version, kind, name string) *runtime.Unstructured {
|
||||||
return &runtime.Unstructured{
|
return &runtime.Unstructured{
|
||||||
TypeMeta: runtime.TypeMeta{
|
|
||||||
APIVersion: version,
|
|
||||||
Kind: kind,
|
|
||||||
},
|
|
||||||
Name: name,
|
|
||||||
Object: map[string]interface{}{
|
Object: map[string]interface{}{
|
||||||
"apiVersion": version,
|
"apiVersion": version,
|
||||||
"kind": kind,
|
"kind": kind,
|
||||||
|
@ -88,9 +83,9 @@ func TestList(t *testing.T) {
|
||||||
getJSON("vTest", "rTest", "item1"),
|
getJSON("vTest", "rTest", "item1"),
|
||||||
getJSON("vTest", "rTest", "item2")),
|
getJSON("vTest", "rTest", "item2")),
|
||||||
want: &runtime.UnstructuredList{
|
want: &runtime.UnstructuredList{
|
||||||
TypeMeta: runtime.TypeMeta{
|
Object: map[string]interface{}{
|
||||||
APIVersion: "vTest",
|
"apiVersion": "vTest",
|
||||||
Kind: "rTestList",
|
"kind": "rTestList",
|
||||||
},
|
},
|
||||||
Items: []*runtime.Unstructured{
|
Items: []*runtime.Unstructured{
|
||||||
getObject("vTest", "rTest", "item1"),
|
getObject("vTest", "rTest", "item1"),
|
||||||
|
@ -106,9 +101,9 @@ func TestList(t *testing.T) {
|
||||||
getJSON("vTest", "rTest", "item1"),
|
getJSON("vTest", "rTest", "item1"),
|
||||||
getJSON("vTest", "rTest", "item2")),
|
getJSON("vTest", "rTest", "item2")),
|
||||||
want: &runtime.UnstructuredList{
|
want: &runtime.UnstructuredList{
|
||||||
TypeMeta: runtime.TypeMeta{
|
Object: map[string]interface{}{
|
||||||
APIVersion: "vTest",
|
"apiVersion": "vTest",
|
||||||
Kind: "rTestList",
|
"kind": "rTestList",
|
||||||
},
|
},
|
||||||
Items: []*runtime.Unstructured{
|
Items: []*runtime.Unstructured{
|
||||||
getObject("vTest", "rTest", "item1"),
|
getObject("vTest", "rTest", "item1"),
|
||||||
|
|
|
@ -236,7 +236,7 @@ func deleteEachItem(
|
||||||
}
|
}
|
||||||
apiResource := unversioned.APIResource{Name: gvr.Resource, Namespaced: true}
|
apiResource := unversioned.APIResource{Name: gvr.Resource, Namespaced: true}
|
||||||
for _, item := range unstructuredList.Items {
|
for _, item := range unstructuredList.Items {
|
||||||
if err = dynamicClient.Resource(&apiResource, namespace).Delete(item.Name, nil); err != nil && !errors.IsNotFound(err) && !errors.IsMethodNotSupported(err) {
|
if err = dynamicClient.Resource(&apiResource, namespace).Delete(item.GetName(), nil); err != nil && !errors.IsNotFound(err) && !errors.IsMethodNotSupported(err) {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,7 +33,13 @@ func TestDecodeList(t *testing.T) {
|
||||||
Raw: []byte(`{"kind":"Pod","apiVersion":"` + testapi.Default.GroupVersion().String() + `","metadata":{"name":"test"}}`),
|
Raw: []byte(`{"kind":"Pod","apiVersion":"` + testapi.Default.GroupVersion().String() + `","metadata":{"name":"test"}}`),
|
||||||
ContentType: runtime.ContentTypeJSON,
|
ContentType: runtime.ContentTypeJSON,
|
||||||
},
|
},
|
||||||
&runtime.Unstructured{TypeMeta: runtime.TypeMeta{Kind: "Foo", APIVersion: "Bar"}, Object: map[string]interface{}{"test": "value"}},
|
&runtime.Unstructured{
|
||||||
|
Object: map[string]interface{}{
|
||||||
|
"kind": "Foo",
|
||||||
|
"apiVersion": "Bar",
|
||||||
|
"test": "value",
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
if errs := runtime.DecodeList(pl.Items, testapi.Default.Codec()); len(errs) != 0 {
|
if errs := runtime.DecodeList(pl.Items, testapi.Default.Codec()); len(errs) != 0 {
|
||||||
|
|
|
@ -31,8 +31,9 @@ func (obj *TypeMeta) GroupVersionKind() *unversioned.GroupVersionKind {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (obj *Unknown) GetObjectKind() unversioned.ObjectKind { return &obj.TypeMeta }
|
func (obj *Unknown) GetObjectKind() unversioned.ObjectKind { return &obj.TypeMeta }
|
||||||
func (obj *Unstructured) GetObjectKind() unversioned.ObjectKind { return &obj.TypeMeta }
|
|
||||||
func (obj *UnstructuredList) GetObjectKind() unversioned.ObjectKind { return &obj.TypeMeta }
|
func (obj *Unstructured) GetObjectKind() unversioned.ObjectKind { return obj }
|
||||||
|
func (obj *UnstructuredList) GetObjectKind() unversioned.ObjectKind { return obj }
|
||||||
|
|
||||||
// GetObjectKind implements Object for VersionedObjects, returning an empty ObjectKind
|
// GetObjectKind implements Object for VersionedObjects, returning an empty ObjectKind
|
||||||
// interface if no objects are provided, or the ObjectKind interface of the object in the
|
// interface if no objects are provided, or the ObjectKind interface of the object in the
|
||||||
|
|
|
@ -16,6 +16,11 @@ limitations under the License.
|
||||||
|
|
||||||
package runtime
|
package runtime
|
||||||
|
|
||||||
|
import (
|
||||||
|
"k8s.io/kubernetes/pkg/api/unversioned"
|
||||||
|
"k8s.io/kubernetes/pkg/types"
|
||||||
|
)
|
||||||
|
|
||||||
// Note that the types provided in this file are not versioned and are intended to be
|
// Note that the types provided in this file are not versioned and are intended to be
|
||||||
// safe to use from within all versions of every API object.
|
// safe to use from within all versions of every API object.
|
||||||
|
|
||||||
|
@ -120,26 +125,259 @@ type Unknown struct {
|
||||||
// TODO: Make this object have easy access to field based accessors and settors for
|
// TODO: Make this object have easy access to field based accessors and settors for
|
||||||
// metadata and field mutatation.
|
// metadata and field mutatation.
|
||||||
type Unstructured struct {
|
type Unstructured struct {
|
||||||
TypeMeta `json:",inline"`
|
|
||||||
|
|
||||||
// Name is populated from metadata (if present) upon deserialization
|
|
||||||
Name string
|
|
||||||
|
|
||||||
// Object is a JSON compatible map with string, float, int, []interface{}, or map[string]interface{}
|
// Object is a JSON compatible map with string, float, int, []interface{}, or map[string]interface{}
|
||||||
// children.
|
// children.
|
||||||
Object map[string]interface{}
|
Object map[string]interface{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getNestedField(obj map[string]interface{}, fields ...string) interface{} {
|
||||||
|
var val interface{} = obj
|
||||||
|
for _, field := range fields {
|
||||||
|
if _, ok := val.(map[string]interface{}); !ok {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
val = val.(map[string]interface{})[field]
|
||||||
|
}
|
||||||
|
return val
|
||||||
|
}
|
||||||
|
|
||||||
|
func getNestedString(obj map[string]interface{}, fields ...string) string {
|
||||||
|
if str, ok := getNestedField(obj, fields...).(string); ok {
|
||||||
|
return str
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func getNestedMap(obj map[string]interface{}, fields ...string) map[string]string {
|
||||||
|
if m, ok := getNestedField(obj, fields...).(map[string]interface{}); ok {
|
||||||
|
strMap := make(map[string]string, len(m))
|
||||||
|
for k, v := range m {
|
||||||
|
if str, ok := v.(string); ok {
|
||||||
|
strMap[k] = str
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return strMap
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func setNestedField(obj map[string]interface{}, value interface{}, fields ...string) {
|
||||||
|
m := obj
|
||||||
|
if len(fields) > 1 {
|
||||||
|
for _, field := range fields[0 : len(fields)-1] {
|
||||||
|
if _, ok := m[field].(map[string]interface{}); !ok {
|
||||||
|
m[field] = make(map[string]interface{})
|
||||||
|
}
|
||||||
|
m = m[field].(map[string]interface{})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m[fields[len(fields)-1]] = value
|
||||||
|
}
|
||||||
|
|
||||||
|
func setNestedMap(obj map[string]interface{}, value map[string]string, fields ...string) {
|
||||||
|
m := make(map[string]interface{}, len(value))
|
||||||
|
for k, v := range value {
|
||||||
|
m[k] = v
|
||||||
|
}
|
||||||
|
setNestedField(obj, m, fields...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *Unstructured) setNestedField(value interface{}, fields ...string) {
|
||||||
|
if u.Object == nil {
|
||||||
|
u.Object = make(map[string]interface{})
|
||||||
|
}
|
||||||
|
setNestedField(u.Object, value, fields...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *Unstructured) setNestedMap(value map[string]string, fields ...string) {
|
||||||
|
if u.Object == nil {
|
||||||
|
u.Object = make(map[string]interface{})
|
||||||
|
}
|
||||||
|
setNestedMap(u.Object, value, fields...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *Unstructured) GetAPIVersion() string {
|
||||||
|
return getNestedString(u.Object, "apiVersion")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *Unstructured) SetAPIVersion(version string) {
|
||||||
|
u.setNestedField(version, "apiVersion")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *Unstructured) GetKind() string {
|
||||||
|
return getNestedString(u.Object, "kind")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *Unstructured) SetKind(kind string) {
|
||||||
|
u.setNestedField(kind, "kind")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *Unstructured) GetNamespace() string {
|
||||||
|
return getNestedString(u.Object, "metadata", "namespace")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *Unstructured) SetNamespace(namespace string) {
|
||||||
|
u.setNestedField(namespace, "metadata", "namespace")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *Unstructured) GetName() string {
|
||||||
|
return getNestedString(u.Object, "metadata", "name")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *Unstructured) SetName(name string) {
|
||||||
|
u.setNestedField(name, "metadata", "name")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *Unstructured) GetGenerateName() string {
|
||||||
|
return getNestedString(u.Object, "metadata", "generateName")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *Unstructured) SetGenerateName(name string) {
|
||||||
|
u.setNestedField(name, "metadata", "generateName")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *Unstructured) GetUID() types.UID {
|
||||||
|
return types.UID(getNestedString(u.Object, "metadata", "uid"))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *Unstructured) SetUID(uid types.UID) {
|
||||||
|
u.setNestedField(string(uid), "metadata", "uid")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *Unstructured) GetResourceVersion() string {
|
||||||
|
return getNestedString(u.Object, "metadata", "resourceVersion")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *Unstructured) SetResourceVersion(version string) {
|
||||||
|
u.setNestedField(version, "metadata", "resourceVersion")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *Unstructured) GetSelfLink() string {
|
||||||
|
return getNestedString(u.Object, "metadata", "selfLink")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *Unstructured) SetSelfLink(selfLink string) {
|
||||||
|
u.setNestedField(selfLink, "metadata", "selfLink")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *Unstructured) GetCreationTimestamp() unversioned.Time {
|
||||||
|
var timestamp unversioned.Time
|
||||||
|
timestamp.UnmarshalQueryParameter(getNestedString(u.Object, "metadata", "creationTimestamp"))
|
||||||
|
return timestamp
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *Unstructured) SetCreationTimestamp(timestamp unversioned.Time) {
|
||||||
|
ts, _ := timestamp.MarshalQueryParameter()
|
||||||
|
u.setNestedField(ts, "metadata", "creationTimestamp")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *Unstructured) GetDeletionTimestamp() *unversioned.Time {
|
||||||
|
var timestamp unversioned.Time
|
||||||
|
timestamp.UnmarshalQueryParameter(getNestedString(u.Object, "metadata", "deletionTimestamp"))
|
||||||
|
if timestamp.IsZero() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return ×tamp
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *Unstructured) SetDeletionTimestamp(timestamp *unversioned.Time) {
|
||||||
|
ts, _ := timestamp.MarshalQueryParameter()
|
||||||
|
u.setNestedField(ts, "metadata", "deletionTimestamp")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *Unstructured) GetLabels() map[string]string {
|
||||||
|
return getNestedMap(u.Object, "metadata", "labels")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *Unstructured) SetLabels(labels map[string]string) {
|
||||||
|
u.setNestedMap(labels, "metadata", "labels")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *Unstructured) GetAnnotations() map[string]string {
|
||||||
|
return getNestedMap(u.Object, "metadata", "annotations")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *Unstructured) SetAnnotations(annotations map[string]string) {
|
||||||
|
u.setNestedMap(annotations, "metadata", "annotations")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *Unstructured) SetGroupVersionKind(gvk *unversioned.GroupVersionKind) {
|
||||||
|
u.SetAPIVersion(gvk.GroupVersion().String())
|
||||||
|
u.SetKind(gvk.Kind)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *Unstructured) GroupVersionKind() *unversioned.GroupVersionKind {
|
||||||
|
gv, err := unversioned.ParseGroupVersion(u.GetAPIVersion())
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
gvk := gv.WithKind(u.GetKind())
|
||||||
|
return &gvk
|
||||||
|
}
|
||||||
|
|
||||||
// UnstructuredList allows lists that do not have Golang structs
|
// UnstructuredList allows lists that do not have Golang structs
|
||||||
// registered to be manipulated generically. This can be used to deal
|
// registered to be manipulated generically. This can be used to deal
|
||||||
// with the API lists from a plug-in.
|
// with the API lists from a plug-in.
|
||||||
type UnstructuredList struct {
|
type UnstructuredList struct {
|
||||||
TypeMeta `json:",inline"`
|
Object map[string]interface{}
|
||||||
|
|
||||||
// Items is a list of unstructured objects.
|
// Items is a list of unstructured objects.
|
||||||
Items []*Unstructured `json:"items"`
|
Items []*Unstructured `json:"items"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (u *UnstructuredList) setNestedField(value interface{}, fields ...string) {
|
||||||
|
if u.Object == nil {
|
||||||
|
u.Object = make(map[string]interface{})
|
||||||
|
}
|
||||||
|
setNestedField(u.Object, value, fields...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *UnstructuredList) GetAPIVersion() string {
|
||||||
|
return getNestedString(u.Object, "apiVersion")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *UnstructuredList) SetAPIVersion(version string) {
|
||||||
|
u.setNestedField(version, "apiVersion")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *UnstructuredList) GetKind() string {
|
||||||
|
return getNestedString(u.Object, "kind")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *UnstructuredList) SetKind(kind string) {
|
||||||
|
u.setNestedField(kind, "kind")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *UnstructuredList) GetResourceVersion() string {
|
||||||
|
return getNestedString(u.Object, "metadata", "resourceVersion")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *UnstructuredList) SetResourceVersion(version string) {
|
||||||
|
u.setNestedField(version, "metadata", "resourceVersion")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *UnstructuredList) GetSelfLink() string {
|
||||||
|
return getNestedString(u.Object, "metadata", "selfLink")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *UnstructuredList) SetSelfLink(selfLink string) {
|
||||||
|
u.setNestedField(selfLink, "metadata", "selfLink")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *UnstructuredList) SetGroupVersionKind(gvk *unversioned.GroupVersionKind) {
|
||||||
|
u.SetAPIVersion(gvk.GroupVersion().String())
|
||||||
|
u.SetKind(gvk.Kind)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *UnstructuredList) GroupVersionKind() *unversioned.GroupVersionKind {
|
||||||
|
gv, err := unversioned.ParseGroupVersion(u.GetAPIVersion())
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
gvk := gv.WithKind(u.GetKind())
|
||||||
|
return &gvk
|
||||||
|
}
|
||||||
|
|
||||||
// VersionedObjects is used by Decoders to give callers a way to access all versions
|
// VersionedObjects is used by Decoders to give callers a way to access all versions
|
||||||
// of an object during the decoding process.
|
// of an object during the decoding process.
|
||||||
type VersionedObjects struct {
|
type VersionedObjects struct {
|
||||||
|
|
|
@ -56,17 +56,13 @@ func (unstructuredJSONScheme) EncodeToStream(obj Object, w io.Writer, overrides
|
||||||
case *Unstructured:
|
case *Unstructured:
|
||||||
return json.NewEncoder(w).Encode(t.Object)
|
return json.NewEncoder(w).Encode(t.Object)
|
||||||
case *UnstructuredList:
|
case *UnstructuredList:
|
||||||
type encodeList struct {
|
var items []map[string]interface{}
|
||||||
TypeMeta `json:",inline"`
|
|
||||||
Items []map[string]interface{} `json:"items"`
|
|
||||||
}
|
|
||||||
eList := encodeList{
|
|
||||||
TypeMeta: t.TypeMeta,
|
|
||||||
}
|
|
||||||
for _, i := range t.Items {
|
for _, i := range t.Items {
|
||||||
eList.Items = append(eList.Items, i.Object)
|
items = append(items, i.Object)
|
||||||
}
|
}
|
||||||
return json.NewEncoder(w).Encode(eList)
|
t.Object["items"] = items
|
||||||
|
defer func() { delete(t.Object, "items") }()
|
||||||
|
return json.NewEncoder(w).Encode(t.Object)
|
||||||
case *Unknown:
|
case *Unknown:
|
||||||
// TODO: Unstructured needs to deal with ContentType.
|
// TODO: Unstructured needs to deal with ContentType.
|
||||||
_, err := w.Write(t.Raw)
|
_, err := w.Write(t.Raw)
|
||||||
|
@ -113,25 +109,6 @@ func (unstructuredJSONScheme) decodeToUnstructured(data []byte, unstruct *Unstru
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if v, ok := m["kind"]; ok {
|
|
||||||
if s, ok := v.(string); ok {
|
|
||||||
unstruct.Kind = s
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if v, ok := m["apiVersion"]; ok {
|
|
||||||
if s, ok := v.(string); ok {
|
|
||||||
unstruct.APIVersion = s
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if metadata, ok := m["metadata"]; ok {
|
|
||||||
if metadata, ok := metadata.(map[string]interface{}); ok {
|
|
||||||
if name, ok := metadata["name"]; ok {
|
|
||||||
if name, ok := name.(string); ok {
|
|
||||||
unstruct.Name = name
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
unstruct.Object = m
|
unstruct.Object = m
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
@ -139,7 +116,6 @@ func (unstructuredJSONScheme) decodeToUnstructured(data []byte, unstruct *Unstru
|
||||||
|
|
||||||
func (s unstructuredJSONScheme) decodeToList(data []byte, list *UnstructuredList) error {
|
func (s unstructuredJSONScheme) decodeToList(data []byte, list *UnstructuredList) error {
|
||||||
type decodeList struct {
|
type decodeList struct {
|
||||||
TypeMeta `json:",inline"`
|
|
||||||
Items []gojson.RawMessage
|
Items []gojson.RawMessage
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -148,7 +124,11 @@ func (s unstructuredJSONScheme) decodeToList(data []byte, list *UnstructuredList
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
list.TypeMeta = dList.TypeMeta
|
if err := json.Unmarshal(data, &list.Object); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
delete(list.Object, "items")
|
||||||
list.Items = nil
|
list.Items = nil
|
||||||
for _, i := range dList.Items {
|
for _, i := range dList.Items {
|
||||||
unstruct := &Unstructured{}
|
unstruct := &Unstructured{}
|
||||||
|
|
|
@ -21,11 +21,14 @@ import (
|
||||||
"reflect"
|
"reflect"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
"k8s.io/kubernetes/pkg/api"
|
"k8s.io/kubernetes/pkg/api"
|
||||||
"k8s.io/kubernetes/pkg/api/testapi"
|
"k8s.io/kubernetes/pkg/api/testapi"
|
||||||
|
"k8s.io/kubernetes/pkg/api/unversioned"
|
||||||
"k8s.io/kubernetes/pkg/api/validation"
|
"k8s.io/kubernetes/pkg/api/validation"
|
||||||
"k8s.io/kubernetes/pkg/runtime"
|
"k8s.io/kubernetes/pkg/runtime"
|
||||||
|
"k8s.io/kubernetes/pkg/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestDecodeUnstructured(t *testing.T) {
|
func TestDecodeUnstructured(t *testing.T) {
|
||||||
|
@ -44,7 +47,13 @@ func TestDecodeUnstructured(t *testing.T) {
|
||||||
Raw: []byte(rawJson),
|
Raw: []byte(rawJson),
|
||||||
ContentType: runtime.ContentTypeJSON,
|
ContentType: runtime.ContentTypeJSON,
|
||||||
},
|
},
|
||||||
&runtime.Unstructured{TypeMeta: runtime.TypeMeta{Kind: "Foo", APIVersion: "Bar"}, Object: map[string]interface{}{"test": "value"}},
|
&runtime.Unstructured{
|
||||||
|
Object: map[string]interface{}{
|
||||||
|
"kind": "Foo",
|
||||||
|
"apiVersion": "Bar",
|
||||||
|
"test": "value",
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
if errs := runtime.DecodeList(pl.Items, runtime.UnstructuredJSONScheme); len(errs) == 1 {
|
if errs := runtime.DecodeList(pl.Items, runtime.UnstructuredJSONScheme); len(errs) == 1 {
|
||||||
|
@ -66,36 +75,21 @@ func TestDecode(t *testing.T) {
|
||||||
{
|
{
|
||||||
json: []byte(`{"apiVersion": "test", "kind": "test_kind"}`),
|
json: []byte(`{"apiVersion": "test", "kind": "test_kind"}`),
|
||||||
want: &runtime.Unstructured{
|
want: &runtime.Unstructured{
|
||||||
TypeMeta: runtime.TypeMeta{
|
|
||||||
APIVersion: "test",
|
|
||||||
Kind: "test_kind",
|
|
||||||
},
|
|
||||||
Object: map[string]interface{}{"apiVersion": "test", "kind": "test_kind"},
|
Object: map[string]interface{}{"apiVersion": "test", "kind": "test_kind"},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
json: []byte(`{"apiVersion": "test", "kind": "test_list", "items": []}`),
|
json: []byte(`{"apiVersion": "test", "kind": "test_list", "items": []}`),
|
||||||
want: &runtime.UnstructuredList{
|
want: &runtime.UnstructuredList{
|
||||||
TypeMeta: runtime.TypeMeta{
|
Object: map[string]interface{}{"apiVersion": "test", "kind": "test_list"},
|
||||||
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"}`),
|
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: &runtime.UnstructuredList{
|
||||||
TypeMeta: runtime.TypeMeta{
|
Object: map[string]interface{}{"apiVersion": "test", "kind": "test_list"},
|
||||||
APIVersion: "test",
|
|
||||||
Kind: "test_list",
|
|
||||||
},
|
|
||||||
Items: []*runtime.Unstructured{
|
Items: []*runtime.Unstructured{
|
||||||
{
|
{
|
||||||
TypeMeta: runtime.TypeMeta{
|
|
||||||
APIVersion: "test",
|
|
||||||
Kind: "test_kind",
|
|
||||||
},
|
|
||||||
Name: "object1",
|
|
||||||
Object: map[string]interface{}{
|
Object: map[string]interface{}{
|
||||||
"metadata": map[string]interface{}{"name": "object1"},
|
"metadata": map[string]interface{}{"name": "object1"},
|
||||||
"apiVersion": "test",
|
"apiVersion": "test",
|
||||||
|
@ -103,11 +97,6 @@ func TestDecode(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
TypeMeta: runtime.TypeMeta{
|
|
||||||
APIVersion: "test",
|
|
||||||
Kind: "test_kind",
|
|
||||||
},
|
|
||||||
Name: "object2",
|
|
||||||
Object: map[string]interface{}{
|
Object: map[string]interface{}{
|
||||||
"metadata": map[string]interface{}{"name": "object2"},
|
"metadata": map[string]interface{}{"name": "object2"},
|
||||||
"apiVersion": "test",
|
"apiVersion": "test",
|
||||||
|
@ -132,6 +121,177 @@ func TestDecode(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestUnstructuredGetters(t *testing.T) {
|
||||||
|
unstruct := runtime.Unstructured{
|
||||||
|
Object: map[string]interface{}{
|
||||||
|
"kind": "test_kind",
|
||||||
|
"apiVersion": "test_version",
|
||||||
|
"metadata": map[string]interface{}{
|
||||||
|
"name": "test_name",
|
||||||
|
"namespace": "test_namespace",
|
||||||
|
"generateName": "test_generateName",
|
||||||
|
"uid": "test_uid",
|
||||||
|
"resourceVersion": "test_resourceVersion",
|
||||||
|
"selfLink": "test_selfLink",
|
||||||
|
"creationTimestamp": "2009-11-10T23:00:00Z",
|
||||||
|
"deletionTimestamp": "2010-11-10T23:00:00Z",
|
||||||
|
"labels": map[string]interface{}{
|
||||||
|
"test_label": "test_value",
|
||||||
|
},
|
||||||
|
"annotations": map[string]interface{}{
|
||||||
|
"test_annotation": "test_value",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
if got, want := unstruct.GetAPIVersion(), "test_version"; got != want {
|
||||||
|
t.Errorf("GetAPIVersions() = %s, want %s", got, want)
|
||||||
|
}
|
||||||
|
|
||||||
|
if got, want := unstruct.GetKind(), "test_kind"; got != want {
|
||||||
|
t.Errorf("GetKind() = %s, want %s", got, want)
|
||||||
|
}
|
||||||
|
|
||||||
|
if got, want := unstruct.GetNamespace(), "test_namespace"; got != want {
|
||||||
|
t.Errorf("GetNamespace() = %s, want %s", got, want)
|
||||||
|
}
|
||||||
|
|
||||||
|
if got, want := unstruct.GetName(), "test_name"; got != want {
|
||||||
|
t.Errorf("GetName() = %s, want %s", got, want)
|
||||||
|
}
|
||||||
|
|
||||||
|
if got, want := unstruct.GetGenerateName(), "test_generateName"; got != want {
|
||||||
|
t.Errorf("GetGenerateName() = %s, want %s", got, want)
|
||||||
|
}
|
||||||
|
|
||||||
|
if got, want := unstruct.GetUID(), types.UID("test_uid"); got != want {
|
||||||
|
t.Errorf("GetUID() = %s, want %s", got, want)
|
||||||
|
}
|
||||||
|
|
||||||
|
if got, want := unstruct.GetResourceVersion(), "test_resourceVersion"; got != want {
|
||||||
|
t.Errorf("GetResourceVersion() = %s, want %s", got, want)
|
||||||
|
}
|
||||||
|
|
||||||
|
if got, want := unstruct.GetSelfLink(), "test_selfLink"; got != want {
|
||||||
|
t.Errorf("GetSelfLink() = %s, want %s", got, want)
|
||||||
|
}
|
||||||
|
|
||||||
|
if got, want := unstruct.GetCreationTimestamp(), unversioned.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC); !got.Equal(want) {
|
||||||
|
t.Errorf("GetCreationTimestamp() = %s, want %s", got, want)
|
||||||
|
}
|
||||||
|
|
||||||
|
if got, want := unstruct.GetDeletionTimestamp(), unversioned.Date(2010, time.November, 10, 23, 0, 0, 0, time.UTC); got == nil || !got.Equal(want) {
|
||||||
|
t.Errorf("GetDeletionTimestamp() = %s, want %s", got, want)
|
||||||
|
}
|
||||||
|
|
||||||
|
if got, want := unstruct.GetLabels(), map[string]string{"test_label": "test_value"}; !reflect.DeepEqual(got, want) {
|
||||||
|
t.Errorf("GetLabels() = %s, want %s", got, want)
|
||||||
|
}
|
||||||
|
|
||||||
|
if got, want := unstruct.GetAnnotations(), map[string]string{"test_annotation": "test_value"}; !reflect.DeepEqual(got, want) {
|
||||||
|
t.Errorf("GetAnnotations() = %s, want %s", got, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUnstructuredSetters(t *testing.T) {
|
||||||
|
unstruct := runtime.Unstructured{}
|
||||||
|
|
||||||
|
want := runtime.Unstructured{
|
||||||
|
Object: map[string]interface{}{
|
||||||
|
"kind": "test_kind",
|
||||||
|
"apiVersion": "test_version",
|
||||||
|
"metadata": map[string]interface{}{
|
||||||
|
"name": "test_name",
|
||||||
|
"namespace": "test_namespace",
|
||||||
|
"generateName": "test_generateName",
|
||||||
|
"uid": "test_uid",
|
||||||
|
"resourceVersion": "test_resourceVersion",
|
||||||
|
"selfLink": "test_selfLink",
|
||||||
|
"creationTimestamp": "2009-11-10T23:00:00Z",
|
||||||
|
"deletionTimestamp": "2010-11-10T23:00:00Z",
|
||||||
|
"labels": map[string]interface{}{
|
||||||
|
"test_label": "test_value",
|
||||||
|
},
|
||||||
|
"annotations": map[string]interface{}{
|
||||||
|
"test_annotation": "test_value",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
unstruct.SetAPIVersion("test_version")
|
||||||
|
unstruct.SetKind("test_kind")
|
||||||
|
unstruct.SetNamespace("test_namespace")
|
||||||
|
unstruct.SetName("test_name")
|
||||||
|
unstruct.SetGenerateName("test_generateName")
|
||||||
|
unstruct.SetUID(types.UID("test_uid"))
|
||||||
|
unstruct.SetResourceVersion("test_resourceVersion")
|
||||||
|
unstruct.SetSelfLink("test_selfLink")
|
||||||
|
unstruct.SetCreationTimestamp(unversioned.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC))
|
||||||
|
date := unversioned.Date(2010, time.November, 10, 23, 0, 0, 0, time.UTC)
|
||||||
|
unstruct.SetDeletionTimestamp(&date)
|
||||||
|
unstruct.SetLabels(map[string]string{"test_label": "test_value"})
|
||||||
|
unstruct.SetAnnotations(map[string]string{"test_annotation": "test_value"})
|
||||||
|
|
||||||
|
if !reflect.DeepEqual(unstruct, want) {
|
||||||
|
t.Errorf("Wanted: \n%s\n Got:\n%s", unstruct, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUnstructuredListGetters(t *testing.T) {
|
||||||
|
unstruct := runtime.UnstructuredList{
|
||||||
|
Object: map[string]interface{}{
|
||||||
|
"kind": "test_kind",
|
||||||
|
"apiVersion": "test_version",
|
||||||
|
"metadata": map[string]interface{}{
|
||||||
|
"resourceVersion": "test_resourceVersion",
|
||||||
|
"selfLink": "test_selfLink",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
if got, want := unstruct.GetAPIVersion(), "test_version"; got != want {
|
||||||
|
t.Errorf("GetAPIVersions() = %s, want %s", got, want)
|
||||||
|
}
|
||||||
|
|
||||||
|
if got, want := unstruct.GetKind(), "test_kind"; got != want {
|
||||||
|
t.Errorf("GetKind() = %s, want %s", got, want)
|
||||||
|
}
|
||||||
|
|
||||||
|
if got, want := unstruct.GetResourceVersion(), "test_resourceVersion"; got != want {
|
||||||
|
t.Errorf("GetResourceVersion() = %s, want %s", got, want)
|
||||||
|
}
|
||||||
|
|
||||||
|
if got, want := unstruct.GetSelfLink(), "test_selfLink"; got != want {
|
||||||
|
t.Errorf("GetSelfLink() = %s, want %s", got, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUnstructuredListSetters(t *testing.T) {
|
||||||
|
unstruct := runtime.UnstructuredList{}
|
||||||
|
|
||||||
|
want := runtime.UnstructuredList{
|
||||||
|
Object: map[string]interface{}{
|
||||||
|
"kind": "test_kind",
|
||||||
|
"apiVersion": "test_version",
|
||||||
|
"metadata": map[string]interface{}{
|
||||||
|
"resourceVersion": "test_resourceVersion",
|
||||||
|
"selfLink": "test_selfLink",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
unstruct.SetAPIVersion("test_version")
|
||||||
|
unstruct.SetKind("test_kind")
|
||||||
|
unstruct.SetResourceVersion("test_resourceVersion")
|
||||||
|
unstruct.SetSelfLink("test_selfLink")
|
||||||
|
|
||||||
|
if !reflect.DeepEqual(unstruct, want) {
|
||||||
|
t.Errorf("Wanted: \n%s\n Got:\n%s", unstruct, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestDecodeNumbers(t *testing.T) {
|
func TestDecodeNumbers(t *testing.T) {
|
||||||
|
|
||||||
// Start with a valid pod
|
// Start with a valid pod
|
||||||
|
|
Loading…
Reference in New Issue