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 }
// 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) }
// 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 }