// AsVersionedObject converts a list of infos into a single object - either a List containing // the objects as children, or if only a single Object is present, as that object. The provided // version will be preferred as the conversion target, but the Object's mapping version will be // used if that version is not present. func AsVersionedObject(infos []*Info, forceList bool, version unversioned.GroupVersion, encoder runtime.Encoder) (runtime.Object, error) { objects, err := AsVersionedObjects(infos, version, encoder) if err != nil { return nil, err } var object runtime.Object if len(objects) == 1 && !forceList { object = objects[0] } else { object = &api.List{Items: objects} converted, err := TryConvert(api.Scheme, object, version, registered.GroupOrDie(api.GroupName).GroupVersion) if err != nil { return nil, err } object = converted } // validSpecifiedVersion resolves to true if the version passed to this function matches the // version assigned to the converted object actualVersion := object.GetObjectKind().GroupVersionKind() if actualVersion.Version != version.Version { defaultVersionInfo := "" if len(actualVersion.Version) > 0 { defaultVersionInfo = fmt.Sprintf("Defaulting to %q", actualVersion.Version) } glog.V(1).Infof("info: the output version specified is invalid. %s\n", defaultVersionInfo) } return object, nil }
// 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 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 t := obj.(type) { case *runtime.Unknown: if gv, ok := runtime.PreferredGroupVersion(c.encodeVersion); ok { t.APIVersion = gv.String() } return c.encoder.Encode(obj, w) case *runtime.Unstructured: if gv, ok := runtime.PreferredGroupVersion(c.encodeVersion); ok { t.SetAPIVersion(gv.String()) } return c.encoder.Encode(obj, w) case *runtime.UnstructuredList: if gv, ok := runtime.PreferredGroupVersion(c.encodeVersion); ok { t.SetAPIVersion(gv.String()) } 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 := obj.(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 }
// EncodeToStream serializes the provided object to the given writer. Overrides is ignored. func (s *Serializer) EncodeToStream(obj runtime.Object, w io.Writer, overrides ...unversioned.GroupVersion) error { var unk runtime.Unknown if kind := obj.GetObjectKind().GroupVersionKind(); kind != nil { unk = runtime.Unknown{ TypeMeta: runtime.TypeMeta{ Kind: kind.Kind, APIVersion: kind.GroupVersion().String(), }, } } prefixSize := uint64(len(s.prefix)) 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)} } }
// 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 } meta, err := meta.Accessor(obj) if err != nil { return nil, err } 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 := Scheme.ObjectKinds(obj) if err != nil { return nil, err } kind = gvks[0].Kind } // if the object referenced is actually persisted, we can also get version from meta version := gvk.GroupVersion().String() if len(version) == 0 { selfLink := meta.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] } return &ObjectReference{ Kind: kind, APIVersion: version, Name: meta.GetName(), Namespace: meta.GetNamespace(), UID: meta.GetUID(), ResourceVersion: meta.GetResourceVersion(), }, nil }
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 { // TODO: should this be a typed error? return nil, fmt.Errorf("%v is unstructured and is not suitable for converting to %q", kind, target) } in.GetObjectKind().SetGroupVersionKind(gvk) } return in, nil }
// EncodeToStream does not do conversion. It sets the gvk during serialization. overrides are ignored. func (c DirectCodec) Encode(obj runtime.Object, stream io.Writer) error { gvks, _, err := c.ObjectTyper.ObjectKinds(obj) if err != nil { return err } kind := obj.GetObjectKind() oldGVK := kind.GroupVersionKind() kind.SetGroupVersionKind(gvks[0]) err = c.Serializer.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 { if _, ok := obj.(*runtime.Unknown); ok { return c.encoder.Encode(obj, w) } gvks, isUnversioned, err := c.typer.ObjectKinds(obj) if err != nil { return err } gvk := gvks[0] if c.encodeVersion == nil || isUnversioned { objectKind := obj.GetObjectKind() old := objectKind.GroupVersionKind() objectKind.SetGroupVersionKind(gvk) err = c.encoder.Encode(obj, w) objectKind.SetGroupVersionKind(old) return err } targetGV, ok := c.encodeVersion[gvk.Group] // attempt a conversion to the sole encode version if !ok && c.preferredEncodeVersion != nil { ok = true targetGV = c.preferredEncodeVersion[0] } // if no fallback is available, error if !ok { return fmt.Errorf("the codec does not recognize group %q for kind %q and cannot encode it", gvk.Group, gvk.Kind) } // Perform a conversion if necessary objectKind := obj.GetObjectKind() old := objectKind.GroupVersionKind() out, err := c.convertor.ConvertToVersion(obj, targetGV) if err != nil { if ok { return err } } else { obj = out } // Conversion is responsible for setting the proper group, version, and kind onto the outgoing object err = c.encoder.Encode(obj, w) // restore the old GVK, in case conversion returned the same object objectKind.SetGroupVersionKind(old) return err }
// 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 }
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) } else { obj, err = s.decode(data) } if err != nil { return nil, nil, err } gvk := obj.GetObjectKind().GroupVersionKind() if len(gvk.Kind) == 0 { return nil, &gvk, runtime.NewMissingKindErr(string(data)) } return obj, &gvk, nil }
// EncodeToStream ensures the provided object is output in the right scheme. If overrides are specified, when // encoding the object the first override that matches the object's group is used. Other overrides are ignored. func (c *codec) EncodeToStream(obj runtime.Object, w io.Writer, overrides ...unversioned.GroupVersion) error { if _, ok := obj.(*runtime.Unknown); ok { return c.encoder.EncodeToStream(obj, w, overrides...) } gvk, isUnversioned, err := c.typer.ObjectKind(obj) if err != nil { return err } if (c.encodeVersion == nil && len(overrides) == 0) || isUnversioned { old := obj.GetObjectKind().GroupVersionKind() obj.GetObjectKind().SetGroupVersionKind(gvk) defer obj.GetObjectKind().SetGroupVersionKind(old) return c.encoder.EncodeToStream(obj, w, overrides...) } targetGV, ok := c.encodeVersion[gvk.Group] // use override if provided for i, override := range overrides { if override.Group == gvk.Group { ok = true targetGV = override // swap the position of the override overrides[0], overrides[i] = targetGV, overrides[0] break } } // attempt a conversion to the sole encode version if !ok && len(c.encodeVersion) == 1 { ok = true for _, v := range c.encodeVersion { targetGV = v } // ensure the target override is first overrides = promoteOrPrependGroupVersion(targetGV, overrides) } // if no fallback is available, error if !ok { return fmt.Errorf("the codec does not recognize group %q for kind %q and cannot encode it", gvk.Group, gvk.Kind) } old := obj.GetObjectKind().GroupVersionKind() defer obj.GetObjectKind().SetGroupVersionKind(old) // Perform a conversion if necessary if gvk.GroupVersion() != targetGV { out, err := c.convertor.ConvertToVersion(obj, targetGV.String()) if err != nil { if ok { return err } } else { obj = out } } else { obj.GetObjectKind().SetGroupVersionKind(&unversioned.GroupVersionKind{Group: targetGV.Group, Version: targetGV.Version, Kind: gvk.Kind}) } return c.encoder.EncodeToStream(obj, w, overrides...) }
// 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) ([]schema.GroupVersionKind, bool, error) { if _, ok := obj.(*runtime.Unstructured); !ok { return nil, false, fmt.Errorf("type %T is invalid for dynamic object typer", obj) } return []schema.GroupVersionKind{obj.GetObjectKind().GroupVersionKind()}, false, nil }
// AddObjectAnnotations adds new annotation(s) to a single runtime.Object func AddObjectAnnotations(obj runtime.Object, annotations map[string]string) error { if len(annotations) == 0 { return nil } accessor, err := kmeta.Accessor(obj) if err != nil { if _, ok := obj.(*runtime.Unstructured); !ok { // error out if it's not possible to get an accessor and it's also not an unstructured object return err } } else { metaAnnotations := accessor.GetAnnotations() if metaAnnotations == nil { metaAnnotations = make(map[string]string) } switch objType := obj.(type) { case *deployapi.DeploymentConfig: if err := addDeploymentConfigNestedAnnotations(objType, annotations); err != nil { return fmt.Errorf("unable to add nested annotations to %s/%s: %v", obj.GetObjectKind().GroupVersionKind(), accessor.GetName(), err) } } MergeInto(metaAnnotations, annotations, OverwriteExistingDstKey) accessor.SetAnnotations(metaAnnotations) return nil } // handle unstructured object // TODO: allow meta.Accessor to handle runtime.Unstructured if unstruct, ok := obj.(*runtime.Unstructured); ok && unstruct.Object != nil { // the presence of "metadata" is sufficient for us to apply the rules for Kube-like // objects. // TODO: add swagger detection to allow this to happen more effectively if obj, ok := unstruct.Object["metadata"]; ok { if m, ok := obj.(map[string]interface{}); ok { existing := make(map[string]string) if l, ok := m["annotations"]; ok { if found, ok := interfaceToStringMap(l); ok { existing = found } } if err := MergeInto(existing, annotations, OverwriteExistingDstKey); err != nil { return err } m["annotations"] = mapToGeneric(existing) } return nil } // only attempt to set root annotations if a root object called annotations exists // TODO: add swagger detection to allow this to happen more effectively if obj, ok := unstruct.Object["annotations"]; ok { existing := make(map[string]string) if found, ok := interfaceToStringMap(obj); ok { existing = found } if err := MergeInto(existing, annotations, OverwriteExistingDstKey); err != nil { return err } unstruct.Object["annotations"] = mapToGeneric(existing) return nil } } return nil }
func (s *mockSerializer) Encode(obj runtime.Object, w io.Writer) error { s.obj = obj s.encodingObjGVK = obj.GetObjectKind().GroupVersionKind() return s.err }
// EncodeToStream ensures the provided object is output in the right scheme. If overrides are specified, when // encoding the object the first override that matches the object's group is used. Other overrides are ignored. func (c *codec) EncodeToStream(obj runtime.Object, w io.Writer, overrides ...unversioned.GroupVersion) error { if _, ok := obj.(*runtime.Unknown); ok { return c.encoder.EncodeToStream(obj, w, overrides...) } gvk, isUnversioned, err := c.typer.ObjectKind(obj) if err != nil { return err } if (c.encodeVersion == nil && len(overrides) == 0) || isUnversioned { objectKind := obj.GetObjectKind() old := objectKind.GroupVersionKind() objectKind.SetGroupVersionKind(*gvk) err = c.encoder.EncodeToStream(obj, w, overrides...) objectKind.SetGroupVersionKind(old) return err } targetGV, ok := c.encodeVersion[gvk.Group] // use override if provided for i, override := range overrides { if override.Group == gvk.Group { ok = true targetGV = override // swap the position of the override overrides[0], overrides[i] = targetGV, overrides[0] break } } // attempt a conversion to the sole encode version if !ok && len(c.encodeVersion) == 1 { ok = true for _, v := range c.encodeVersion { targetGV = v } // ensure the target override is first overrides = promoteOrPrependGroupVersion(targetGV, overrides) } // if no fallback is available, error if !ok { return fmt.Errorf("the codec does not recognize group %q for kind %q and cannot encode it", gvk.Group, gvk.Kind) } // Perform a conversion if necessary objectKind := obj.GetObjectKind() old := objectKind.GroupVersionKind() out, err := c.convertor.ConvertToVersion(obj, targetGV) if err != nil { if ok { return err } } else { obj = out } // Conversion is responsible for setting the proper group, version, and kind onto the outgoing object err = c.encoder.EncodeToStream(obj, w, overrides...) // restore the old GVK, in case conversion returned the same object objectKind.SetGroupVersionKind(old) return err }