diff --git a/staging/src/k8s.io/apimachinery/pkg/apis/meta/v1/unstructured/BUILD b/staging/src/k8s.io/apimachinery/pkg/apis/meta/v1/unstructured/BUILD index 3450d869db7..ceeb848d2ba 100644 --- a/staging/src/k8s.io/apimachinery/pkg/apis/meta/v1/unstructured/BUILD +++ b/staging/src/k8s.io/apimachinery/pkg/apis/meta/v1/unstructured/BUILD @@ -44,6 +44,7 @@ go_library( "//staging/src/k8s.io/apimachinery/pkg/types:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/util/json:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/util/runtime:go_default_library", + "//vendor/k8s.io/klog:go_default_library", ], ) diff --git a/staging/src/k8s.io/apimachinery/pkg/apis/meta/v1/unstructured/helpers.go b/staging/src/k8s.io/apimachinery/pkg/apis/meta/v1/unstructured/helpers.go index e80824bdf86..12c078025ea 100644 --- a/staging/src/k8s.io/apimachinery/pkg/apis/meta/v1/unstructured/helpers.go +++ b/staging/src/k8s.io/apimachinery/pkg/apis/meta/v1/unstructured/helpers.go @@ -27,6 +27,7 @@ import ( "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/util/json" + "k8s.io/klog" ) // NestedFieldCopy returns a deep copy of the value of a nested field. @@ -329,6 +330,8 @@ var UnstructuredJSONScheme runtime.Codec = unstructuredJSONScheme{} type unstructuredJSONScheme struct{} +const unstructuredJSONSchemeIdentifier runtime.Identifier = "unstructuredJSON" + func (s unstructuredJSONScheme) Decode(data []byte, _ *schema.GroupVersionKind, obj runtime.Object) (runtime.Object, *schema.GroupVersionKind, error) { var err error if obj != nil { @@ -373,6 +376,11 @@ func (unstructuredJSONScheme) Encode(obj runtime.Object, w io.Writer) error { } } +// Identifier implements runtime.Encoder interface. +func (unstructuredJSONScheme) Identifier() runtime.Identifier { + return unstructuredJSONSchemeIdentifier +} + func (s unstructuredJSONScheme) decode(data []byte) (runtime.Object, error) { type detector struct { Items gojson.RawMessage @@ -461,16 +469,28 @@ func (s unstructuredJSONScheme) decodeToList(data []byte, list *UnstructuredList } type jsonFallbackEncoder struct { - encoder runtime.Encoder + encoder runtime.Encoder + identifier runtime.Identifier } func NewJSONFallbackEncoder(encoder runtime.Encoder) runtime.Encoder { + result := map[string]string{ + "name": "fallback", + "base": string(encoder.Identifier()), + } + identifier, err := gojson.Marshal(result) + if err != nil { + klog.Fatalf("Failed marshaling identifier for jsonFallbackEncoder: %v", err) + } return &jsonFallbackEncoder{ - encoder: encoder, + encoder: encoder, + identifier: runtime.Identifier(identifier), } } func (c *jsonFallbackEncoder) Encode(obj runtime.Object, w io.Writer) error { + // There is no need to handle runtime.CacheableObject, as we only + // fallback to other encoders here. err := c.encoder.Encode(obj, w) if runtime.IsNotRegisteredError(err) { switch obj.(type) { @@ -480,3 +500,8 @@ func (c *jsonFallbackEncoder) Encode(obj runtime.Object, w io.Writer) error { } return err } + +// Identifier implements runtime.Encoder interface. +func (c *jsonFallbackEncoder) Identifier() runtime.Identifier { + return c.identifier +} diff --git a/staging/src/k8s.io/apimachinery/pkg/runtime/codec.go b/staging/src/k8s.io/apimachinery/pkg/runtime/codec.go index f0d7e9f82b1..de0068ab1ad 100644 --- a/staging/src/k8s.io/apimachinery/pkg/runtime/codec.go +++ b/staging/src/k8s.io/apimachinery/pkg/runtime/codec.go @@ -104,10 +104,17 @@ type NoopEncoder struct { var _ Serializer = NoopEncoder{} +const noopEncoderIdentifier Identifier = "noop" + func (n NoopEncoder) Encode(obj Object, w io.Writer) error { return fmt.Errorf("encoding is not allowed for this codec: %v", reflect.TypeOf(n.Decoder)) } +// Identifier implements runtime.Encoder interface. +func (n NoopEncoder) Identifier() Identifier { + return noopEncoderIdentifier +} + // NoopDecoder converts an Encoder to a Serializer or Codec for code that expects them but only uses encoding. type NoopDecoder struct { Encoder @@ -197,10 +204,30 @@ func (c *parameterCodec) EncodeParameters(obj Object, to schema.GroupVersion) (u type base64Serializer struct { Encoder Decoder + + identifier Identifier } func NewBase64Serializer(e Encoder, d Decoder) Serializer { - return &base64Serializer{e, d} + return &base64Serializer{ + Encoder: e, + Decoder: d, + identifier: identifier(e), + } +} + +func identifier(e Encoder) Identifier { + result := map[string]string{ + "name": "base64", + } + if e != nil { + result["encoder"] = string(e.Identifier()) + } + identifier, err := json.Marshal(result) + if err != nil { + klog.Fatalf("Failed marshaling identifier for base64Serializer: %v", err) + } + return Identifier(identifier) } func (s base64Serializer) Encode(obj Object, stream io.Writer) error { @@ -210,6 +237,11 @@ func (s base64Serializer) Encode(obj Object, stream io.Writer) error { return err } +// Identifier implements runtime.Encoder interface. +func (s base64Serializer) Identifier() Identifier { + return s.identifier +} + func (s base64Serializer) Decode(data []byte, defaults *schema.GroupVersionKind, into Object) (Object, *schema.GroupVersionKind, error) { out := make([]byte, base64.StdEncoding.DecodedLen(len(data))) n, err := base64.StdEncoding.Decode(out, data) diff --git a/staging/src/k8s.io/apimachinery/pkg/runtime/serializer/json/BUILD b/staging/src/k8s.io/apimachinery/pkg/runtime/serializer/json/BUILD index 8ff68498d0a..5dfd2b27b91 100644 --- a/staging/src/k8s.io/apimachinery/pkg/runtime/serializer/json/BUILD +++ b/staging/src/k8s.io/apimachinery/pkg/runtime/serializer/json/BUILD @@ -36,6 +36,7 @@ go_library( "//staging/src/k8s.io/apimachinery/pkg/util/yaml:go_default_library", "//vendor/github.com/json-iterator/go:go_default_library", "//vendor/github.com/modern-go/reflect2:go_default_library", + "//vendor/k8s.io/klog:go_default_library", "//vendor/sigs.k8s.io/yaml:go_default_library", ], ) diff --git a/staging/src/k8s.io/apimachinery/pkg/runtime/serializer/json/json.go b/staging/src/k8s.io/apimachinery/pkg/runtime/serializer/json/json.go index 69ada8ecf9c..1871c9ac2ef 100644 --- a/staging/src/k8s.io/apimachinery/pkg/runtime/serializer/json/json.go +++ b/staging/src/k8s.io/apimachinery/pkg/runtime/serializer/json/json.go @@ -31,6 +31,7 @@ import ( "k8s.io/apimachinery/pkg/runtime/serializer/recognizer" "k8s.io/apimachinery/pkg/util/framer" utilyaml "k8s.io/apimachinery/pkg/util/yaml" + "k8s.io/klog" ) // NewSerializer creates a JSON serializer that handles encoding versioned objects into the proper JSON form. If typer @@ -53,13 +54,28 @@ func NewYAMLSerializer(meta MetaFactory, creater runtime.ObjectCreater, typer ru // and are immutable. func NewSerializerWithOptions(meta MetaFactory, creater runtime.ObjectCreater, typer runtime.ObjectTyper, options SerializerOptions) *Serializer { return &Serializer{ - meta: meta, - creater: creater, - typer: typer, - options: options, + meta: meta, + creater: creater, + typer: typer, + options: options, + identifier: identifier(options), } } +// identifier computes Identifier of Encoder based on the given options. +func identifier(options SerializerOptions) runtime.Identifier { + result := map[string]string{ + "name": "json", + "yaml": strconv.FormatBool(options.Yaml), + "pretty": strconv.FormatBool(options.Pretty), + } + identifier, err := json.Marshal(result) + if err != nil { + klog.Fatalf("Failed marshaling identifier for json Serializer: %v", err) + } + return runtime.Identifier(identifier) +} + // SerializerOptions holds the options which are used to configure a JSON/YAML serializer. // example: // (1) To configure a JSON serializer, set `Yaml` to `false`. @@ -85,6 +101,8 @@ type Serializer struct { options SerializerOptions creater runtime.ObjectCreater typer runtime.ObjectTyper + + identifier runtime.Identifier } // Serializer implements Serializer @@ -311,6 +329,11 @@ func (s *Serializer) Encode(obj runtime.Object, w io.Writer) error { return encoder.Encode(obj) } +// Identifier implements runtime.Encoder interface. +func (s *Serializer) Identifier() runtime.Identifier { + return s.identifier +} + // RecognizesData implements the RecognizingDecoder interface. func (s *Serializer) RecognizesData(peek io.Reader) (ok, unknown bool, err error) { if s.options.Yaml { diff --git a/staging/src/k8s.io/apimachinery/pkg/runtime/serializer/protobuf/protobuf.go b/staging/src/k8s.io/apimachinery/pkg/runtime/serializer/protobuf/protobuf.go index 0f33e1d821f..3d408a09355 100644 --- a/staging/src/k8s.io/apimachinery/pkg/runtime/serializer/protobuf/protobuf.go +++ b/staging/src/k8s.io/apimachinery/pkg/runtime/serializer/protobuf/protobuf.go @@ -86,6 +86,8 @@ type Serializer struct { var _ runtime.Serializer = &Serializer{} var _ recognizer.RecognizingDecoder = &Serializer{} +const serializerIdentifier runtime.Identifier = "protobuf" + // 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 @@ -245,6 +247,11 @@ func (s *Serializer) Encode(obj runtime.Object, w io.Writer) error { } } +// Identifier implements runtime.Encoder interface. +func (s *Serializer) Identifier() runtime.Identifier { + return serializerIdentifier +} + // RecognizesData implements the RecognizingDecoder interface. func (s *Serializer) RecognizesData(peek io.Reader) (bool, bool, error) { prefix := make([]byte, 4) @@ -321,6 +328,8 @@ type RawSerializer struct { var _ runtime.Serializer = &RawSerializer{} +const rawSerializerIdentifier runtime.Identifier = "raw-protobuf" + // 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 @@ -460,6 +469,11 @@ func (s *RawSerializer) Encode(obj runtime.Object, w io.Writer) error { } } +// Identifier implements runtime.Encoder interface. +func (s *RawSerializer) Identifier() runtime.Identifier { + return rawSerializerIdentifier +} + var LengthDelimitedFramer = lengthDelimitedFramer{} type lengthDelimitedFramer struct{} diff --git a/staging/src/k8s.io/apimachinery/pkg/runtime/serializer/versioning/BUILD b/staging/src/k8s.io/apimachinery/pkg/runtime/serializer/versioning/BUILD index 9ba9d16f5a4..3406307ebc8 100644 --- a/staging/src/k8s.io/apimachinery/pkg/runtime/serializer/versioning/BUILD +++ b/staging/src/k8s.io/apimachinery/pkg/runtime/serializer/versioning/BUILD @@ -31,6 +31,7 @@ go_library( "//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1/unstructured:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/runtime/schema:go_default_library", + "//vendor/k8s.io/klog:go_default_library", ], ) diff --git a/staging/src/k8s.io/apimachinery/pkg/runtime/serializer/versioning/versioning.go b/staging/src/k8s.io/apimachinery/pkg/runtime/serializer/versioning/versioning.go index ee5cb86f7e6..f7dd7983323 100644 --- a/staging/src/k8s.io/apimachinery/pkg/runtime/serializer/versioning/versioning.go +++ b/staging/src/k8s.io/apimachinery/pkg/runtime/serializer/versioning/versioning.go @@ -17,12 +17,14 @@ limitations under the License. package versioning import ( + "encoding/json" "io" "reflect" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/klog" ) // NewDefaultingCodecForScheme is a convenience method for callers that are using a scheme. @@ -62,6 +64,8 @@ func NewCodec( encodeVersion: encodeVersion, decodeVersion: decodeVersion, + identifier: identifier(encodeVersion, encoder), + originalSchemeName: originalSchemeName, } return internal @@ -78,10 +82,30 @@ type codec struct { encodeVersion runtime.GroupVersioner decodeVersion runtime.GroupVersioner + identifier runtime.Identifier + // originalSchemeName is optional, but when filled in it holds the name of the scheme from which this codec originates originalSchemeName string } +// identifier computes Identifier of Encoder based on codec parameters. +func identifier(encodeGV runtime.GroupVersioner, encoder runtime.Encoder) runtime.Identifier { + result := map[string]string{ + "name": "versioning", + } + if encodeGV != nil { + result["encodeGV"] = encodeGV.Identifier() + } + if encoder != nil { + result["encoder"] = string(encoder.Identifier()) + } + identifier, err := json.Marshal(result) + if err != nil { + klog.Fatalf("Failed marshaling identifier for codec: %v", err) + } + return runtime.Identifier(identifier) +} + // Decode attempts a decode of the object, then tries to convert it to the internal version. If into is provided and the decoding is // successful, the returned runtime.Object will be the value passed as into. Note that this may bypass conversion if you pass an // into that matches the serialized version. @@ -230,3 +254,8 @@ func (c *codec) Encode(obj runtime.Object, w io.Writer) error { // Conversion is responsible for setting the proper group, version, and kind onto the outgoing object return c.encoder.Encode(out, w) } + +// Identifier implements runtime.Encoder interface. +func (c *codec) Identifier() runtime.Identifier { + return c.identifier +} diff --git a/staging/src/k8s.io/apiserver/pkg/endpoints/discovery/BUILD b/staging/src/k8s.io/apiserver/pkg/endpoints/discovery/BUILD index d80a60ea96b..09824784fa7 100644 --- a/staging/src/k8s.io/apiserver/pkg/endpoints/discovery/BUILD +++ b/staging/src/k8s.io/apiserver/pkg/endpoints/discovery/BUILD @@ -46,6 +46,7 @@ go_library( "//staging/src/k8s.io/apiserver/pkg/endpoints/handlers/negotiation:go_default_library", "//staging/src/k8s.io/apiserver/pkg/endpoints/handlers/responsewriters:go_default_library", "//vendor/github.com/emicklei/go-restful:go_default_library", + "//vendor/k8s.io/klog:go_default_library", ], ) diff --git a/staging/src/k8s.io/apiserver/pkg/endpoints/discovery/util.go b/staging/src/k8s.io/apiserver/pkg/endpoints/discovery/util.go index 81a13d64a00..fa63b19d21e 100644 --- a/staging/src/k8s.io/apiserver/pkg/endpoints/discovery/util.go +++ b/staging/src/k8s.io/apiserver/pkg/endpoints/discovery/util.go @@ -18,10 +18,12 @@ package discovery import ( "bytes" + "encoding/json" "fmt" "io" "k8s.io/apimachinery/pkg/runtime" + "k8s.io/klog" ) const APIGroupPrefix = "/apis" @@ -36,6 +38,29 @@ func keepUnversioned(group string) bool { type stripVersionEncoder struct { encoder runtime.Encoder serializer runtime.Serializer + identifier runtime.Identifier +} + +func newStripVersionEncoder(e runtime.Encoder, s runtime.Serializer) runtime.Encoder { + return stripVersionEncoder{ + encoder: e, + serializer: s, + identifier: identifier(e), + } +} + +func identifier(e runtime.Encoder) runtime.Identifier { + result := map[string]string{ + "name": "stripVersion", + } + if e != nil { + result["encoder"] = string(e.Identifier()) + } + identifier, err := json.Marshal(result) + if err != nil { + klog.Fatalf("Failed marshaling identifier for stripVersionEncoder: %v", err) + } + return runtime.Identifier(identifier) } func (c stripVersionEncoder) Encode(obj runtime.Object, w io.Writer) error { @@ -54,6 +79,11 @@ func (c stripVersionEncoder) Encode(obj runtime.Object, w io.Writer) error { return c.serializer.Encode(roundTrippedObj, w) } +// Identifier implements runtime.Encoder interface. +func (c stripVersionEncoder) Identifier() runtime.Identifier { + return c.identifier +} + // stripVersionNegotiatedSerializer will return stripVersionEncoder when // EncoderForVersion is called. See comments for stripVersionEncoder. type stripVersionNegotiatedSerializer struct { @@ -69,5 +99,5 @@ func (n stripVersionNegotiatedSerializer) EncoderForVersion(encoder runtime.Enco panic(fmt.Sprintf("Unable to extract serializer from %#v", encoder)) } versioned := n.NegotiatedSerializer.EncoderForVersion(encoder, gv) - return stripVersionEncoder{versioned, serializer} + return newStripVersionEncoder(versioned, serializer) } diff --git a/staging/src/k8s.io/apiserver/pkg/endpoints/handlers/responsewriters/writers_test.go b/staging/src/k8s.io/apiserver/pkg/endpoints/handlers/responsewriters/writers_test.go index 31bea58c0ed..624b6becdff 100644 --- a/staging/src/k8s.io/apiserver/pkg/endpoints/handlers/responsewriters/writers_test.go +++ b/staging/src/k8s.io/apiserver/pkg/endpoints/handlers/responsewriters/writers_test.go @@ -287,6 +287,10 @@ func (e *fakeEncoder) Encode(obj runtime.Object, w io.Writer) error { return err } +func (e *fakeEncoder) Identifier() runtime.Identifier { + return runtime.Identifier("fake") +} + func gzipContent(data []byte, level int) []byte { buf := &bytes.Buffer{} gw, err := gzip.NewWriterLevel(buf, level) diff --git a/staging/src/k8s.io/cli-runtime/pkg/resource/scheme.go b/staging/src/k8s.io/cli-runtime/pkg/resource/scheme.go index cce86edf412..94939a1c641 100644 --- a/staging/src/k8s.io/cli-runtime/pkg/resource/scheme.go +++ b/staging/src/k8s.io/cli-runtime/pkg/resource/scheme.go @@ -58,6 +58,11 @@ func (dynamicCodec) Encode(obj runtime.Object, w io.Writer) error { return unstructured.UnstructuredJSONScheme.Encode(obj, w) } +// Identifier implements runtime.Encoder interface. +func (dynamicCodec) Identifier() runtime.Identifier { + return unstructured.UnstructuredJSONScheme.Identifier() +} + // UnstructuredPlusDefaultContentConfig returns a rest.ContentConfig for dynamic types. It includes enough codecs to act as a "normal" // serializer for the rest.client with options, status and the like. func UnstructuredPlusDefaultContentConfig() rest.ContentConfig { diff --git a/staging/src/k8s.io/client-go/rest/config_test.go b/staging/src/k8s.io/client-go/rest/config_test.go index df5778ce5c5..06915567cae 100644 --- a/staging/src/k8s.io/client-go/rest/config_test.go +++ b/staging/src/k8s.io/client-go/rest/config_test.go @@ -190,6 +190,10 @@ func (c *fakeCodec) Encode(obj runtime.Object, stream io.Writer) error { return nil } +func (c *fakeCodec) Identifier() runtime.Identifier { + return runtime.Identifier("fake") +} + type fakeRoundTripper struct{} func (r *fakeRoundTripper) RoundTrip(*http.Request) (*http.Response, error) {