mirror of
https://github.com/minio/minio.git
synced 2025-01-11 15:03:22 -05:00
Add NTP retention time (#8548)
This commit is contained in:
parent
4e9de58675
commit
fd0fa4e5c5
@ -28,6 +28,8 @@ import (
|
||||
"time"
|
||||
|
||||
xhttp "github.com/minio/minio/cmd/http"
|
||||
"github.com/minio/minio/cmd/logger"
|
||||
"github.com/minio/minio/pkg/env"
|
||||
)
|
||||
|
||||
// RetentionMode - object retention mode.
|
||||
@ -65,6 +67,14 @@ var (
|
||||
errObjectLockInvalidHeaders = errors.New("x-amz-object-lock-retain-until-date and x-amz-object-lock-mode must both be supplied")
|
||||
)
|
||||
|
||||
const (
|
||||
ntpServerEnv = "MINIO_NTP_SERVER"
|
||||
)
|
||||
|
||||
var (
|
||||
ntpServer = env.Get(ntpServerEnv, "")
|
||||
)
|
||||
|
||||
// Retention - bucket level retention configuration.
|
||||
type Retention struct {
|
||||
Mode RetentionMode
|
||||
@ -78,7 +88,13 @@ func (r Retention) IsEmpty() bool {
|
||||
|
||||
// Retain - check whether given date is retainable by validity time.
|
||||
func (r Retention) Retain(created time.Time) bool {
|
||||
return globalWORMEnabled || created.Add(r.Validity).After(time.Now())
|
||||
t, err := UTCNowNTP()
|
||||
if err != nil {
|
||||
logger.LogIf(context.Background(), err)
|
||||
// Retain
|
||||
return true
|
||||
}
|
||||
return globalWORMEnabled || created.Add(r.Validity).After(t)
|
||||
}
|
||||
|
||||
// BucketObjectLockConfig - map of bucket and retention configuration.
|
||||
@ -205,11 +221,19 @@ func (config *ObjectLockConfig) UnmarshalXML(d *xml.Decoder, start xml.StartElem
|
||||
func (config *ObjectLockConfig) ToRetention() (r Retention) {
|
||||
if config.Rule != nil {
|
||||
r.Mode = config.Rule.DefaultRetention.Mode
|
||||
utcNow := time.Now().UTC()
|
||||
|
||||
t, err := UTCNowNTP()
|
||||
if err != nil {
|
||||
logger.LogIf(context.Background(), err)
|
||||
// Do not change any configuration
|
||||
// upon NTP failure.
|
||||
return r
|
||||
}
|
||||
|
||||
if config.Rule.DefaultRetention.Days != nil {
|
||||
r.Validity = utcNow.AddDate(0, 0, int(*config.Rule.DefaultRetention.Days)).Sub(utcNow)
|
||||
r.Validity = t.AddDate(0, 0, int(*config.Rule.DefaultRetention.Days)).Sub(t)
|
||||
} else {
|
||||
r.Validity = utcNow.AddDate(int(*config.Rule.DefaultRetention.Years), 0, 0).Sub(utcNow)
|
||||
r.Validity = t.AddDate(int(*config.Rule.DefaultRetention.Years), 0, 0).Sub(t)
|
||||
}
|
||||
}
|
||||
|
||||
@ -282,9 +306,17 @@ func parseObjectRetention(reader io.Reader) (*ObjectRetention, error) {
|
||||
if ret.Mode != Compliance && ret.Mode != Governance {
|
||||
return &ret, errUnknownWORMModeDirective
|
||||
}
|
||||
if ret.RetainUntilDate.Before(time.Now()) {
|
||||
|
||||
t, err := UTCNowNTP()
|
||||
if err != nil {
|
||||
logger.LogIf(context.Background(), err)
|
||||
return &ret, errPastObjectLockRetainDate
|
||||
}
|
||||
|
||||
if ret.RetainUntilDate.Before(t) {
|
||||
return &ret, errPastObjectLockRetainDate
|
||||
}
|
||||
|
||||
return &ret, nil
|
||||
}
|
||||
|
||||
@ -334,7 +366,14 @@ func parseObjectLockRetentionHeaders(h http.Header) (rmode RetentionMode, r Rete
|
||||
if err != nil {
|
||||
return rmode, r, errInvalidRetentionDate
|
||||
}
|
||||
if retDate.Before(time.Now()) {
|
||||
|
||||
t, err := UTCNowNTP()
|
||||
if err != nil {
|
||||
logger.LogIf(context.Background(), err)
|
||||
return rmode, r, errPastObjectLockRetainDate
|
||||
}
|
||||
|
||||
if retDate.Before(t) {
|
||||
return rmode, r, errPastObjectLockRetainDate
|
||||
}
|
||||
}
|
||||
@ -392,7 +431,12 @@ func checkGovernanceBypassAllowed(ctx context.Context, r *http.Request, bucket,
|
||||
}
|
||||
if ret.Mode == Governance {
|
||||
if !isObjectLockGovernanceBypassSet(r.Header) {
|
||||
if ret.RetainUntilDate.After(UTCNow()) {
|
||||
t, err := UTCNowNTP()
|
||||
if err != nil {
|
||||
logger.LogIf(ctx, err)
|
||||
return oi, ErrObjectLocked
|
||||
}
|
||||
if ret.RetainUntilDate.After(t) {
|
||||
return oi, ErrObjectLocked
|
||||
}
|
||||
return oi, ErrNone
|
||||
@ -440,7 +484,12 @@ func checkPutObjectRetentionAllowed(ctx context.Context, r *http.Request, bucket
|
||||
return mode, retainDate, toAPIErrorCode(ctx, err)
|
||||
}
|
||||
// AWS S3 just creates a new version of object when an object is being overwritten.
|
||||
if objExists && retainDate.After(UTCNow()) {
|
||||
t, err := UTCNowNTP()
|
||||
if err != nil {
|
||||
logger.LogIf(ctx, err)
|
||||
return mode, retainDate, ErrObjectLocked
|
||||
}
|
||||
if objExists && retainDate.After(t) {
|
||||
return mode, retainDate, ErrObjectLocked
|
||||
}
|
||||
if rMode == Invalid {
|
||||
@ -455,12 +504,17 @@ func checkPutObjectRetentionAllowed(ctx context.Context, r *http.Request, bucket
|
||||
if retentionPermErr != ErrNone {
|
||||
return mode, retainDate, retentionPermErr
|
||||
}
|
||||
t, err := UTCNowNTP()
|
||||
if err != nil {
|
||||
logger.LogIf(ctx, err)
|
||||
return mode, retainDate, ErrObjectLocked
|
||||
}
|
||||
// AWS S3 just creates a new version of object when an object is being overwritten.
|
||||
if objExists && retainDate.After(UTCNow()) {
|
||||
if objExists && retainDate.After(t) {
|
||||
return mode, retainDate, ErrObjectLocked
|
||||
}
|
||||
// inherit retention from bucket configuration
|
||||
return retention.Mode, RetentionDate{UTCNow().Add(retention.Validity)}, ErrNone
|
||||
return retention.Mode, RetentionDate{t.Add(retention.Validity)}, ErrNone
|
||||
}
|
||||
return mode, retainDate, ErrNone
|
||||
}
|
||||
|
12
cmd/utils.go
12
cmd/utils.go
@ -35,6 +35,7 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/beevik/ntp"
|
||||
xhttp "github.com/minio/minio/cmd/http"
|
||||
"github.com/minio/minio/cmd/logger"
|
||||
"github.com/minio/minio/pkg/handlers"
|
||||
@ -314,6 +315,17 @@ func UTCNow() time.Time {
|
||||
return time.Now().UTC()
|
||||
}
|
||||
|
||||
// UTCNowNTP - is similar in functionality to UTCNow()
|
||||
// but only used when we do not wish to rely on system
|
||||
// time.
|
||||
func UTCNowNTP() (time.Time, error) {
|
||||
// ntp server is disabled
|
||||
if ntpServer == "" {
|
||||
return UTCNow(), nil
|
||||
}
|
||||
return ntp.Time(ntpServer)
|
||||
}
|
||||
|
||||
// GenETag - generate UUID based ETag
|
||||
func GenETag() string {
|
||||
return ToS3ETag(getMD5Hash([]byte(mustGetUUID())))
|
||||
|
1
go.mod
1
go.mod
@ -11,6 +11,7 @@ require (
|
||||
github.com/aliyun/aliyun-oss-go-sdk v0.0.0-20190307165228-86c17b95fcd5
|
||||
github.com/aws/aws-sdk-go v1.20.21
|
||||
github.com/bcicen/jstream v0.0.0-20190220045926-16c1f8af81c2
|
||||
github.com/beevik/ntp v0.2.0
|
||||
github.com/cheggaaa/pb v1.0.28
|
||||
github.com/coredns/coredns v1.4.0
|
||||
github.com/coreos/etcd v3.3.12+incompatible
|
||||
|
2
go.sum
2
go.sum
@ -63,6 +63,8 @@ github.com/baiyubin/aliyun-sts-go-sdk v0.0.0-20180326062324-cfa1a18b161f h1:ZNv7
|
||||
github.com/baiyubin/aliyun-sts-go-sdk v0.0.0-20180326062324-cfa1a18b161f/go.mod h1:AuiFmCCPBSrqvVMvuqFuk0qogytodnVFVSN5CeJB8Gc=
|
||||
github.com/bcicen/jstream v0.0.0-20190220045926-16c1f8af81c2 h1:M+TYzBcNIRyzPRg66ndEqUMd7oWDmhvdQmaPC6EZNwM=
|
||||
github.com/bcicen/jstream v0.0.0-20190220045926-16c1f8af81c2/go.mod h1:RDu/qcrnpEdJC/p8tx34+YBFqqX71lB7dOX9QE+ZC4M=
|
||||
github.com/beevik/ntp v0.2.0 h1:sGsd+kAXzT0bfVfzJfce04g+dSRfrs+tbQW8lweuYgw=
|
||||
github.com/beevik/ntp v0.2.0/go.mod h1:hIHWr+l3+/clUnF44zdK+CWW7fO8dR5cIylAQ76NRpg=
|
||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973 h1:xJ4a3vCFaGF/jqvzLMYoU8P317H5OQ+Via4RmuPwCS0=
|
||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
|
||||
|
Loading…
Reference in New Issue
Block a user