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 }
// Decode attempts to convert the provided data into YAML or JSON, extract the stored schema kind, apply the provided default gvk, and then // load that data into an object matching the desired schema kind or the provided into. If into is *runtime.Unknown, the raw data will be // extracted and no decoding will be performed. If into is not registered with the typer, then the object will be straight decoded using // normal JSON/YAML unmarshalling. If into is provided and the original data is not fully qualified with kind/version/group, the type of // the into will be used to alter the returned gvk. On success or most errors, the method will return the calculated schema kind. func (s *Serializer) Decode(originalData []byte, gvk *schema.GroupVersionKind, into runtime.Object) (runtime.Object, *schema.GroupVersionKind, error) { if versioned, ok := into.(*runtime.VersionedObjects); ok { into = versioned.Last() obj, actual, err := s.Decode(originalData, gvk, into) if err != nil { return nil, actual, err } versioned.Objects = []runtime.Object{obj} return versioned, actual, nil } data := originalData if s.yaml { altered, err := yaml.YAMLToJSON(data) if err != nil { return nil, nil, err } data = altered } actual, err := s.meta.Interpret(data) if err != nil { return nil, nil, err } if gvk != nil { // apply kind and version defaulting from provided default if len(actual.Kind) == 0 { actual.Kind = gvk.Kind } if len(actual.Version) == 0 && len(actual.Group) == 0 { actual.Group = gvk.Group actual.Version = gvk.Version } if len(actual.Version) == 0 && actual.Group == gvk.Group { actual.Version = gvk.Version } } if unk, ok := into.(*runtime.Unknown); ok && unk != nil { unk.Raw = originalData unk.ContentType = runtime.ContentTypeJSON unk.GetObjectKind().SetGroupVersionKind(*actual) return unk, actual, nil } if into != nil { types, _, err := s.typer.ObjectKinds(into) switch { case runtime.IsNotRegisteredError(err): if err := codec.NewDecoderBytes(data, new(codec.JsonHandle)).Decode(into); err != nil { return nil, actual, err } return into, actual, nil case err != nil: return nil, actual, err default: typed := types[0] if len(actual.Kind) == 0 { actual.Kind = typed.Kind } if len(actual.Version) == 0 && len(actual.Group) == 0 { actual.Group = typed.Group actual.Version = typed.Version } if len(actual.Version) == 0 && actual.Group == typed.Group { actual.Version = typed.Version } } } if len(actual.Kind) == 0 { return nil, actual, runtime.NewMissingKindErr(string(originalData)) } if len(actual.Version) == 0 { return nil, actual, runtime.NewMissingVersionErr(string(originalData)) } // use the target if necessary obj, err := runtime.UseOrCreateObject(s.typer, s.creater, *actual, into) if err != nil { return nil, actual, err } if err := codec.NewDecoderBytes(data, new(codec.JsonHandle)).Decode(obj); err != nil { return nil, actual, err } return obj, actual, nil }
func (t *thirdPartyResourceDataDecoder) Decode(data []byte, gvk *schema.GroupVersionKind, into runtime.Object) (runtime.Object, *schema.GroupVersionKind, error) { if into == nil { if gvk == nil || gvk.Kind != t.kind { if isThirdParty, _, err := IsThirdPartyObject(data, gvk); err != nil { return nil, nil, err } else if !isThirdParty { return t.delegate.Decode(data, gvk, into) } } return t.populate(data) } switch o := into.(type) { case *extensions.ThirdPartyResourceData: break case *runtime.VersionedObjects: // We're not sure that it's third party, we need to test if gvk == nil || gvk.Kind != t.kind { if isThirdParty, _, err := IsThirdPartyObject(data, gvk); err != nil { return nil, nil, err } else if !isThirdParty { return t.delegate.Decode(data, gvk, into) } } obj, outGVK, err := t.populate(data) if err != nil { return nil, nil, err } o.Objects = []runtime.Object{ obj, } return o, outGVK, nil default: if gvk != nil && api.Registry.IsThirdPartyAPIGroupVersion(gvk.GroupVersion()) { // delegate won't recognize a thirdparty group version gvk = nil } return t.delegate.Decode(data, gvk, into) } thirdParty := into.(*extensions.ThirdPartyResourceData) var dataObj interface{} if err := json.Unmarshal(data, &dataObj); err != nil { return nil, nil, err } mapObj, ok := dataObj.(map[string]interface{}) if !ok { return nil, nil, fmt.Errorf("unexpected object: %#v", dataObj) } /*if gvk.Kind != "ThirdPartyResourceData" { return nil, nil, fmt.Errorf("unexpected kind: %s", gvk.Kind) }*/ actual := &schema.GroupVersionKind{} if kindObj, found := mapObj["kind"]; !found { if gvk == nil { return nil, nil, runtime.NewMissingKindErr(string(data)) } mapObj["kind"] = gvk.Kind actual.Kind = gvk.Kind } else { kindStr, ok := kindObj.(string) if !ok { return nil, nil, fmt.Errorf("unexpected object for 'kind': %v", kindObj) } if len(t.kind) > 0 && kindStr != t.kind { return nil, nil, fmt.Errorf("kind doesn't match, expecting: %s, got %s", t.kind, kindStr) } actual.Kind = kindStr } if versionObj, found := mapObj["apiVersion"]; !found { if gvk == nil { return nil, nil, runtime.NewMissingVersionErr(string(data)) } mapObj["apiVersion"] = gvk.GroupVersion().String() actual.Group, actual.Version = gvk.Group, gvk.Version } else { versionStr, ok := versionObj.(string) if !ok { return nil, nil, fmt.Errorf("unexpected object for 'apiVersion': %v", versionObj) } if gvk != nil && versionStr != gvk.GroupVersion().String() { return nil, nil, fmt.Errorf("version doesn't match, expecting: %v, got %s", gvk.GroupVersion(), versionStr) } gv, err := schema.ParseGroupVersion(versionStr) if err != nil { return nil, nil, err } actual.Group, actual.Version = gv.Group, gv.Version } mapObj, err := parseObject(data) if err != nil { return nil, actual, err } if err := t.populateResource(thirdParty, mapObj, data); err != nil { return nil, actual, err } return thirdParty, actual, nil }
// Decode attempts to convert the provided data into a protobuf message, extract the stored schema kind, apply the provided default // gvk, and then load that data into an object matching the desired schema kind or the provided into. If into is *runtime.Unknown, // the raw data will be extracted and no decoding will be performed. If into is not registered with the typer, then the object will // be straight decoded using normal protobuf unmarshalling (the MarshalTo interface). If into is provided and the original data is // not fully qualified with kind/version/group, the type of the into will be used to alter the returned gvk. On success or most // errors, the method will return the calculated schema kind. func (s *Serializer) Decode(originalData []byte, gvk *schema.GroupVersionKind, into runtime.Object) (runtime.Object, *schema.GroupVersionKind, error) { if versioned, ok := into.(*runtime.VersionedObjects); ok { into = versioned.Last() obj, actual, err := s.Decode(originalData, gvk, into) if err != nil { return nil, actual, err } // the last item in versioned becomes into, so if versioned was not originally empty we reset the object // array so the first position is the decoded object and the second position is the outermost object. // if there were no objects in the versioned list passed to us, only add ourselves. if into != nil && into != obj { versioned.Objects = []runtime.Object{obj, into} } else { versioned.Objects = []runtime.Object{obj} } return versioned, actual, err } prefixLen := len(s.prefix) switch { case len(originalData) == 0: // TODO: treat like decoding {} from JSON with defaulting return nil, nil, fmt.Errorf("empty data") case len(originalData) < prefixLen || !bytes.Equal(s.prefix, originalData[:prefixLen]): return nil, nil, fmt.Errorf("provided data does not appear to be a protobuf message, expected prefix %v", s.prefix) case len(originalData) == prefixLen: // TODO: treat like decoding {} from JSON with defaulting return nil, nil, fmt.Errorf("empty body") } data := originalData[prefixLen:] unk := runtime.Unknown{} if err := unk.Unmarshal(data); err != nil { return nil, nil, err } actual := unk.GroupVersionKind() copyKindDefaults(&actual, gvk) if intoUnknown, ok := into.(*runtime.Unknown); ok && intoUnknown != nil { *intoUnknown = unk if ok, _, _ := s.RecognizesData(bytes.NewBuffer(unk.Raw)); ok { intoUnknown.ContentType = s.contentType } return intoUnknown, &actual, nil } if into != nil { types, _, err := s.typer.ObjectKinds(into) switch { case runtime.IsNotRegisteredError(err): pb, ok := into.(proto.Message) if !ok { return nil, &actual, errNotMarshalable{reflect.TypeOf(into)} } if err := proto.Unmarshal(unk.Raw, pb); err != nil { return nil, &actual, err } return into, &actual, nil case err != nil: return nil, &actual, err default: copyKindDefaults(&actual, &types[0]) // if the result of defaulting did not set a version or group, ensure that at least group is set // (copyKindDefaults will not assign Group if version is already set). This guarantees that the group // of into is set if there is no better information from the caller or object. if len(actual.Version) == 0 && len(actual.Group) == 0 { actual.Group = types[0].Group } } } if len(actual.Kind) == 0 { return nil, &actual, runtime.NewMissingKindErr(fmt.Sprintf("%#v", unk.TypeMeta)) } if len(actual.Version) == 0 { return nil, &actual, runtime.NewMissingVersionErr(fmt.Sprintf("%#v", unk.TypeMeta)) } return unmarshalToObject(s.typer, s.creater, &actual, into, unk.Raw) }
// Decode attempts to convert the provided data into a protobuf message, extract the stored schema kind, apply the provided default // gvk, and then load that data into an object matching the desired schema kind or the provided into. If into is *runtime.Unknown, // the raw data will be extracted and no decoding will be performed. If into is not registered with the typer, then the object will // be straight decoded using normal protobuf unmarshalling (the MarshalTo interface). If into is provided and the original data is // not fully qualified with kind/version/group, the type of the into will be used to alter the returned gvk. On success or most // errors, the method will return the calculated schema kind. func (s *RawSerializer) Decode(originalData []byte, gvk *schema.GroupVersionKind, into runtime.Object) (runtime.Object, *schema.GroupVersionKind, error) { if into == nil { return nil, nil, fmt.Errorf("this serializer requires an object to decode into: %#v", s) } if versioned, ok := into.(*runtime.VersionedObjects); ok { into = versioned.Last() obj, actual, err := s.Decode(originalData, gvk, into) if err != nil { return nil, actual, err } if into != nil && into != obj { versioned.Objects = []runtime.Object{obj, into} } else { versioned.Objects = []runtime.Object{obj} } return versioned, actual, err } if len(originalData) == 0 { // TODO: treat like decoding {} from JSON with defaulting return nil, nil, fmt.Errorf("empty data") } data := originalData actual := &schema.GroupVersionKind{} copyKindDefaults(actual, gvk) if intoUnknown, ok := into.(*runtime.Unknown); ok && intoUnknown != nil { intoUnknown.Raw = data intoUnknown.ContentEncoding = "" intoUnknown.ContentType = s.contentType intoUnknown.SetGroupVersionKind(*actual) return intoUnknown, actual, nil } types, _, err := s.typer.ObjectKinds(into) switch { case runtime.IsNotRegisteredError(err): pb, ok := into.(proto.Message) if !ok { return nil, actual, errNotMarshalable{reflect.TypeOf(into)} } if err := proto.Unmarshal(data, pb); err != nil { return nil, actual, err } return into, actual, nil case err != nil: return nil, actual, err default: copyKindDefaults(actual, &types[0]) // if the result of defaulting did not set a version or group, ensure that at least group is set // (copyKindDefaults will not assign Group if version is already set). This guarantees that the group // of into is set if there is no better information from the caller or object. if len(actual.Version) == 0 && len(actual.Group) == 0 { actual.Group = types[0].Group } } if len(actual.Kind) == 0 { return nil, actual, runtime.NewMissingKindErr("<protobuf encoded body - must provide default type>") } if len(actual.Version) == 0 { return nil, actual, runtime.NewMissingVersionErr("<protobuf encoded body - must provide default type>") } return unmarshalToObject(s.typer, s.creater, actual, into, data) }