daemon/internal/timestamp: replace GetTimestamp for Parse
All code in the daemon using `GetTimestamp` called `ParseTimestamp` afterwards to convert the string value to a time.Time. Replace it with a `Parse` function that immediately returns a time.Time (in UTC) so that we don't have to "fuzzy" parse twice. Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
This commit is contained in:
10 files changed
+48
-106
No files matched your search
@@ -601,20 +601,15 @@ func (i *ImageService) setupFilters(ctx context.Context, imageFilters filters.Ar
|
||||
return nil, err
|
||||
}
|
||||
|
||||
now := time.Now()
|
||||
err = imageFilters.WalkValues("until", func(value string) error {
|
||||
ts, err := timestamp.GetTimestamp(value, time.Now())
|
||||
until, err := timestamp.Parse(value, now)
|
||||
if err != nil {
|
||||
return errdefs.InvalidParameter(fmt.Errorf("invalid value for 'until' filter: %w", err))
|
||||
}
|
||||
seconds, nanoseconds, err := timestamp.ParseTimestamps(ts, 0)
|
||||
if err != nil {
|
||||
return errdefs.InvalidParameter(fmt.Errorf("invalid value for 'until' filter: %w", err))
|
||||
}
|
||||
until := time.Unix(seconds, nanoseconds)
|
||||
|
||||
fltrs = append(fltrs, func(image c8dimages.Image) bool {
|
||||
created := image.CreatedAt
|
||||
return created.Before(until)
|
||||
return image.CreatedAt.Before(until)
|
||||
})
|
||||
return nil
|
||||
})
|
||||
|
||||
@@ -126,10 +126,7 @@ func TestLogEvents(t *testing.T) {
|
||||
// 2016-03-07T17:28:03.129014751+02:00 container destroy 0b863f2a26c18557fc6cdadda007c459f9ec81b874780808138aea78a3595079 (image=ubuntu, name=small_hoover)
|
||||
func TestLoadBufferedEvents(t *testing.T) {
|
||||
now := time.Now()
|
||||
f, err := timestamp.GetTimestamp("2016-03-07T17:28:03.100000000+02:00", now)
|
||||
assert.NilError(t, err)
|
||||
|
||||
s, sNano, err := timestamp.ParseTimestamps(f, -1)
|
||||
since, err := timestamp.Parse("2016-03-07T17:28:03.100000000+02:00", now)
|
||||
assert.NilError(t, err)
|
||||
|
||||
m1, err := eventstestutils.Scan("2016-03-07T17:28:03.022433271+02:00 container die 0b863f2a26c18557fc6cdadda007c459f9ec81b874780808138aea78a3595079 (image=ubuntu, name=small_hoover)")
|
||||
@@ -145,7 +142,6 @@ func TestLoadBufferedEvents(t *testing.T) {
|
||||
events: []events.Message{*m1, *m2, *m3},
|
||||
}
|
||||
|
||||
since := time.Unix(s, sNano)
|
||||
until := time.Time{}
|
||||
|
||||
messages := evts.loadBufferedEvents(since, until, nil)
|
||||
@@ -154,16 +150,11 @@ func TestLoadBufferedEvents(t *testing.T) {
|
||||
|
||||
func TestLoadBufferedEventsOnlyFromPast(t *testing.T) {
|
||||
now := time.Now()
|
||||
f, err := timestamp.GetTimestamp("2016-03-07T17:28:03.090000000+02:00", now)
|
||||
|
||||
since, err := timestamp.Parse("2016-03-07T17:28:03.090000000+02:00", now)
|
||||
assert.NilError(t, err)
|
||||
|
||||
s, sNano, err := timestamp.ParseTimestamps(f, 0)
|
||||
assert.NilError(t, err)
|
||||
|
||||
f, err = timestamp.GetTimestamp("2016-03-07T17:28:03.100000000+02:00", now)
|
||||
assert.NilError(t, err)
|
||||
|
||||
u, uNano, err := timestamp.ParseTimestamps(f, 0)
|
||||
until, err := timestamp.Parse("2016-03-07T17:28:03.100000000+02:00", now)
|
||||
assert.NilError(t, err)
|
||||
|
||||
m1, err := eventstestutils.Scan("2016-03-07T17:28:03.022433271+02:00 container die 0b863f2a26c18557fc6cdadda007c459f9ec81b874780808138aea78a3595079 (image=ubuntu, name=small_hoover)")
|
||||
@@ -179,9 +170,6 @@ func TestLoadBufferedEventsOnlyFromPast(t *testing.T) {
|
||||
events: []events.Message{*m1, *m2, *m3},
|
||||
}
|
||||
|
||||
since := time.Unix(s, sNano)
|
||||
until := time.Unix(u, uNano)
|
||||
|
||||
messages := evts.loadBufferedEvents(since, until, nil)
|
||||
assert.Assert(t, is.Len(messages, 1))
|
||||
assert.Check(t, is.Equal(messages[0].Type, events.NetworkEventType))
|
||||
|
||||
@@ -45,12 +45,7 @@ func Scan(text string) (*events.Message, error) {
|
||||
return nil, fmt.Errorf("text is not an event: %s", text)
|
||||
}
|
||||
|
||||
f, err := timestamp.GetTimestamp(md["timestamp"], time.Now())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
t, tn, err := timestamp.ParseTimestamps(f, -1)
|
||||
created, err := timestamp.Parse(md["timestamp"], time.Now())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -62,8 +57,8 @@ func Scan(text string) (*events.Message, error) {
|
||||
}
|
||||
|
||||
return &events.Message{
|
||||
Time: t,
|
||||
TimeNano: time.Unix(t, tn).UnixNano(),
|
||||
Time: created.Unix(),
|
||||
TimeNano: created.UnixNano(),
|
||||
Type: events.Type(md["eventType"]),
|
||||
Action: events.Action(md["action"]),
|
||||
Actor: events.Actor{
|
||||
|
||||
@@ -62,17 +62,14 @@ func (i *ImageService) Images(ctx context.Context, opts imagebackend.ListOptions
|
||||
return nil, err
|
||||
}
|
||||
|
||||
now := time.Now()
|
||||
err = opts.Filters.WalkValues("until", func(value string) error {
|
||||
ts, err := timestamp.GetTimestamp(value, time.Now())
|
||||
ts, err := timestamp.Parse(value, now)
|
||||
if err != nil {
|
||||
return errdefs.InvalidParameter(fmt.Errorf("invalid value for 'until' filter: %w", err))
|
||||
}
|
||||
seconds, nanoseconds, err := timestamp.ParseTimestamps(ts, 0)
|
||||
if err != nil {
|
||||
return errdefs.InvalidParameter(fmt.Errorf("invalid value for 'until' filter: %w", err))
|
||||
}
|
||||
if tsUnix := time.Unix(seconds, nanoseconds); beforeFilter.IsZero() || beforeFilter.After(tsUnix) {
|
||||
beforeFilter = tsUnix
|
||||
if beforeFilter.IsZero() || beforeFilter.After(ts) {
|
||||
beforeFilter = ts
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
@@ -193,13 +193,9 @@ func getUntilFromPruneFilters(pruneFilters filters.Args) (time.Time, error) {
|
||||
if len(untilFilters) > 1 {
|
||||
return time.Time{}, errdefs.InvalidParameter(errors.New("more than one until filter specified"))
|
||||
}
|
||||
ts, err := timestamp.GetTimestamp(untilFilters[0], time.Now())
|
||||
t, err := timestamp.Parse(untilFilters[0], time.Now())
|
||||
if err != nil {
|
||||
return time.Time{}, errdefs.InvalidParameter(fmt.Errorf("invalid value for 'until' filter: %w", err))
|
||||
}
|
||||
seconds, nanoseconds, err := timestamp.ParseTimestamps(ts, 0)
|
||||
if err != nil {
|
||||
return time.Time{}, errdefs.InvalidParameter(fmt.Errorf("invalid value for 'until' filter: %w", err))
|
||||
}
|
||||
return time.Unix(seconds, nanoseconds), nil
|
||||
return t, nil
|
||||
}
|
||||
@@ -674,20 +674,13 @@ func toBuildkitPruneInfo(opts buildbackend.CachePruneOptions) (client.PruneInfo,
|
||||
case 0:
|
||||
// nothing to do
|
||||
case 1:
|
||||
ts, err := timestamp.GetTimestamp(untilValues[0], time.Now())
|
||||
parsed, err := timestamp.Parse(untilValues[0], time.Now())
|
||||
if err != nil {
|
||||
return client.PruneInfo{}, errInvalidFilterValue{
|
||||
errors.Wrapf(err, "%q filter expects a duration (e.g., '24h') or a timestamp", filterKey),
|
||||
}
|
||||
}
|
||||
seconds, nanoseconds, err := timestamp.ParseTimestamps(ts, 0)
|
||||
if err != nil {
|
||||
return client.PruneInfo{}, errInvalidFilterValue{
|
||||
errors.Wrapf(err, "failed to parse timestamp %q", ts),
|
||||
}
|
||||
}
|
||||
|
||||
until = time.Since(time.Unix(seconds, nanoseconds))
|
||||
until = time.Since(parsed)
|
||||
default:
|
||||
return client.PruneInfo{}, errMultipleFilterValues{}
|
||||
}
|
||||
|
||||
@@ -17,19 +17,17 @@ const (
|
||||
dateLocal = "2006-01-02" // RFC3339 with local timezone and time at 00:00:00
|
||||
)
|
||||
|
||||
// GetTimestamp tries to parse given string as golang duration,
|
||||
// then RFC3339 time and finally as a Unix timestamp. If
|
||||
// any of these were successful, it returns a Unix timestamp
|
||||
// as string otherwise returns the given value back.
|
||||
// In case of duration input, the returned timestamp is computed
|
||||
// as the given reference time minus the amount of the duration.
|
||||
func GetTimestamp(value string, reference time.Time) (string, error) {
|
||||
// Parse tries to parse given string as golang duration, then RFC3339 time and
|
||||
// finally as a Unix timestamp. The returned time is normalized to UTC.
|
||||
//
|
||||
// In case of duration input, the returned timestamp is computed as the given
|
||||
// reference time minus the amount of the duration.
|
||||
func Parse(value string, reference time.Time) (time.Time, error) {
|
||||
if strings.TrimSpace(value) == "" {
|
||||
return time.Time{}, errors.New("failed to parse value as time or duration: value is empty")
|
||||
}
|
||||
if d, err := time.ParseDuration(value); value != "0" && err == nil {
|
||||
t := reference.Add(-d)
|
||||
if t.Nanosecond() == 0 {
|
||||
return strconv.FormatInt(t.Unix(), 10), nil
|
||||
}
|
||||
return fmt.Sprintf("%d.%09d", t.Unix(), t.Nanosecond()), nil
|
||||
return reference.Add(-d).UTC(), nil
|
||||
}
|
||||
|
||||
var format string
|
||||
@@ -88,18 +86,16 @@ func GetTimestamp(value string, reference time.Time) (string, error) {
|
||||
if err != nil {
|
||||
// if there is a `-` then it's an RFC3339 like timestamp
|
||||
if strings.Contains(value, "-") {
|
||||
return "", err // was probably an RFC3339 like timestamp but the parser failed with an error
|
||||
return time.Time{}, err // was probably an RFC3339 like timestamp but the parser failed with an error
|
||||
}
|
||||
if _, _, err := parseTimestamp(value); err != nil {
|
||||
return "", fmt.Errorf("failed to parse value as time or duration: %q", value)
|
||||
sec, nsec, err := parseTimestamp(value)
|
||||
if err != nil {
|
||||
return time.Time{}, fmt.Errorf("failed to parse value as time or duration: %q", value)
|
||||
}
|
||||
return value, nil // unix timestamp in and out case (meaning: the value passed at the command line is already in the right format for passing to the server)
|
||||
return time.Unix(sec, nsec), nil
|
||||
}
|
||||
|
||||
if t.Nanosecond() == 0 {
|
||||
return strconv.FormatInt(t.Unix(), 10), nil
|
||||
}
|
||||
return fmt.Sprintf("%d.%09d", t.Unix(), t.Nanosecond()), nil
|
||||
return t.UTC(), nil
|
||||
}
|
||||
|
||||
// ParseTimestamps returns seconds and nanoseconds from a timestamp that has
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
package timestamp_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
@@ -11,7 +9,7 @@ import (
|
||||
is "gotest.tools/v3/assert/cmp"
|
||||
)
|
||||
|
||||
func TestGetTimestamp(t *testing.T) {
|
||||
func TestParse(t *testing.T) {
|
||||
now := time.Date(2020, 1, 2, 3, 4, 5, 123456789, time.UTC)
|
||||
tests := []struct {
|
||||
in string
|
||||
@@ -73,26 +71,20 @@ func TestGetTimestamp(t *testing.T) {
|
||||
name = "<empty>"
|
||||
}
|
||||
t.Run(name, func(t *testing.T) {
|
||||
out, err := timestamp.GetTimestamp(tc.in, now)
|
||||
out, err := timestamp.Parse(tc.in, now)
|
||||
if tc.expectedErr {
|
||||
assert.Assert(t, err != nil, "expected error for %q, got none", tc.in)
|
||||
return
|
||||
}
|
||||
assert.NilError(t, err)
|
||||
|
||||
exp, err := time.Parse(time.RFC3339Nano, tc.expected)
|
||||
want, err := time.Parse(time.RFC3339Nano, tc.expected)
|
||||
assert.NilError(t, err, "invalid expected value")
|
||||
|
||||
var want string
|
||||
if exp.Nanosecond() == 0 {
|
||||
want = strconv.FormatInt(exp.Unix(), 10)
|
||||
} else {
|
||||
want = fmt.Sprintf("%d.%09d", exp.Unix(), exp.Nanosecond())
|
||||
}
|
||||
assert.Assert(t, out == want,
|
||||
assert.Assert(t, out.Equal(want),
|
||||
"expected: %s\ngot: %s",
|
||||
want,
|
||||
out,
|
||||
want.Format(time.RFC3339Nano),
|
||||
out.Format(time.RFC3339Nano),
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -96,20 +96,16 @@ func newFilter(args filters.Args) (Filter, error) {
|
||||
if err := args.WalkValues("type", validateNetworkTypeFilter); err != nil {
|
||||
return Filter{}, err
|
||||
}
|
||||
until := time.Time{}
|
||||
var until time.Time
|
||||
if untilFilters := args.Get("until"); len(untilFilters) > 0 {
|
||||
if len(untilFilters) > 1 {
|
||||
return Filter{}, errdefs.InvalidParameter(errors.New("more than one until filter specified"))
|
||||
}
|
||||
ts, err := timestamp.GetTimestamp(untilFilters[0], time.Now())
|
||||
var err error
|
||||
until, err = timestamp.Parse(untilFilters[0], time.Now())
|
||||
if err != nil {
|
||||
return Filter{}, errdefs.InvalidParameter(err)
|
||||
}
|
||||
seconds, nanoseconds, err := timestamp.ParseTimestamps(ts, 0)
|
||||
if err != nil {
|
||||
return Filter{}, errdefs.InvalidParameter(err)
|
||||
}
|
||||
until = time.Unix(seconds, nanoseconds)
|
||||
}
|
||||
return Filter{
|
||||
args: args,
|
||||
|
||||
+5
-11
@@ -205,24 +205,18 @@ func (daemon *Daemon) NetworkPrune(ctx context.Context, filterArgs filters.Args)
|
||||
}
|
||||
|
||||
func getUntilFromPruneFilters(pruneFilters filters.Args) (time.Time, error) {
|
||||
until := time.Time{}
|
||||
if !pruneFilters.Contains("until") {
|
||||
return until, nil
|
||||
return time.Time{}, nil
|
||||
}
|
||||
untilFilters := pruneFilters.Get("until")
|
||||
if len(untilFilters) > 1 {
|
||||
return until, errdefs.InvalidParameter(errors.New("more than one until filter specified"))
|
||||
return time.Time{}, errdefs.InvalidParameter(errors.New("more than one until filter specified"))
|
||||
}
|
||||
ts, err := timestamp.GetTimestamp(untilFilters[0], time.Now())
|
||||
t, err := timestamp.Parse(untilFilters[0], time.Now())
|
||||
if err != nil {
|
||||
return until, errdefs.InvalidParameter(err)
|
||||
return time.Time{}, errdefs.InvalidParameter(err)
|
||||
}
|
||||
seconds, nanoseconds, err := timestamp.ParseTimestamps(ts, 0)
|
||||
if err != nil {
|
||||
return until, errdefs.InvalidParameter(err)
|
||||
}
|
||||
until = time.Unix(seconds, nanoseconds)
|
||||
return until, nil
|
||||
return t, nil
|
||||
}
|
||||
|
||||
func matchLabels(pruneFilters filters.Args, labels map[string]string) bool {
|
||||
|
||||
Reference in new issue
Block a user