mirror of https://github.com/k3s-io/k3s
Merge pull request #856 from pmorie/workaround-timestamp
Set CreationTimestamp in each storage implementationpull/6/head
commit
87256127e0
|
@ -43,7 +43,11 @@ var apiObjectFuzzer = fuzz.New().NilChance(.5).NumElements(1, 1).Funcs(
|
|||
// only when all 8 bytes are set.
|
||||
j.ResourceVersion = c.RandUint64() >> 8
|
||||
j.SelfLink = c.RandString()
|
||||
j.CreationTimestamp = c.RandString()
|
||||
|
||||
var sec, nsec int64
|
||||
c.Fuzz(&sec)
|
||||
c.Fuzz(&nsec)
|
||||
j.CreationTimestamp = util.Unix(sec, nsec).Rfc3339Copy()
|
||||
},
|
||||
func(intstr *util.IntOrString, c fuzz.Continue) {
|
||||
// util.IntOrString will panic if its kind is set wrong.
|
||||
|
@ -113,6 +117,7 @@ func runTest(t *testing.T, source interface{}) {
|
|||
t.Errorf("%v: %v (%#v)", name, err, source)
|
||||
return
|
||||
}
|
||||
|
||||
obj2, err := Decode(data)
|
||||
if err != nil {
|
||||
t.Errorf("%v: %v", name, err)
|
||||
|
|
|
@ -195,12 +195,12 @@ type Event struct {
|
|||
|
||||
// JSONBase is shared by all objects sent to, or returned from the client
|
||||
type JSONBase struct {
|
||||
Kind string `json:"kind,omitempty" yaml:"kind,omitempty"`
|
||||
ID string `json:"id,omitempty" yaml:"id,omitempty"`
|
||||
CreationTimestamp string `json:"creationTimestamp,omitempty" yaml:"creationTimestamp,omitempty"`
|
||||
SelfLink string `json:"selfLink,omitempty" yaml:"selfLink,omitempty"`
|
||||
ResourceVersion uint64 `json:"resourceVersion,omitempty" yaml:"resourceVersion,omitempty"`
|
||||
APIVersion string `json:"apiVersion,omitempty" yaml:"apiVersion,omitempty"`
|
||||
Kind string `json:"kind,omitempty" yaml:"kind,omitempty"`
|
||||
ID string `json:"id,omitempty" yaml:"id,omitempty"`
|
||||
CreationTimestamp util.Time `json:"creationTimestamp,omitempty" yaml:"creationTimestamp,omitempty"`
|
||||
SelfLink string `json:"selfLink,omitempty" yaml:"selfLink,omitempty"`
|
||||
ResourceVersion uint64 `json:"resourceVersion,omitempty" yaml:"resourceVersion,omitempty"`
|
||||
APIVersion string `json:"apiVersion,omitempty" yaml:"apiVersion,omitempty"`
|
||||
}
|
||||
|
||||
// PodStatus represents a status of a pod.
|
||||
|
|
|
@ -198,12 +198,12 @@ type Event struct {
|
|||
|
||||
// JSONBase is shared by all objects sent to, or returned from the client
|
||||
type JSONBase struct {
|
||||
Kind string `json:"kind,omitempty" yaml:"kind,omitempty"`
|
||||
ID string `json:"id,omitempty" yaml:"id,omitempty"`
|
||||
CreationTimestamp string `json:"creationTimestamp,omitempty" yaml:"creationTimestamp,omitempty"`
|
||||
SelfLink string `json:"selfLink,omitempty" yaml:"selfLink,omitempty"`
|
||||
ResourceVersion uint64 `json:"resourceVersion,omitempty" yaml:"resourceVersion,omitempty"`
|
||||
APIVersion string `json:"apiVersion,omitempty" yaml:"apiVersion,omitempty"`
|
||||
Kind string `json:"kind,omitempty" yaml:"kind,omitempty"`
|
||||
ID string `json:"id,omitempty" yaml:"id,omitempty"`
|
||||
CreationTimestamp util.Time `json:"creationTimestamp,omitempty" yaml:"creationTimestamp,omitempty"`
|
||||
SelfLink string `json:"selfLink,omitempty" yaml:"selfLink,omitempty"`
|
||||
ResourceVersion uint64 `json:"resourceVersion,omitempty" yaml:"resourceVersion,omitempty"`
|
||||
APIVersion string `json:"apiVersion,omitempty" yaml:"apiVersion,omitempty"`
|
||||
}
|
||||
|
||||
// PodStatus represents a status of a pod.
|
||||
|
|
|
@ -88,7 +88,7 @@ func (c *Converter) Register(conversionFunc interface{}) error {
|
|||
type FieldMatchingFlags int
|
||||
|
||||
const (
|
||||
// Loop through destiation fields, search for matching source
|
||||
// Loop through destination fields, search for matching source
|
||||
// field to copy it from. Source fields with no corresponding
|
||||
// destination field will be ignored. If SourceToDest is
|
||||
// specified, this flag is ignored. If niether is specified,
|
||||
|
|
|
@ -24,6 +24,7 @@ import (
|
|||
"github.com/GoogleCloudPlatform/kubernetes/pkg/apiserver"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/registry/pod"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/watch"
|
||||
|
||||
"code.google.com/p/go-uuid/uuid"
|
||||
|
@ -61,6 +62,9 @@ func (rs *RegistryStorage) Create(obj interface{}) (<-chan interface{}, error) {
|
|||
if errs := api.ValidateReplicationController(controller); len(errs) > 0 {
|
||||
return nil, fmt.Errorf("Validation errors: %v", errs)
|
||||
}
|
||||
|
||||
controller.CreationTimestamp = util.Now()
|
||||
|
||||
return apiserver.MakeAsync(func() (interface{}, error) {
|
||||
err := rs.registry.CreateController(*controller)
|
||||
if err != nil {
|
||||
|
|
|
@ -22,6 +22,7 @@ import (
|
|||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/apiserver"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
||||
)
|
||||
|
||||
// RegistryStorage implements the RESTStorage interface, backed by a MinionRegistry.
|
||||
|
@ -44,6 +45,9 @@ func (rs *RegistryStorage) Create(obj interface{}) (<-chan interface{}, error) {
|
|||
if minion.ID == "" {
|
||||
return nil, fmt.Errorf("ID should not be empty: %#v", minion)
|
||||
}
|
||||
|
||||
minion.CreationTimestamp = util.Now()
|
||||
|
||||
return apiserver.MakeAsync(func() (interface{}, error) {
|
||||
err := rs.registry.Insert(minion.ID)
|
||||
if err != nil {
|
||||
|
|
|
@ -28,6 +28,7 @@ import (
|
|||
"github.com/GoogleCloudPlatform/kubernetes/pkg/cloudprovider"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/scheduler"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
||||
|
||||
"code.google.com/p/go-uuid/uuid"
|
||||
"github.com/golang/glog"
|
||||
|
@ -76,6 +77,9 @@ func (rs *RegistryStorage) Create(obj interface{}) (<-chan interface{}, error) {
|
|||
if errs := api.ValidatePod(pod); len(errs) > 0 {
|
||||
return nil, fmt.Errorf("Validation errors: %v", errs)
|
||||
}
|
||||
|
||||
pod.CreationTimestamp = util.Now()
|
||||
|
||||
return apiserver.MakeAsync(func() (interface{}, error) {
|
||||
if err := rs.scheduleAndCreatePod(*pod); err != nil {
|
||||
return nil, err
|
||||
|
|
|
@ -0,0 +1,97 @@
|
|||
package util
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"time"
|
||||
)
|
||||
|
||||
// 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.
|
||||
type Time struct {
|
||||
time.Time
|
||||
}
|
||||
|
||||
// Date returns the Time corresponding to the supplied parameters
|
||||
// by wrapping time.Date.
|
||||
func Date(year int, month time.Month, day, hour, min, sec, nsec int, loc *time.Location) Time {
|
||||
return Time{time.Date(year, month, day, hour, min, sec, nsec, loc)}
|
||||
}
|
||||
|
||||
// Now returns the current local time.
|
||||
func Now() Time {
|
||||
return Time{time.Now()}
|
||||
}
|
||||
|
||||
// Unix returns the local time corresponding to the given Unix time
|
||||
// by wrapping time.Unix.
|
||||
func Unix(sec int64, nsec int64) Time {
|
||||
return Time{time.Unix(sec, nsec)}
|
||||
}
|
||||
|
||||
// Rfc3339Copy returns a copy of the Time at second-level precision.
|
||||
func (t Time) Rfc3339Copy() Time {
|
||||
copied, _ := time.Parse(time.RFC3339, t.Format(time.RFC3339))
|
||||
return Time{copied}
|
||||
}
|
||||
|
||||
// UnmarshalJSON implements the json.Unmarshaller interface.
|
||||
func (t *Time) UnmarshalJSON(b []byte) error {
|
||||
if len(b) == 4 && string(b) == "null" {
|
||||
t.Time = time.Time{}
|
||||
return nil
|
||||
}
|
||||
|
||||
var str string
|
||||
json.Unmarshal(b, &str)
|
||||
|
||||
pt, err := time.Parse(time.RFC3339, str)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
t.Time = pt
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalJSON implements the json.Marshaler interface.
|
||||
func (t Time) MarshalJSON() ([]byte, error) {
|
||||
if t.IsZero() {
|
||||
// Encode unset/nil objects as JSON's "null".
|
||||
return []byte("null"), nil
|
||||
}
|
||||
|
||||
return json.Marshal(t.Format(time.RFC3339))
|
||||
}
|
||||
|
||||
// SetYAML implements the yaml.Setter interface.
|
||||
func (t *Time) SetYAML(tag string, value interface{}) bool {
|
||||
if value == nil {
|
||||
t.Time = time.Time{}
|
||||
return true
|
||||
}
|
||||
|
||||
str, ok := value.(string)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
|
||||
pt, err := time.Parse(time.RFC3339, str)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
t.Time = pt
|
||||
return true
|
||||
}
|
||||
|
||||
// GetYAML implements the yaml.Getter interface.
|
||||
func (t Time) GetYAML() (tag string, value interface{}) {
|
||||
if t.IsZero() {
|
||||
value = "null"
|
||||
return
|
||||
}
|
||||
|
||||
value = t.Format(time.RFC3339)
|
||||
return tag, value
|
||||
}
|
|
@ -0,0 +1,126 @@
|
|||
package util
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"reflect"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"gopkg.in/v1/yaml"
|
||||
)
|
||||
|
||||
type TimeHolder struct {
|
||||
T Time `json:"t" yaml:"t"`
|
||||
}
|
||||
|
||||
func TestTimeMarshalYAML(t *testing.T) {
|
||||
cases := []struct {
|
||||
input Time
|
||||
result string
|
||||
}{
|
||||
{Time{}, "t: \"null\"\n"},
|
||||
{Date(1998, time.May, 5, 5, 5, 5, 50, time.UTC), "t: 1998-05-05T05:05:05Z\n"},
|
||||
{Date(1998, time.May, 5, 5, 5, 5, 0, time.UTC), "t: 1998-05-05T05:05:05Z\n"},
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
input := TimeHolder{c.input}
|
||||
result, err := yaml.Marshal(&input)
|
||||
if err != nil {
|
||||
t.Errorf("Failed to marshal input: '%v': %v", input, err)
|
||||
}
|
||||
if string(result) != c.result {
|
||||
t.Errorf("Failed to marshal input: '%v': expected %+v, got %q", input, c.result, string(result))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestTimeUnmarshalYAML(t *testing.T) {
|
||||
cases := []struct {
|
||||
input string
|
||||
result Time
|
||||
}{
|
||||
{"t: \"null\"\n", Time{}},
|
||||
{"t: 1998-05-05T05:05:05Z\n", Date(1998, time.May, 5, 5, 5, 5, 0, time.UTC)},
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
var result TimeHolder
|
||||
if err := yaml.Unmarshal([]byte(c.input), &result); err != nil {
|
||||
t.Errorf("Failed to unmarshal input '%v': %v", c.input, err)
|
||||
}
|
||||
if result.T != c.result {
|
||||
t.Errorf("Failed to unmarshal input '%v': expected %+v, got %+v", c.input, c.result, result)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestTimeMarshalJSON(t *testing.T) {
|
||||
cases := []struct {
|
||||
input Time
|
||||
result string
|
||||
}{
|
||||
{Time{}, "{\"t\":null}"},
|
||||
{Date(1998, time.May, 5, 5, 5, 5, 50, time.UTC), "{\"t\":\"1998-05-05T05:05:05Z\"}"},
|
||||
{Date(1998, time.May, 5, 5, 5, 5, 0, time.UTC), "{\"t\":\"1998-05-05T05:05:05Z\"}"},
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
input := TimeHolder{c.input}
|
||||
result, err := json.Marshal(&input)
|
||||
if err != nil {
|
||||
t.Errorf("Failed to marshal input: '%v': %v", input, err)
|
||||
}
|
||||
if string(result) != c.result {
|
||||
t.Errorf("Failed to marshal input: '%v': expected %+v, got %q", input, c.result, string(result))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestTimeUnmarshalJSON(t *testing.T) {
|
||||
cases := []struct {
|
||||
input string
|
||||
result Time
|
||||
}{
|
||||
{"{\"t\":null}", Time{}},
|
||||
{"{\"t\":\"1998-05-05T05:05:05Z\"}", Date(1998, time.May, 5, 5, 5, 5, 0, time.UTC)},
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
var result TimeHolder
|
||||
if err := json.Unmarshal([]byte(c.input), &result); err != nil {
|
||||
t.Errorf("Failed to unmarshal input '%v': %v", c.input, err)
|
||||
}
|
||||
if result.T != c.result {
|
||||
t.Errorf("Failed to unmarshal input '%v': expected %+v, got %+v", c.input, c.result, result)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestTimeMarshalJSONUnmarshalYAML(t *testing.T) {
|
||||
cases := []struct {
|
||||
input Time
|
||||
}{
|
||||
{Time{}},
|
||||
{Date(1998, time.May, 5, 5, 5, 5, 50, time.UTC).Rfc3339Copy()},
|
||||
{Date(1998, time.May, 5, 5, 5, 5, 0, time.UTC).Rfc3339Copy()},
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
input := TimeHolder{c.input}
|
||||
jsonMarshalled, err := json.Marshal(&input)
|
||||
if err != nil {
|
||||
t.Errorf("1: Failed to marshal input: '%v': %v", input, err)
|
||||
}
|
||||
|
||||
var result TimeHolder
|
||||
err = yaml.Unmarshal(jsonMarshalled, &result)
|
||||
if err != nil {
|
||||
t.Errorf("2: Failed to unmarshall '%+v': %v", string(jsonMarshalled), err)
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(input, result) {
|
||||
t.Errorf("3: Failed to marshal input '%+v': got %+v", input, result)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -101,10 +101,10 @@ func TestIntOrStringUnmarshalYAML(t *testing.T) {
|
|||
for _, c := range cases {
|
||||
var result IntOrStringHolder
|
||||
if err := yaml.Unmarshal([]byte(c.input), &result); err != nil {
|
||||
t.Errorf("Failed to unmarshal: %v", err)
|
||||
t.Errorf("Failed to unmarshal input '%v': %v", c.input, err)
|
||||
}
|
||||
if result.IOrS != c.result {
|
||||
t.Errorf("Failed to unmarshal IntOrString: got %+v", result)
|
||||
t.Errorf("Failed to unmarshal input '%v': expected: %+v, got %+v", c.input, c.result, result)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -122,10 +122,10 @@ func TestIntOrStringMarshalYAML(t *testing.T) {
|
|||
input := IntOrStringHolder{c.input}
|
||||
result, err := yaml.Marshal(&input)
|
||||
if err != nil {
|
||||
t.Errorf("Failed to marshal: %v", err)
|
||||
t.Errorf("Failed to marshal input '%v': %v", input, err)
|
||||
}
|
||||
if string(result) != c.result {
|
||||
t.Errorf("Failed to marshal IntOrString: got %q", string(result))
|
||||
t.Errorf("Failed to marshal input '%v': expected: %+v, got %q", input, c.result, string(result))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -142,10 +142,10 @@ func TestIntOrStringUnmarshalJSON(t *testing.T) {
|
|||
for _, c := range cases {
|
||||
var result IntOrStringHolder
|
||||
if err := json.Unmarshal([]byte(c.input), &result); err != nil {
|
||||
t.Errorf("Failed to unmarshal: %v", err)
|
||||
t.Errorf("Failed to unmarshal input '%v': %v", c.input, err)
|
||||
}
|
||||
if result.IOrS != c.result {
|
||||
t.Errorf("Failed to unmarshal IntOrString: got %+v", result)
|
||||
t.Errorf("Failed to unmarshal input '%v': expected %+v, got %+v", c.input, c.result, result)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -163,10 +163,10 @@ func TestIntOrStringMarshalJSON(t *testing.T) {
|
|||
input := IntOrStringHolder{c.input}
|
||||
result, err := json.Marshal(&input)
|
||||
if err != nil {
|
||||
t.Errorf("Failed to marshal: %v", err)
|
||||
t.Errorf("Failed to marshal input '%v': %v", input, err)
|
||||
}
|
||||
if string(result) != c.result {
|
||||
t.Errorf("Failed to marshal IntOrString: got %q", string(result))
|
||||
t.Errorf("Failed to marshal input '%v': expected: %+v, got %q", input, c.result, string(result))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue