Example #1
0
// 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
}
Example #2
0
// 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
}
Example #3
0
// 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
}
Example #4
0
// 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)}
	}
}
Example #5
0
// 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
}
Example #6
0
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
}
Example #7
0
// 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
}
Example #8
0
// 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
}
Example #9
0
// 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
}
Example #10
0
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
}
Example #11
0
// 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...)
}
Example #12
0
// 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
}
Example #13
0
// 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
}
Example #14
0
func (s *mockSerializer) Encode(obj runtime.Object, w io.Writer) error {
	s.obj = obj
	s.encodingObjGVK = obj.GetObjectKind().GroupVersionKind()
	return s.err
}
Example #15
0
// 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
}