// ObjectKind returns the group,version,kind of the provided object, or an error // if the object in not *runtime.Unstructured or has no group,version,kind // information. func (d *UnstructuredObjectTyper) ObjectKind(obj runtime.Object) (unversioned.GroupVersionKind, error) { if _, ok := obj.(*runtime.Unstructured); !ok { return unversioned.GroupVersionKind{}, fmt.Errorf("type %T is invalid for dynamic object typer", obj) } return obj.GetObjectKind().GroupVersionKind(), nil }
// Encode does not do conversion. It sets the gvk during serialization. func (e DirectEncoder) Encode(obj runtime.Object, stream io.Writer) error { gvks, _, err := e.ObjectTyper.ObjectKinds(obj) if err != nil { if runtime.IsNotRegisteredError(err) { return e.Encoder.Encode(obj, stream) } return err } kind := obj.GetObjectKind() oldGVK := kind.GroupVersionKind() kind.SetGroupVersionKind(gvks[0]) err = e.Encoder.Encode(obj, stream) kind.SetGroupVersionKind(oldGVK) return err }
// Encode ensures the provided object is output in the appropriate group and version, invoking // 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: return c.encoder.Encode(obj, w) } gvks, isUnversioned, err := c.typer.ObjectKinds(obj) if err != nil { return err } if c.encodeVersion == nil || isUnversioned { if e, ok := obj.(runtime.NestedObjectEncoder); ok { if err := e.EncodeNestedObjects(DirectEncoder{Encoder: c.encoder, ObjectTyper: c.typer}); err != nil { return err } } objectKind := obj.GetObjectKind() old := objectKind.GroupVersionKind() objectKind.SetGroupVersionKind(gvks[0]) err = c.encoder.Encode(obj, w) objectKind.SetGroupVersionKind(old) return err } // Perform a conversion if necessary objectKind := obj.GetObjectKind() old := objectKind.GroupVersionKind() out, err := c.convertor.ConvertToVersion(obj, c.encodeVersion) if err != nil { return err } if e, ok := out.(runtime.NestedObjectEncoder); ok { if err := e.EncodeNestedObjects(DirectEncoder{Encoder: c.encoder, ObjectTyper: c.typer}); err != nil { return err } } // Conversion is responsible for setting the proper group, version, and kind onto the outgoing object err = c.encoder.Encode(out, w) // restore the old GVK, in case conversion returned the same object objectKind.SetGroupVersionKind(old) return err }
// 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 http://issue.k8s.io/7127 func GetReference(obj runtime.Object) (*ObjectReference, error) { if obj == nil { return nil, ErrNilObject } if ref, ok := obj.(*ObjectReference); ok { // Don't make a reference to a reference. return ref, nil } gvk := obj.GetObjectKind().GroupVersionKind() // 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 := gvk.Kind if len(kind) == 0 { // TODO: this is wrong gvks, _, err := api.Scheme.ObjectKinds(obj) if err != nil { return nil, err } kind = gvks[0].Kind } // An object that implements only List has enough metadata to build a reference var listMeta meta.List objectMeta, err := meta.Accessor(obj) if err != nil { listMeta, err = meta.ListAccessor(obj) if err != nil { return nil, err } } else { listMeta = objectMeta } // if the object referenced is actually persisted, we can also get version from meta version := gvk.GroupVersion().String() if len(version) == 0 { selfLink := listMeta.GetSelfLink() if len(selfLink) == 0 { return nil, ErrNoSelfLink } selfLinkUrl, err := url.Parse(selfLink) if err != nil { return nil, err } // example paths: /<prefix>/<version>/* 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] } // only has list metadata if objectMeta == nil { return &ObjectReference{ Kind: kind, APIVersion: version, ResourceVersion: listMeta.GetResourceVersion(), }, nil } return &ObjectReference{ Kind: kind, APIVersion: version, Name: objectMeta.GetName(), Namespace: objectMeta.GetNamespace(), UID: objectMeta.GetUID(), ResourceVersion: objectMeta.GetResourceVersion(), }, nil }
// ObjectKinds returns a slice of one element with the // group,version,kind of the provided object, or an error if the // object is not *runtime.Unstructured or has no group,version,kind // information. func (ot *ObjectTyper) ObjectKinds(obj runtime.Object) ([]unversioned.GroupVersionKind, bool, error) { if _, ok := obj.(*runtime.Unstructured); !ok { return nil, false, fmt.Errorf("type %T is invalid for dynamic object typer", obj) } return []unversioned.GroupVersionKind{obj.GetObjectKind().GroupVersionKind()}, false, nil }
// Encode serializes the provided object to the given writer. func (s *Serializer) Encode(obj runtime.Object, w io.Writer) error { prefixSize := uint64(len(s.prefix)) var unk runtime.Unknown switch t := obj.(type) { case *runtime.Unknown: estimatedSize := prefixSize + uint64(t.Size()) data := make([]byte, estimatedSize) i, err := t.MarshalTo(data[prefixSize:]) if err != nil { return err } copy(data, s.prefix) _, err = w.Write(data[:prefixSize+uint64(i)]) return err default: kind := obj.GetObjectKind().GroupVersionKind() unk = runtime.Unknown{ TypeMeta: runtime.TypeMeta{ Kind: kind.Kind, APIVersion: kind.GroupVersion().String(), }, } } switch t := obj.(type) { case bufferedMarshaller: // this path performs a single allocation during write but requires the caller to implement // the more efficient Size and MarshalTo methods encodedSize := uint64(t.Size()) estimatedSize := prefixSize + estimateUnknownSize(&unk, encodedSize) data := make([]byte, estimatedSize) i, err := unk.NestedMarshalTo(data[prefixSize:], t, encodedSize) if err != nil { return err } copy(data, s.prefix) _, err = w.Write(data[:prefixSize+uint64(i)]) return err case proto.Marshaler: // this path performs extra allocations data, err := t.Marshal() if err != nil { return err } unk.Raw = data estimatedSize := prefixSize + uint64(unk.Size()) data = make([]byte, estimatedSize) i, err := unk.MarshalTo(data[prefixSize:]) if err != nil { return err } copy(data, s.prefix) _, err = w.Write(data[:prefixSize+uint64(i)]) return err default: // TODO: marshal with a different content type and serializer (JSON for third party objects) return errNotMarshalable{reflect.TypeOf(obj)} } }