Beispiel #1
0
func (o objects) Kind(gvk unversioned.GroupVersionKind, name string) (runtime.Object, error) {
	// TODO our test clients deal in internal versions.  We need to plumb that knowledge down here
	// we might do this via an extra function to the scheme to allow getting internal group versions
	// I'm punting for now
	gvk.Version = ""

	empty, _ := o.scheme.New(gvk.GroupVersion().String(), gvk.Kind)
	nilValue := reflect.Zero(reflect.TypeOf(empty)).Interface().(runtime.Object)

	arr, ok := o.types[gvk.Kind]
	if !ok {
		if strings.HasSuffix(gvk.Kind, "List") {
			itemKind := gvk.Kind[:len(gvk.Kind)-4]
			arr, ok := o.types[itemKind]
			if !ok {
				return empty, nil
			}
			out, err := o.scheme.New(gvk.GroupVersion().String(), gvk.Kind)
			if err != nil {
				return nilValue, err
			}
			if err := meta.SetList(out, arr); err != nil {
				return nilValue, err
			}
			if out, err = o.scheme.Copy(out); err != nil {
				return nilValue, err
			}
			return out, nil
		}
		return nilValue, errors.NewNotFound(gvk.Kind, name)
	}

	index := o.last[gvk.Kind]
	if index >= len(arr) {
		index = len(arr) - 1
	}
	if index < 0 {
		return nilValue, errors.NewNotFound(gvk.Kind, name)
	}
	out, err := o.scheme.Copy(arr[index])
	if err != nil {
		return nilValue, err
	}
	o.last[gvk.Kind] = index + 1

	if status, ok := out.(*unversioned.Status); ok {
		if status.Details != nil {
			status.Details.Kind = gvk.Kind
		}
		if status.Status != unversioned.StatusSuccess {
			return nilValue, &errors.StatusError{ErrStatus: *status}
		}
	}

	return out, nil
}
Beispiel #2
0
// DecodeIntoWithSpecifiedVersionKind compares the passed in requestGroupVersionKind
// with data.Version and data.Kind, defaulting data.Version and
// data.Kind to the specified value if they are empty, or generating an error if
// data.Version and data.Kind are not empty and differ from the specified value.
// The function then implements the functionality of DecodeInto.
// If specifiedVersion and specifiedKind are empty, the function degenerates to
// DecodeInto.
func (s *Scheme) DecodeIntoWithSpecifiedVersionKind(data []byte, obj interface{}, requestedGVK unversioned.GroupVersionKind) error {
	if len(data) == 0 {
		return errors.New("empty input")
	}
	dataVersion, dataKind, err := s.DataVersionAndKind(data)
	if err != nil {
		return err
	}
	if dataVersion == "" {
		dataVersion = requestedGVK.GroupVersion().String()
	}
	if dataKind == "" {
		dataKind = requestedGVK.Kind
	}
	if (len(requestedGVK.Group) > 0 || len(requestedGVK.Version) > 0) && (dataVersion != requestedGVK.GroupVersion().String()) {
		return errors.New(fmt.Sprintf("The apiVersion in the data (%s) does not match the specified apiVersion(%v)", dataVersion, requestedGVK.GroupVersion()))
	}
	if len(requestedGVK.Kind) > 0 && (dataKind != requestedGVK.Kind) {
		return errors.New(fmt.Sprintf("The kind in the data (%s) does not match the specified kind(%v)", dataKind, requestedGVK))
	}

	objVersion, objKind, err := s.ObjectVersionAndKind(obj)
	if err != nil {
		return err
	}
	if dataKind == "" {
		// Assume objects with unset Kind fields are being unmarshalled into the
		// correct type.
		dataKind = objKind
	}
	if dataVersion == "" {
		// Assume objects with unset Version fields are being unmarshalled into the
		// correct type.
		dataVersion = objVersion
	}

	external, err := s.NewObject(dataVersion, dataKind)
	if err != nil {
		return err
	}
	if err := codec.NewDecoderBytes(data, new(codec.JsonHandle)).Decode(external); err != nil {
		return err
	}
	flags, meta := s.generateConvertMeta(dataVersion, objVersion, external)
	if err := s.converter.Convert(external, obj, flags, meta); err != nil {
		return err
	}

	// Version and Kind should be blank in memory.
	return s.SetVersionAndKind("", "", obj)
}
Beispiel #3
0
// RESTMapping returns a struct representing the resource path and conversion interfaces a
// RESTClient should use to operate on the provided group/kind in order of versions. If a version search
// order is not provided, the search order provided to DefaultRESTMapper will be used to resolve which
// version should be used to access the named group/kind.
func (m *DefaultRESTMapper) RESTMapping(gk unversioned.GroupKind, versions ...string) (*RESTMapping, error) {
	// Pick an appropriate version
	var gvk *unversioned.GroupVersionKind
	hadVersion := false
	for _, version := range versions {
		if len(version) == 0 {
			continue
		}

		currGVK := gk.WithVersion(version)
		hadVersion = true
		if _, ok := m.kindToPluralResource[currGVK]; ok {
			gvk = &currGVK
			break
		}
	}
	// Use the default preferred versions
	if !hadVersion && (gvk == nil) {
		for _, gv := range m.defaultGroupVersions {
			if gv.Group != gk.Group {
				continue
			}

			currGVK := gk.WithVersion(gv.Version)
			if _, ok := m.kindToPluralResource[currGVK]; ok {
				gvk = &currGVK
				break
			}
		}
	}
	if gvk == nil {
		return nil, fmt.Errorf("no kind named %q is registered in versions %q", gk, versions)
	}

	// Ensure we have a REST mapping
	resource, ok := m.kindToPluralResource[*gvk]
	if !ok {
		found := []unversioned.GroupVersion{}
		for _, gv := range m.defaultGroupVersions {
			if _, ok := m.kindToPluralResource[*gvk]; ok {
				found = append(found, gv)
			}
		}
		if len(found) > 0 {
			return nil, fmt.Errorf("object with kind %q exists in versions %v, not %v", gvk.Kind, found, gvk.GroupVersion().String())
		}
		return nil, fmt.Errorf("the provided version %q and kind %q cannot be mapped to a supported object", gvk.GroupVersion().String(), gvk.Kind)
	}

	// Ensure we have a REST scope
	scope, ok := m.kindToScope[*gvk]
	if !ok {
		return nil, fmt.Errorf("the provided version %q and kind %q cannot be mapped to a supported scope", gvk.GroupVersion().String(), gvk.Kind)
	}

	interfaces, err := m.interfacesFunc(gvk.GroupVersion().String())
	if err != nil {
		return nil, fmt.Errorf("the provided version %q has no relevant versions", gvk.GroupVersion().String())
	}

	retVal := &RESTMapping{
		Resource:         resource,
		GroupVersionKind: *gvk,
		Scope:            scope,

		Codec:            interfaces.Codec,
		ObjectConvertor:  interfaces.ObjectConvertor,
		MetadataAccessor: interfaces.MetadataAccessor,
	}

	return retVal, nil
}