From edda7406dd754978112a4096acc6c56653a5b0ab Mon Sep 17 00:00:00 2001 From: Iwasaki Yudai Date: Wed, 7 Mar 2018 16:32:04 -0800 Subject: [PATCH] *: enforce max lease TTL with 9,000,000,000 seconds math.MaxInt64 / time.Second is 9,223,372,036. 9,000,000,000 is easier to remember/document. Closes #9374. --- etcdserver/api/v3rpc/rpctypes/error.go | 15 +++++++++------ etcdserver/api/v3rpc/util.go | 5 +++-- lease/lessor.go | 14 +++++++++++--- lease/lessor_test.go | 14 ++++++++++++++ 4 files changed, 37 insertions(+), 11 deletions(-) diff --git a/etcdserver/api/v3rpc/rpctypes/error.go b/etcdserver/api/v3rpc/rpctypes/error.go index 446e4f6b8709..55eab38ef17b 100644 --- a/etcdserver/api/v3rpc/rpctypes/error.go +++ b/etcdserver/api/v3rpc/rpctypes/error.go @@ -31,8 +31,9 @@ var ( ErrGRPCFutureRev = status.New(codes.OutOfRange, "etcdserver: mvcc: required revision is a future revision").Err() ErrGRPCNoSpace = status.New(codes.ResourceExhausted, "etcdserver: mvcc: database space exceeded").Err() - ErrGRPCLeaseNotFound = status.New(codes.NotFound, "etcdserver: requested lease not found").Err() - ErrGRPCLeaseExist = status.New(codes.FailedPrecondition, "etcdserver: lease already exists").Err() + ErrGRPCLeaseNotFound = status.New(codes.NotFound, "etcdserver: requested lease not found").Err() + ErrGRPCLeaseExist = status.New(codes.FailedPrecondition, "etcdserver: lease already exists").Err() + ErrGRPCLeaseTTLTooLarge = status.New(codes.OutOfRange, "etcdserver: too large lease TTL").Err() ErrGRPCMemberExist = status.New(codes.FailedPrecondition, "etcdserver: member ID already exist").Err() ErrGRPCPeerURLExist = status.New(codes.FailedPrecondition, "etcdserver: Peer URLs already exists").Err() @@ -80,8 +81,9 @@ var ( ErrorDesc(ErrGRPCFutureRev): ErrGRPCFutureRev, ErrorDesc(ErrGRPCNoSpace): ErrGRPCNoSpace, - ErrorDesc(ErrGRPCLeaseNotFound): ErrGRPCLeaseNotFound, - ErrorDesc(ErrGRPCLeaseExist): ErrGRPCLeaseExist, + ErrorDesc(ErrGRPCLeaseNotFound): ErrGRPCLeaseNotFound, + ErrorDesc(ErrGRPCLeaseExist): ErrGRPCLeaseExist, + ErrorDesc(ErrGRPCLeaseTTLTooLarge): ErrGRPCLeaseTTLTooLarge, ErrorDesc(ErrGRPCMemberExist): ErrGRPCMemberExist, ErrorDesc(ErrGRPCPeerURLExist): ErrGRPCPeerURLExist, @@ -131,8 +133,9 @@ var ( ErrFutureRev = Error(ErrGRPCFutureRev) ErrNoSpace = Error(ErrGRPCNoSpace) - ErrLeaseNotFound = Error(ErrGRPCLeaseNotFound) - ErrLeaseExist = Error(ErrGRPCLeaseExist) + ErrLeaseNotFound = Error(ErrGRPCLeaseNotFound) + ErrLeaseExist = Error(ErrGRPCLeaseExist) + ErrLeaseTTLTooLarge = Error(ErrGRPCLeaseTTLTooLarge) ErrMemberExist = Error(ErrGRPCMemberExist) ErrPeerURLExist = Error(ErrGRPCPeerURLExist) diff --git a/etcdserver/api/v3rpc/util.go b/etcdserver/api/v3rpc/util.go index 328135b1e676..799c1197d8dd 100644 --- a/etcdserver/api/v3rpc/util.go +++ b/etcdserver/api/v3rpc/util.go @@ -52,8 +52,9 @@ var toGRPCErrorMap = map[error]error{ etcdserver.ErrKeyNotFound: rpctypes.ErrGRPCKeyNotFound, etcdserver.ErrCorrupt: rpctypes.ErrGRPCCorrupt, - lease.ErrLeaseNotFound: rpctypes.ErrGRPCLeaseNotFound, - lease.ErrLeaseExists: rpctypes.ErrGRPCLeaseExist, + lease.ErrLeaseNotFound: rpctypes.ErrGRPCLeaseNotFound, + lease.ErrLeaseExists: rpctypes.ErrGRPCLeaseExist, + lease.ErrLeaseTTLTooLarge: rpctypes.ErrGRPCLeaseTTLTooLarge, auth.ErrRootUserNotExist: rpctypes.ErrGRPCRootUserNotExist, auth.ErrRootRoleNotExist: rpctypes.ErrGRPCRootRoleNotExist, diff --git a/lease/lessor.go b/lease/lessor.go index 30dd23806931..31f645fa3371 100644 --- a/lease/lessor.go +++ b/lease/lessor.go @@ -29,6 +29,9 @@ import ( // NoLease is a special LeaseID representing the absence of a lease. const NoLease = LeaseID(0) +// MaxLeaseTTL is the maximum lease TTL value +const MaxLeaseTTL = 9000000000 + var ( forever = time.Time{} @@ -37,9 +40,10 @@ var ( // maximum number of leases to revoke per second; configurable for tests leaseRevokeRate = 1000 - ErrNotPrimary = errors.New("not a primary lessor") - ErrLeaseNotFound = errors.New("lease not found") - ErrLeaseExists = errors.New("lease already exists") + ErrNotPrimary = errors.New("not a primary lessor") + ErrLeaseNotFound = errors.New("lease not found") + ErrLeaseExists = errors.New("lease already exists") + ErrLeaseTTLTooLarge = errors.New("too large lease TTL") ) // TxnDelete is a TxnWrite that only permits deletes. Defined here @@ -198,6 +202,10 @@ func (le *lessor) Grant(id LeaseID, ttl int64) (*Lease, error) { return nil, ErrLeaseNotFound } + if ttl > MaxLeaseTTL { + return nil, ErrLeaseTTLTooLarge + } + // TODO: when lessor is under high load, it should give out lease // with longer TTL to reduce renew load. l := &Lease{ diff --git a/lease/lessor_test.go b/lease/lessor_test.go index 3f6a5ce504b4..3a39e846f729 100644 --- a/lease/lessor_test.go +++ b/lease/lessor_test.go @@ -451,6 +451,20 @@ func TestLessorExpireAndDemote(t *testing.T) { } } +func TestLessorMaxTTL(t *testing.T) { + dir, be := NewTestBackend(t) + defer os.RemoveAll(dir) + defer be.Close() + + le := newLessor(be, minLeaseTTL) + defer le.Stop() + + _, err := le.Grant(1, MaxLeaseTTL+1) + if err != ErrLeaseTTLTooLarge { + t.Fatalf("grant unexpectedly succeeded") + } +} + type fakeDeleter struct { deleted []string tx backend.BatchTx