mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-30 06:54:01 +00:00
Add protobuf preparation objects, guarded by proto tag
This commit is contained in:
parent
e2679abdb8
commit
9fea762917
@ -83,6 +83,11 @@ import (
|
||||
// This format is intended to make it difficult to use these numbers without
|
||||
// writing some sort of special handling code in the hopes that that will
|
||||
// cause implementors to also use a fixed point implementation.
|
||||
//
|
||||
// +protobuf=true
|
||||
// +protobuf.embed=QuantityProto
|
||||
// +protobuf.options.marshal=false
|
||||
// +protobuf.options.(gogoproto.goproto_stringer)=false
|
||||
type Quantity struct {
|
||||
// Amount is public, so you can manipulate it if the accessor
|
||||
// functions are not sufficient.
|
||||
|
80
pkg/api/resource/quantity_proto.go
Normal file
80
pkg/api/resource/quantity_proto.go
Normal file
@ -0,0 +1,80 @@
|
||||
// +build proto
|
||||
|
||||
/*
|
||||
Copyright 2015 The Kubernetes Authors All rights reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package resource
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
|
||||
"speter.net/go/exp/math/dec/inf"
|
||||
)
|
||||
|
||||
// QuantityProto is a struct that is equivalent to Quantity, but intended for
|
||||
// protobuf marshalling/unmarshalling. It is generated into a serialization
|
||||
// that matches Quantity. Do not use in Go structs.
|
||||
//
|
||||
// +protobuf=true
|
||||
type QuantityProto struct {
|
||||
// The format of the quantity
|
||||
Format Format
|
||||
// The scale dimension of the value
|
||||
Scale int32
|
||||
// Bigint is serialized as a raw bytes array
|
||||
Bigint []byte
|
||||
}
|
||||
|
||||
// ProtoTime returns the Time as a new ProtoTime value.
|
||||
func (q *Quantity) QuantityProto() *QuantityProto {
|
||||
if q == nil {
|
||||
return &QuantityProto{}
|
||||
}
|
||||
p := &QuantityProto{
|
||||
Format: q.Format,
|
||||
}
|
||||
if q.Amount != nil {
|
||||
p.Scale = int32(q.Amount.Scale())
|
||||
p.Bigint = q.Amount.UnscaledBig().Bytes()
|
||||
}
|
||||
return p
|
||||
}
|
||||
|
||||
// Size implements the protobuf marshalling interface.
|
||||
func (q *Quantity) Size() (n int) { return q.QuantityProto().Size() }
|
||||
|
||||
// Reset implements the protobuf marshalling interface.
|
||||
func (q *Quantity) Unmarshal(data []byte) error {
|
||||
p := QuantityProto{}
|
||||
if err := p.Unmarshal(data); err != nil {
|
||||
return err
|
||||
}
|
||||
q.Format = p.Format
|
||||
b := big.NewInt(0)
|
||||
b.SetBytes(p.Bigint)
|
||||
q.Amount = inf.NewDecBig(b, inf.Scale(p.Scale))
|
||||
return nil
|
||||
}
|
||||
|
||||
// Marshal implements the protobuf marshalling interface.
|
||||
func (q *Quantity) Marshal() (data []byte, err error) {
|
||||
return q.QuantityProto().Marshal()
|
||||
}
|
||||
|
||||
// MarshalTo implements the protobuf marshalling interface.
|
||||
func (q *Quantity) MarshalTo(data []byte) (int, error) {
|
||||
return q.QuantityProto().MarshalTo(data)
|
||||
}
|
95
pkg/api/serialization_proto_test.go
Normal file
95
pkg/api/serialization_proto_test.go
Normal file
@ -0,0 +1,95 @@
|
||||
// +build proto
|
||||
|
||||
/*
|
||||
Copyright 2015 The Kubernetes Authors All rights reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package api_test
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"math/rand"
|
||||
"testing"
|
||||
|
||||
"github.com/gogo/protobuf/proto"
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
apitesting "k8s.io/kubernetes/pkg/api/testing"
|
||||
"k8s.io/kubernetes/pkg/api/v1"
|
||||
_ "k8s.io/kubernetes/pkg/apis/extensions"
|
||||
_ "k8s.io/kubernetes/pkg/apis/extensions/v1beta1"
|
||||
"k8s.io/kubernetes/pkg/runtime"
|
||||
"k8s.io/kubernetes/pkg/runtime/protobuf"
|
||||
"k8s.io/kubernetes/pkg/util"
|
||||
)
|
||||
|
||||
func init() {
|
||||
codecsToTest = append(codecsToTest, func(version string, item runtime.Object) (runtime.Codec, error) {
|
||||
return protobuf.NewCodec(version, api.Scheme, api.Scheme, api.Scheme), nil
|
||||
})
|
||||
}
|
||||
|
||||
func TestProtobufRoundTrip(t *testing.T) {
|
||||
obj := &v1.Pod{}
|
||||
apitesting.FuzzerFor(t, "v1", rand.NewSource(benchmarkSeed)).Fuzz(obj)
|
||||
data, err := obj.Marshal()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
out := &v1.Pod{}
|
||||
if err := out.Unmarshal(data); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !api.Semantic.Equalities.DeepEqual(out, obj) {
|
||||
t.Logf("marshal\n%s", hex.Dump(data))
|
||||
t.Fatalf("Unmarshal is unequal\n%s", util.ObjectGoPrintSideBySide(out, obj))
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkEncodeProtobufGeneratedMarshal(b *testing.B) {
|
||||
items := benchmarkItems()
|
||||
width := len(items)
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
if _, err := items[i%width].Marshal(); err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
}
|
||||
b.StopTimer()
|
||||
}
|
||||
|
||||
// BenchmarkDecodeJSON provides a baseline for regular JSON decode performance
|
||||
func BenchmarkDecodeIntoProtobuf(b *testing.B) {
|
||||
items := benchmarkItems()
|
||||
width := len(items)
|
||||
encoded := make([][]byte, width)
|
||||
for i := range items {
|
||||
data, err := (&items[i]).Marshal()
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
encoded[i] = data
|
||||
validate := &v1.Pod{}
|
||||
if err := proto.Unmarshal(data, validate); err != nil {
|
||||
b.Fatalf("Failed to unmarshal %d: %v\n%#v", i, err, items[i])
|
||||
}
|
||||
}
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
obj := v1.Pod{}
|
||||
if err := proto.Unmarshal(encoded[i%width], &obj); err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
@ -18,29 +18,35 @@ package api_test
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"math/rand"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/davecgh/go-spew/spew"
|
||||
flag "github.com/spf13/pflag"
|
||||
"github.com/ugorji/go/codec"
|
||||
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/api/meta"
|
||||
"k8s.io/kubernetes/pkg/api/testapi"
|
||||
apitesting "k8s.io/kubernetes/pkg/api/testing"
|
||||
"k8s.io/kubernetes/pkg/api/unversioned"
|
||||
"k8s.io/kubernetes/pkg/api/v1"
|
||||
_ "k8s.io/kubernetes/pkg/apis/extensions"
|
||||
_ "k8s.io/kubernetes/pkg/apis/extensions/v1beta1"
|
||||
"k8s.io/kubernetes/pkg/runtime"
|
||||
"k8s.io/kubernetes/pkg/util"
|
||||
"k8s.io/kubernetes/pkg/util/sets"
|
||||
|
||||
_ "k8s.io/kubernetes/pkg/apis/extensions"
|
||||
_ "k8s.io/kubernetes/pkg/apis/extensions/v1beta1"
|
||||
|
||||
flag "github.com/spf13/pflag"
|
||||
)
|
||||
|
||||
var fuzzIters = flag.Int("fuzz-iters", 20, "How many fuzzing iterations to do.")
|
||||
|
||||
var codecsToTest = []func(version string, item runtime.Object) (runtime.Codec, error){
|
||||
func(version string, item runtime.Object) (runtime.Codec, error) {
|
||||
return testapi.GetCodecForObject(item)
|
||||
},
|
||||
}
|
||||
|
||||
func fuzzInternalObject(t *testing.T, forVersion string, item runtime.Object, seed int64) runtime.Object {
|
||||
apitesting.FuzzerFor(t, forVersion, rand.NewSource(seed)).Fuzz(item)
|
||||
|
||||
@ -92,16 +98,22 @@ func roundTripSame(t *testing.T, item runtime.Object, except ...string) {
|
||||
seed := rand.Int63()
|
||||
fuzzInternalObject(t, "", item, seed)
|
||||
|
||||
codec, err := testapi.GetCodecForObject(item)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
return
|
||||
version := testapi.Default.VersionUnderTest
|
||||
codecs := []runtime.Codec{}
|
||||
for _, fn := range codecsToTest {
|
||||
codec, err := fn(version, item)
|
||||
if err != nil {
|
||||
t.Errorf("unable to get codec: %v", err)
|
||||
return
|
||||
}
|
||||
codecs = append(codecs, codec)
|
||||
}
|
||||
|
||||
version := testapi.Default.Version()
|
||||
if !set.Has(version) {
|
||||
fuzzInternalObject(t, version, item, seed)
|
||||
roundTrip(t, codec, item)
|
||||
for _, codec := range codecs {
|
||||
roundTrip(t, codec, item)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -163,7 +175,9 @@ func doRoundTripTest(kind string, t *testing.T) {
|
||||
if _, err := meta.TypeAccessor(item); err != nil {
|
||||
t.Fatalf("%q is not a TypeMeta and cannot be tested - add it to nonRoundTrippableTypes: %v", kind, err)
|
||||
}
|
||||
roundTripSame(t, item, nonRoundTrippableTypesByVersion[kind]...)
|
||||
if api.Scheme.Recognizes(testapi.Default.VersionUnderTest, kind) {
|
||||
roundTripSame(t, item, nonRoundTrippableTypesByVersion[kind]...)
|
||||
}
|
||||
if !nonInternalRoundTrippableTypes.Has(kind) {
|
||||
roundTrip(t, api.Codec, fuzzInternalObject(t, "", item, rand.Int63()))
|
||||
}
|
||||
@ -247,54 +261,132 @@ func TestUnversionedTypes(t *testing.T) {
|
||||
|
||||
const benchmarkSeed = 100
|
||||
|
||||
func BenchmarkEncode(b *testing.B) {
|
||||
pod := api.Pod{}
|
||||
func benchmarkItems() []v1.Pod {
|
||||
apiObjectFuzzer := apitesting.FuzzerFor(nil, "", rand.NewSource(benchmarkSeed))
|
||||
apiObjectFuzzer.Fuzz(&pod)
|
||||
for i := 0; i < b.N; i++ {
|
||||
testapi.Default.Codec().Encode(&pod)
|
||||
items := make([]v1.Pod, 2)
|
||||
for i := range items {
|
||||
apiObjectFuzzer.Fuzz(&items[i])
|
||||
}
|
||||
return items
|
||||
}
|
||||
|
||||
// BenchmarkEncodeJSON provides a baseline for regular JSON encode performance
|
||||
func BenchmarkEncodeJSON(b *testing.B) {
|
||||
pod := api.Pod{}
|
||||
apiObjectFuzzer := apitesting.FuzzerFor(nil, "", rand.NewSource(benchmarkSeed))
|
||||
apiObjectFuzzer.Fuzz(&pod)
|
||||
// BenchmarkEncodeCodec measures the cost of performing a codec encode, which includes
|
||||
// reflection (to clear APIVersion and Kind)
|
||||
func BenchmarkEncodeCodec(b *testing.B) {
|
||||
items := benchmarkItems()
|
||||
width := len(items)
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
json.Marshal(&pod)
|
||||
if _, err := testapi.Default.Codec().Encode(&items[i%width]); err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
}
|
||||
b.StopTimer()
|
||||
}
|
||||
|
||||
func BenchmarkDecode(b *testing.B) {
|
||||
pod := api.Pod{}
|
||||
apiObjectFuzzer := apitesting.FuzzerFor(nil, "", rand.NewSource(benchmarkSeed))
|
||||
apiObjectFuzzer.Fuzz(&pod)
|
||||
data, _ := testapi.Default.Codec().Encode(&pod)
|
||||
// BenchmarkEncodeJSONMarshal provides a baseline for regular JSON encode performance
|
||||
func BenchmarkEncodeJSONMarshal(b *testing.B) {
|
||||
items := benchmarkItems()
|
||||
width := len(items)
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
testapi.Default.Codec().Decode(data)
|
||||
if _, err := json.Marshal(&items[i%width]); err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
}
|
||||
b.StopTimer()
|
||||
}
|
||||
|
||||
func BenchmarkDecodeInto(b *testing.B) {
|
||||
pod := api.Pod{}
|
||||
apiObjectFuzzer := apitesting.FuzzerFor(nil, "", rand.NewSource(benchmarkSeed))
|
||||
apiObjectFuzzer.Fuzz(&pod)
|
||||
data, _ := testapi.Default.Codec().Encode(&pod)
|
||||
for i := 0; i < b.N; i++ {
|
||||
obj := api.Pod{}
|
||||
testapi.Default.Codec().DecodeInto(data, &obj)
|
||||
func BenchmarkDecodeCodec(b *testing.B) {
|
||||
codec := testapi.Default.Codec()
|
||||
items := benchmarkItems()
|
||||
width := len(items)
|
||||
encoded := make([][]byte, width)
|
||||
for i := range items {
|
||||
data, err := codec.Encode(&items[i])
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
encoded[i] = data
|
||||
}
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
if _, err := codec.Decode(encoded[i%width]); err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
}
|
||||
b.StopTimer()
|
||||
}
|
||||
|
||||
func BenchmarkDecodeIntoCodec(b *testing.B) {
|
||||
codec := testapi.Default.Codec()
|
||||
items := benchmarkItems()
|
||||
width := len(items)
|
||||
encoded := make([][]byte, width)
|
||||
for i := range items {
|
||||
data, err := codec.Encode(&items[i])
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
encoded[i] = data
|
||||
}
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
obj := v1.Pod{}
|
||||
if err := codec.DecodeInto(encoded[i%width], &obj); err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
}
|
||||
b.StopTimer()
|
||||
}
|
||||
|
||||
// BenchmarkDecodeJSON provides a baseline for regular JSON decode performance
|
||||
func BenchmarkDecodeJSON(b *testing.B) {
|
||||
pod := api.Pod{}
|
||||
apiObjectFuzzer := apitesting.FuzzerFor(nil, "", rand.NewSource(benchmarkSeed))
|
||||
apiObjectFuzzer.Fuzz(&pod)
|
||||
data, _ := testapi.Default.Codec().Encode(&pod)
|
||||
for i := 0; i < b.N; i++ {
|
||||
obj := api.Pod{}
|
||||
json.Unmarshal(data, &obj)
|
||||
func BenchmarkDecodeIntoJSON(b *testing.B) {
|
||||
codec := testapi.Default.Codec()
|
||||
items := benchmarkItems()
|
||||
width := len(items)
|
||||
encoded := make([][]byte, width)
|
||||
for i := range items {
|
||||
data, err := codec.Encode(&items[i])
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
encoded[i] = data
|
||||
}
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
obj := v1.Pod{}
|
||||
if err := json.Unmarshal(encoded[i%width], &obj); err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
}
|
||||
b.StopTimer()
|
||||
}
|
||||
|
||||
// BenchmarkDecodeJSON provides a baseline for codecgen JSON decode performance
|
||||
func BenchmarkDecodeIntoJSONCodecGen(b *testing.B) {
|
||||
kcodec := testapi.Default.Codec()
|
||||
items := benchmarkItems()
|
||||
width := len(items)
|
||||
encoded := make([][]byte, width)
|
||||
for i := range items {
|
||||
data, err := kcodec.Encode(&items[i])
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
encoded[i] = data
|
||||
}
|
||||
handler := &codec.JsonHandle{}
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
obj := v1.Pod{}
|
||||
if err := codec.NewDecoderBytes(encoded[i%width], handler).Decode(&obj); err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
}
|
||||
b.StopTimer()
|
||||
}
|
||||
|
@ -43,5 +43,5 @@ func (d *Duration) UnmarshalJSON(b []byte) error {
|
||||
|
||||
// MarshalJSON implements the json.Marshaler interface.
|
||||
func (d Duration) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(d.String())
|
||||
return json.Marshal(d.Duration.String())
|
||||
}
|
||||
|
@ -40,6 +40,8 @@ func (gvr *GroupVersionResource) String() string {
|
||||
|
||||
// GroupKind specifies a Group and a Kind, but does not force a version. This is useful for identifying
|
||||
// concepts during lookup stages without having partially valid types
|
||||
//
|
||||
// +protobuf.options.(gogoproto.goproto_stringer)=false
|
||||
type GroupKind struct {
|
||||
Group string
|
||||
Kind string
|
||||
@ -55,6 +57,8 @@ func (gk *GroupKind) String() string {
|
||||
|
||||
// GroupVersionKind unambiguously identifies a kind. It doesn't anonymously include GroupVersion
|
||||
// to avoid automatic coersion. It doesn't use a GroupVersion to avoid custom marshalling
|
||||
//
|
||||
// +protobuf.options.(gogoproto.goproto_stringer)=false
|
||||
type GroupVersionKind struct {
|
||||
Group string
|
||||
Version string
|
||||
@ -79,6 +83,8 @@ func (gvk *GroupVersionKind) String() string {
|
||||
}
|
||||
|
||||
// GroupVersion contains the "group" and the "version", which uniquely identifies the API.
|
||||
//
|
||||
// +protobuf.options.(gogoproto.goproto_stringer)=false
|
||||
type GroupVersion struct {
|
||||
Group string
|
||||
Version string
|
||||
|
@ -26,8 +26,10 @@ import (
|
||||
// Time is a wrapper around time.Time which supports correct
|
||||
// marshaling to YAML and JSON. Wrappers are provided for many
|
||||
// of the factory methods that the time package offers.
|
||||
//
|
||||
// +protobuf.options.marshal=false
|
||||
type Time struct {
|
||||
time.Time
|
||||
time.Time `protobuf:"Timestamp,1,req,name=time"`
|
||||
}
|
||||
|
||||
// NewTime returns a wrapped instance of the provided time
|
||||
|
80
pkg/api/unversioned/time_proto.go
Normal file
80
pkg/api/unversioned/time_proto.go
Normal file
@ -0,0 +1,80 @@
|
||||
// +build proto
|
||||
|
||||
/*
|
||||
Copyright 2015 The Kubernetes Authors All rights reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package unversioned
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// ProtoTime is a struct that is equivalent to Time, but intended for
|
||||
// protobuf marshalling/unmarshalling. It is generated into a serialization
|
||||
// that matches Time. Do not use in Go structs.
|
||||
type ProtoTime struct {
|
||||
// Represents the time of an event.
|
||||
Timestamp Timestamp `json:"timestamp"`
|
||||
}
|
||||
|
||||
// Timestamp is a protobuf Timestamp compatible representation of time.Time
|
||||
type Timestamp struct {
|
||||
// Represents seconds of UTC time since Unix epoch
|
||||
// 1970-01-01T00:00:00Z. Must be from from 0001-01-01T00:00:00Z to
|
||||
// 9999-12-31T23:59:59Z inclusive.
|
||||
Seconds int64 `json:"seconds"`
|
||||
// Non-negative fractions of a second at nanosecond resolution. Negative
|
||||
// second values with fractions must still have non-negative nanos values
|
||||
// that count forward in time. Must be from 0 to 999,999,999
|
||||
// inclusive.
|
||||
Nanos int32 `json:"nanos"`
|
||||
}
|
||||
|
||||
// ProtoTime returns the Time as a new ProtoTime value.
|
||||
func (m *Time) ProtoTime() *ProtoTime {
|
||||
if m == nil {
|
||||
return &ProtoTime{}
|
||||
}
|
||||
return &ProtoTime{
|
||||
Timestamp: Timestamp{
|
||||
Seconds: m.Time.Unix(),
|
||||
Nanos: int32(m.Time.Nanosecond()),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// Size implements the protobuf marshalling interface.
|
||||
func (m *Time) Size() (n int) { return m.ProtoTime().Size() }
|
||||
|
||||
// Reset implements the protobuf marshalling interface.
|
||||
func (m *Time) Unmarshal(data []byte) error {
|
||||
p := ProtoTime{}
|
||||
if err := p.Unmarshal(data); err != nil {
|
||||
return err
|
||||
}
|
||||
m.Time = time.Unix(p.Timestamp.Seconds, int64(p.Timestamp.Nanos))
|
||||
return nil
|
||||
}
|
||||
|
||||
// Marshal implements the protobuf marshalling interface.
|
||||
func (m *Time) Marshal() (data []byte, err error) {
|
||||
return m.ProtoTime().Marshal()
|
||||
}
|
||||
|
||||
// MarshalTo implements the protobuf marshalling interface.
|
||||
func (m *Time) MarshalTo(data []byte) (int, error) {
|
||||
return m.ProtoTime().MarshalTo(data)
|
||||
}
|
@ -311,6 +311,8 @@ func (*APIResourceList) IsAnAPIObject() {}
|
||||
|
||||
// APIVersions lists the versions that are available, to allow clients to
|
||||
// discover the API at /api, which is the root path of the legacy v1 API.
|
||||
//
|
||||
// +protobuf.options.(gogoproto.goproto_stringer)=false
|
||||
type APIVersions struct {
|
||||
TypeMeta `json:",inline"`
|
||||
// versions are the api versions that are available.
|
||||
|
18
pkg/runtime/protobuf/doc.go
Normal file
18
pkg/runtime/protobuf/doc.go
Normal file
@ -0,0 +1,18 @@
|
||||
/*
|
||||
Copyright 2015 The Kubernetes Authors All rights reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// Package protobuf implements ProtoBuf serialization and deserialization.
|
||||
package protobuf
|
158
pkg/runtime/protobuf/protobuf.go
Normal file
158
pkg/runtime/protobuf/protobuf.go
Normal file
@ -0,0 +1,158 @@
|
||||
// +build proto
|
||||
|
||||
/*
|
||||
Copyright 2015 The Kubernetes Authors All rights reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package protobuf
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net/url"
|
||||
"reflect"
|
||||
|
||||
"github.com/gogo/protobuf/proto"
|
||||
|
||||
"k8s.io/kubernetes/pkg/api/unversioned"
|
||||
"k8s.io/kubernetes/pkg/runtime"
|
||||
)
|
||||
|
||||
// NewCodec
|
||||
func NewCodec(version string, creater runtime.ObjectCreater, typer runtime.ObjectTyper, convertor runtime.ObjectConvertor) runtime.Codec {
|
||||
return &codec{
|
||||
version: version,
|
||||
creater: creater,
|
||||
typer: typer,
|
||||
convertor: convertor,
|
||||
}
|
||||
}
|
||||
|
||||
// codec decodes protobuf objects
|
||||
type codec struct {
|
||||
version string
|
||||
outputVersion string
|
||||
creater runtime.ObjectCreater
|
||||
typer runtime.ObjectTyper
|
||||
convertor runtime.ObjectConvertor
|
||||
}
|
||||
|
||||
var _ runtime.Codec = codec{}
|
||||
|
||||
func (c codec) Decode(data []byte) (runtime.Object, error) {
|
||||
unknown := &runtime.Unknown{}
|
||||
if err := proto.Unmarshal(data, unknown); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
obj, err := c.creater.New(unknown.APIVersion, unknown.Kind)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
pobj, ok := obj.(proto.Message)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("runtime object is not a proto.Message: %v", reflect.TypeOf(obj))
|
||||
}
|
||||
if err := proto.Unmarshal(unknown.RawJSON, pobj); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if unknown.APIVersion != c.outputVersion {
|
||||
out, err := c.convertor.ConvertToVersion(obj, c.outputVersion)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
obj = out
|
||||
}
|
||||
return obj, nil
|
||||
}
|
||||
|
||||
func (c codec) DecodeToVersion(data []byte, version unversioned.GroupVersion) (runtime.Object, error) {
|
||||
return nil, fmt.Errorf("unimplemented")
|
||||
}
|
||||
|
||||
func (c codec) DecodeInto(data []byte, obj runtime.Object) error {
|
||||
version, kind, err := c.typer.ObjectVersionAndKind(obj)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
unknown := &runtime.Unknown{}
|
||||
if err := proto.Unmarshal(data, unknown); err != nil {
|
||||
return err
|
||||
}
|
||||
if unknown.APIVersion == version && unknown.Kind == kind {
|
||||
pobj, ok := obj.(proto.Message)
|
||||
if !ok {
|
||||
return fmt.Errorf("runtime object is not a proto.Message: %v", reflect.TypeOf(obj))
|
||||
}
|
||||
|
||||
return proto.Unmarshal(unknown.RawJSON, pobj)
|
||||
}
|
||||
|
||||
versioned, err := c.creater.New(unknown.APIVersion, unknown.Kind)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
pobj, ok := versioned.(proto.Message)
|
||||
if !ok {
|
||||
return fmt.Errorf("runtime object is not a proto.Message: %v", reflect.TypeOf(obj))
|
||||
}
|
||||
|
||||
if err := proto.Unmarshal(unknown.RawJSON, pobj); err != nil {
|
||||
return err
|
||||
}
|
||||
return c.convertor.Convert(versioned, obj)
|
||||
}
|
||||
|
||||
func (c codec) DecodeIntoWithSpecifiedVersionKind(data []byte, obj runtime.Object, kind unversioned.GroupVersionKind) error {
|
||||
return fmt.Errorf("unimplemented")
|
||||
}
|
||||
|
||||
func (c codec) DecodeParametersInto(parameters url.Values, obj runtime.Object) error {
|
||||
return fmt.Errorf("unimplemented")
|
||||
}
|
||||
|
||||
func (c codec) Encode(obj runtime.Object) (data []byte, err error) {
|
||||
version, kind, err := c.typer.ObjectVersionAndKind(obj)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(version) == 0 {
|
||||
version = c.version
|
||||
converted, err := c.convertor.ConvertToVersion(obj, version)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
obj = converted
|
||||
}
|
||||
m, ok := obj.(proto.Marshaler)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("object %v (kind: %s in version: %s) does not implement ProtoBuf marshalling", reflect.TypeOf(obj), kind, c.version)
|
||||
}
|
||||
b, err := m.Marshal()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return (&runtime.Unknown{
|
||||
TypeMeta: runtime.TypeMeta{
|
||||
Kind: kind,
|
||||
APIVersion: version,
|
||||
},
|
||||
RawJSON: b,
|
||||
}).Marshal()
|
||||
}
|
||||
|
||||
func (c codec) EncodeToStream(obj runtime.Object, stream io.Writer) error {
|
||||
return fmt.Errorf("unimplemented")
|
||||
}
|
@ -30,6 +30,7 @@ package runtime
|
||||
// TypeMeta is provided here for convenience. You may use it directly from this package or define
|
||||
// your own with the same fields.
|
||||
//
|
||||
// +protobuf=true
|
||||
type TypeMeta struct {
|
||||
APIVersion string `json:"apiVersion,omitempty" yaml:"apiVersion,omitempty"`
|
||||
Kind string `json:"kind,omitempty" yaml:"kind,omitempty"`
|
||||
@ -98,6 +99,8 @@ type EmbeddedObject struct {
|
||||
// JSON stored in RawExtension, turning it into the correct object type, and storing it
|
||||
// in the EmbeddedObject. (TODO: In the case where the object is of an unknown type, a
|
||||
// runtime.Unknown object will be created and stored.)
|
||||
//
|
||||
// +protobuf=true
|
||||
type RawExtension struct {
|
||||
RawJSON []byte
|
||||
}
|
||||
@ -107,6 +110,8 @@ type RawExtension struct {
|
||||
// TypeMeta features-- kind, version, etc.
|
||||
// TODO: Make this object have easy access to field based accessors and settors for
|
||||
// metadata and field mutatation.
|
||||
//
|
||||
// +protobuf=true
|
||||
type Unknown struct {
|
||||
TypeMeta `json:",inline"`
|
||||
// RawJSON will hold the complete JSON of the object which couldn't be matched
|
||||
|
@ -29,6 +29,9 @@ import (
|
||||
// inner type. This allows you to have, for example, a JSON field that can
|
||||
// accept a name or number.
|
||||
// TODO: Rename to Int32OrString
|
||||
//
|
||||
// +protobuf=true
|
||||
// +protobuf.options.(gogoproto.goproto_stringer)=false
|
||||
type IntOrString struct {
|
||||
Type Type
|
||||
IntVal int32
|
||||
|
Loading…
Reference in New Issue
Block a user