json.go 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245
  1. /*
  2. Copyright 2014 The Kubernetes Authors.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. package json
  14. import (
  15. "encoding/json"
  16. "io"
  17. "github.com/ghodss/yaml"
  18. "github.com/ugorji/go/codec"
  19. "k8s.io/kubernetes/pkg/api/unversioned"
  20. "k8s.io/kubernetes/pkg/runtime"
  21. "k8s.io/kubernetes/pkg/runtime/serializer/recognizer"
  22. "k8s.io/kubernetes/pkg/util/framer"
  23. utilyaml "k8s.io/kubernetes/pkg/util/yaml"
  24. )
  25. // NewSerializer creates a JSON serializer that handles encoding versioned objects into the proper JSON form. If typer
  26. // is not nil, the object has the group, version, and kind fields set.
  27. func NewSerializer(meta MetaFactory, creater runtime.ObjectCreater, typer runtime.ObjectTyper, pretty bool) *Serializer {
  28. return &Serializer{
  29. meta: meta,
  30. creater: creater,
  31. typer: typer,
  32. yaml: false,
  33. pretty: pretty,
  34. }
  35. }
  36. // NewYAMLSerializer creates a YAML serializer that handles encoding versioned objects into the proper YAML form. If typer
  37. // is not nil, the object has the group, version, and kind fields set. This serializer supports only the subset of YAML that
  38. // matches JSON, and will error if constructs are used that do not serialize to JSON.
  39. func NewYAMLSerializer(meta MetaFactory, creater runtime.ObjectCreater, typer runtime.ObjectTyper) *Serializer {
  40. return &Serializer{
  41. meta: meta,
  42. creater: creater,
  43. typer: typer,
  44. yaml: true,
  45. }
  46. }
  47. type Serializer struct {
  48. meta MetaFactory
  49. creater runtime.ObjectCreater
  50. typer runtime.ObjectTyper
  51. yaml bool
  52. pretty bool
  53. }
  54. // Serializer implements Serializer
  55. var _ runtime.Serializer = &Serializer{}
  56. var _ recognizer.RecognizingDecoder = &Serializer{}
  57. // Decode attempts to convert the provided data into YAML or JSON, extract the stored schema kind, apply the provided default gvk, and then
  58. // 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
  59. // extracted and no decoding will be performed. If into is not registered with the typer, then the object will be straight decoded using
  60. // normal JSON/YAML unmarshalling. If into is provided and the original data is not fully qualified with kind/version/group, the type of
  61. // the into will be used to alter the returned gvk. On success or most errors, the method will return the calculated schema kind.
  62. func (s *Serializer) Decode(originalData []byte, gvk *unversioned.GroupVersionKind, into runtime.Object) (runtime.Object, *unversioned.GroupVersionKind, error) {
  63. if versioned, ok := into.(*runtime.VersionedObjects); ok {
  64. into = versioned.Last()
  65. obj, actual, err := s.Decode(originalData, gvk, into)
  66. if err != nil {
  67. return nil, actual, err
  68. }
  69. versioned.Objects = []runtime.Object{obj}
  70. return versioned, actual, nil
  71. }
  72. data := originalData
  73. if s.yaml {
  74. altered, err := yaml.YAMLToJSON(data)
  75. if err != nil {
  76. return nil, nil, err
  77. }
  78. data = altered
  79. }
  80. actual, err := s.meta.Interpret(data)
  81. if err != nil {
  82. return nil, nil, err
  83. }
  84. if gvk != nil {
  85. // apply kind and version defaulting from provided default
  86. if len(actual.Kind) == 0 {
  87. actual.Kind = gvk.Kind
  88. }
  89. if len(actual.Version) == 0 && len(actual.Group) == 0 {
  90. actual.Group = gvk.Group
  91. actual.Version = gvk.Version
  92. }
  93. if len(actual.Version) == 0 && actual.Group == gvk.Group {
  94. actual.Version = gvk.Version
  95. }
  96. }
  97. if unk, ok := into.(*runtime.Unknown); ok && unk != nil {
  98. unk.Raw = originalData
  99. unk.ContentType = runtime.ContentTypeJSON
  100. unk.GetObjectKind().SetGroupVersionKind(*actual)
  101. return unk, actual, nil
  102. }
  103. if into != nil {
  104. types, _, err := s.typer.ObjectKinds(into)
  105. switch {
  106. case runtime.IsNotRegisteredError(err):
  107. if err := codec.NewDecoderBytes(data, new(codec.JsonHandle)).Decode(into); err != nil {
  108. return nil, actual, err
  109. }
  110. return into, actual, nil
  111. case err != nil:
  112. return nil, actual, err
  113. default:
  114. typed := types[0]
  115. if len(actual.Kind) == 0 {
  116. actual.Kind = typed.Kind
  117. }
  118. if len(actual.Version) == 0 && len(actual.Group) == 0 {
  119. actual.Group = typed.Group
  120. actual.Version = typed.Version
  121. }
  122. if len(actual.Version) == 0 && actual.Group == typed.Group {
  123. actual.Version = typed.Version
  124. }
  125. }
  126. }
  127. if len(actual.Kind) == 0 {
  128. return nil, actual, runtime.NewMissingKindErr(string(originalData))
  129. }
  130. if len(actual.Version) == 0 {
  131. return nil, actual, runtime.NewMissingVersionErr(string(originalData))
  132. }
  133. // use the target if necessary
  134. obj, err := runtime.UseOrCreateObject(s.typer, s.creater, *actual, into)
  135. if err != nil {
  136. return nil, actual, err
  137. }
  138. if err := codec.NewDecoderBytes(data, new(codec.JsonHandle)).Decode(obj); err != nil {
  139. return nil, actual, err
  140. }
  141. return obj, actual, nil
  142. }
  143. // Encode serializes the provided object to the given writer.
  144. func (s *Serializer) Encode(obj runtime.Object, w io.Writer) error {
  145. if s.yaml {
  146. json, err := json.Marshal(obj)
  147. if err != nil {
  148. return err
  149. }
  150. data, err := yaml.JSONToYAML(json)
  151. if err != nil {
  152. return err
  153. }
  154. _, err = w.Write(data)
  155. return err
  156. }
  157. if s.pretty {
  158. data, err := json.MarshalIndent(obj, "", " ")
  159. if err != nil {
  160. return err
  161. }
  162. _, err = w.Write(data)
  163. return err
  164. }
  165. encoder := json.NewEncoder(w)
  166. return encoder.Encode(obj)
  167. }
  168. // RecognizesData implements the RecognizingDecoder interface.
  169. func (s *Serializer) RecognizesData(peek io.Reader) (ok, unknown bool, err error) {
  170. if s.yaml {
  171. // we could potentially look for '---'
  172. return false, true, nil
  173. }
  174. _, ok = utilyaml.GuessJSONStream(peek, 2048)
  175. return ok, false, nil
  176. }
  177. // Framer is the default JSON framing behavior, with newlines delimiting individual objects.
  178. var Framer = jsonFramer{}
  179. type jsonFramer struct{}
  180. // NewFrameWriter implements stream framing for this serializer
  181. func (jsonFramer) NewFrameWriter(w io.Writer) io.Writer {
  182. // we can write JSON objects directly to the writer, because they are self-framing
  183. return w
  184. }
  185. // NewFrameReader implements stream framing for this serializer
  186. func (jsonFramer) NewFrameReader(r io.ReadCloser) io.ReadCloser {
  187. // we need to extract the JSON chunks of data to pass to Decode()
  188. return framer.NewJSONFramedReader(r)
  189. }
  190. // Framer is the default JSON framing behavior, with newlines delimiting individual objects.
  191. var YAMLFramer = yamlFramer{}
  192. type yamlFramer struct{}
  193. // NewFrameWriter implements stream framing for this serializer
  194. func (yamlFramer) NewFrameWriter(w io.Writer) io.Writer {
  195. return yamlFrameWriter{w}
  196. }
  197. // NewFrameReader implements stream framing for this serializer
  198. func (yamlFramer) NewFrameReader(r io.ReadCloser) io.ReadCloser {
  199. // extract the YAML document chunks directly
  200. return utilyaml.NewDocumentDecoder(r)
  201. }
  202. type yamlFrameWriter struct {
  203. w io.Writer
  204. }
  205. // Write separates each document with the YAML document separator (`---` followed by line
  206. // break). Writers must write well formed YAML documents (include a final line break).
  207. func (w yamlFrameWriter) Write(data []byte) (n int, err error) {
  208. if _, err := w.w.Write([]byte("---\n")); err != nil {
  209. return 0, err
  210. }
  211. return w.w.Write(data)
  212. }