Skip to content

Commit

Permalink
Merge pull request #8358 from gyuho/lease-list
Browse files Browse the repository at this point in the history
api: lease list
  • Loading branch information
gyuho authored Aug 14, 2017
2 parents 8df2132 + 01f1013 commit deb0098
Show file tree
Hide file tree
Showing 21 changed files with 1,169 additions and 340 deletions.
24 changes: 24 additions & 0 deletions Documentation/dev-guide/api_reference_v3.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ This is a generated documentation. Please read the proto files for more.
| LeaseRevoke | LeaseRevokeRequest | LeaseRevokeResponse | LeaseRevoke revokes a lease. All keys attached to the lease will expire and be deleted. |
| LeaseKeepAlive | LeaseKeepAliveRequest | LeaseKeepAliveResponse | LeaseKeepAlive keeps the lease alive by streaming keep alive requests from the client to the server and streaming keep alive responses from the server to the client. |
| LeaseTimeToLive | LeaseTimeToLiveRequest | LeaseTimeToLiveResponse | LeaseTimeToLive retrieves lease information. |
| LeaseLeases | LeaseLeasesRequest | LeaseLeasesResponse | LeaseLeases lists all existing leases. |



Expand Down Expand Up @@ -513,6 +514,21 @@ Empty field.



##### message `LeaseLeasesRequest` (etcdserver/etcdserverpb/rpc.proto)

Empty field.



##### message `LeaseLeasesResponse` (etcdserver/etcdserverpb/rpc.proto)

| Field | Description | Type |
| ----- | ----------- | ---- |
| header | | ResponseHeader |
| leases | | (slice of) LeaseStatus |



##### message `LeaseRevokeRequest` (etcdserver/etcdserverpb/rpc.proto)

| Field | Description | Type |
Expand All @@ -529,6 +545,14 @@ Empty field.



##### message `LeaseStatus` (etcdserver/etcdserverpb/rpc.proto)

| Field | Description | Type |
| ----- | ----------- | ---- |
| ID | | int64 |



##### message `LeaseTimeToLiveRequest` (etcdserver/etcdserverpb/rpc.proto)

| Field | Description | Type |
Expand Down
53 changes: 53 additions & 0 deletions Documentation/dev-guide/apispec/swagger/rpc.swagger.json
Original file line number Diff line number Diff line change
Expand Up @@ -609,6 +609,33 @@
}
}
},
"/v3alpha/kv/lease/leases": {
"post": {
"tags": [
"Lease"
],
"summary": "LeaseLeases lists all existing leases.",
"operationId": "LeaseLeases",
"parameters": [
{
"name": "body",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/etcdserverpbLeaseLeasesRequest"
}
}
],
"responses": {
"200": {
"description": "(empty)",
"schema": {
"$ref": "#/definitions/etcdserverpbLeaseLeasesResponse"
}
}
}
}
},
"/v3alpha/kv/lease/revoke": {
"post": {
"tags": [
Expand Down Expand Up @@ -1666,6 +1693,23 @@
}
}
},
"etcdserverpbLeaseLeasesRequest": {
"type": "object"
},
"etcdserverpbLeaseLeasesResponse": {
"type": "object",
"properties": {
"header": {
"$ref": "#/definitions/etcdserverpbResponseHeader"
},
"leases": {
"type": "array",
"items": {
"$ref": "#/definitions/etcdserverpbLeaseStatus"
}
}
}
},
"etcdserverpbLeaseRevokeRequest": {
"type": "object",
"properties": {
Expand All @@ -1684,6 +1728,15 @@
}
}
},
"etcdserverpbLeaseStatus": {
"type": "object",
"properties": {
"ID": {
"type": "string",
"format": "int64"
}
}
},
"etcdserverpbLeaseTimeToLiveRequest": {
"type": "object",
"properties": {
Expand Down
31 changes: 31 additions & 0 deletions clientv3/integration/lease_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -574,6 +574,37 @@ func TestLeaseTimeToLiveLeaseNotFound(t *testing.T) {
}
}

func TestLeaseLeases(t *testing.T) {
defer testutil.AfterTest(t)

clus := integration.NewClusterV3(t, &integration.ClusterConfig{Size: 1})
defer clus.Terminate(t)

cli := clus.RandClient()

ids := []clientv3.LeaseID{}
for i := 0; i < 5; i++ {
resp, err := cli.Grant(context.Background(), 10)
if err != nil {
t.Errorf("failed to create lease %v", err)
}
ids = append(ids, resp.ID)
}

resp, err := cli.Leases(context.Background())
if err != nil {
t.Fatal(err)
}
if len(resp.Leases) != 5 {
t.Fatalf("len(resp.Leases) expected 5, got %d", len(resp.Leases))
}
for i := range resp.Leases {
if ids[i] != resp.Leases[i].ID {
t.Fatalf("#%d: lease ID expected %d, got %d", i, ids[i], resp.Leases[i].ID)
}
}
}

// TestLeaseRenewLostQuorum ensures keepalives work after losing quorum
// for a while.
func TestLeaseRenewLostQuorum(t *testing.T) {
Expand Down
31 changes: 31 additions & 0 deletions clientv3/lease.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,18 @@ type LeaseTimeToLiveResponse struct {
Keys [][]byte `json:"keys"`
}

// LeaseStatus represents a lease status.
type LeaseStatus struct {
ID LeaseID `json:"id"`
// TODO: TTL int64
}

// LeaseLeasesResponse is used to convert the protobuf lease list response.
type LeaseLeasesResponse struct {
*pb.ResponseHeader
Leases []LeaseStatus `json:"leases"`
}

const (
// defaultTTL is the assumed lease TTL used for the first keepalive
// deadline before the actual TTL is known to the client.
Expand Down Expand Up @@ -98,6 +110,9 @@ type Lease interface {
// TimeToLive retrieves the lease information of the given lease ID.
TimeToLive(ctx context.Context, id LeaseID, opts ...LeaseOption) (*LeaseTimeToLiveResponse, error)

// Leases retrieves all leases.
Leases(ctx context.Context) (*LeaseLeasesResponse, error)

// KeepAlive keeps the given lease alive forever.
KeepAlive(ctx context.Context, id LeaseID) (<-chan *LeaseKeepAliveResponse, error)

Expand Down Expand Up @@ -219,6 +234,22 @@ func (l *lessor) TimeToLive(ctx context.Context, id LeaseID, opts ...LeaseOption
}
}

func (l *lessor) Leases(ctx context.Context) (*LeaseLeasesResponse, error) {
for {
resp, err := l.remote.LeaseLeases(ctx, &pb.LeaseLeasesRequest{}, grpc.FailFast(false))
if err == nil {
leases := make([]LeaseStatus, len(resp.Leases))
for i := range resp.Leases {
leases[i] = LeaseStatus{ID: LeaseID(resp.Leases[i].ID)}
}
return &LeaseLeasesResponse{ResponseHeader: resp.GetHeader(), Leases: leases}, nil
}
if isHaltErr(ctx, err) {
return nil, toErr(ctx, err)
}
}
}

func (l *lessor) KeepAlive(ctx context.Context, id LeaseID) (<-chan *LeaseKeepAliveResponse, error) {
ch := make(chan *LeaseKeepAliveResponse, leaseResponseChSize)

Expand Down
21 changes: 21 additions & 0 deletions e2e/ctl_v3_lease_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
)

func TestCtlV3LeaseGrantTimeToLive(t *testing.T) { testCtl(t, leaseTestGrantTimeToLive) }
func TestCtlV3LeaseGrantLeases(t *testing.T) { testCtl(t, leaseTestGrantLeasesList) }
func TestCtlV3LeaseKeepAlive(t *testing.T) { testCtl(t, leaseTestKeepAlive) }
func TestCtlV3LeaseRevoke(t *testing.T) { testCtl(t, leaseTestRevoke) }

Expand Down Expand Up @@ -51,6 +52,26 @@ func leaseTestGrantTimeToLive(cx ctlCtx) {
}
}

func leaseTestGrantLeasesList(cx ctlCtx) {
id, err := ctlV3LeaseGrant(cx, 10)
if err != nil {
cx.t.Fatal(err)
}

cmdArgs := append(cx.PrefixArgs(), "lease", "list")
proc, err := spawnCmd(cmdArgs)
if err != nil {
cx.t.Fatal(err)
}
_, err = proc.Expect(id)
if err != nil {
cx.t.Fatal(err)
}
if err = proc.Close(); err != nil {
cx.t.Fatal(err)
}
}

func leaseTestKeepAlive(cx ctlCtx) {
// put with TTL 10 seconds and keep-alive
leaseID, err := ctlV3LeaseGrant(cx, 10)
Expand Down
26 changes: 23 additions & 3 deletions etcdctl/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -439,6 +439,26 @@ Prints lease information.
# {"cluster_id":17186838941855831277,"member_id":4845372305070271874,"revision":3,"raft_term":2,"id":3279279168933706764,"ttl":459,"granted-ttl":500,"keys":["Zm9vMQ==","Zm9vMg=="]}
```

### LEASE LIST

LEASE LIST lists all active leases.

RPC: LeaseLeases

#### Output

Prints a message with a list of active leases.

#### Example

```bash
./etcdctl lease grant 10
# lease 32695410dcc0ca06 granted with TTL(10s)

./etcdctl lease list
32695410dcc0ca06
```

### LEASE KEEP-ALIVE \<leaseID\>

LEASE KEEP-ALIVE periodically refreshes a lease so it does not expire.
Expand Down Expand Up @@ -736,9 +756,9 @@ If NOSPACE alarm is present:

### DEFRAG [options]

DEFRAG defragments the backend database file for a set of given endpoints while etcd is running, or directly defragments an
etcd data directory while etcd is not running. When an etcd member reclaims storage space from deleted and compacted keys, the
space is kept in a free list and the database file remains the same size. By defragmenting the database, the etcd member
DEFRAG defragments the backend database file for a set of given endpoints while etcd is running, or directly defragments an
etcd data directory while etcd is not running. When an etcd member reclaims storage space from deleted and compacted keys, the
space is kept in a free list and the database file remains the same size. By defragmenting the database, the etcd member
releases this free space back to the file system.

#### Options
Expand Down
20 changes: 20 additions & 0 deletions etcdctl/ctlv3/command/lease_command.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ func NewLeaseCommand() *cobra.Command {
lc.AddCommand(NewLeaseGrantCommand())
lc.AddCommand(NewLeaseRevokeCommand())
lc.AddCommand(NewLeaseTimeToLiveCommand())
lc.AddCommand(NewLeaseListCommand())
lc.AddCommand(NewLeaseKeepAliveCommand())

return lc
Expand Down Expand Up @@ -129,6 +130,25 @@ func leaseTimeToLiveCommandFunc(cmd *cobra.Command, args []string) {
display.TimeToLive(*resp, timeToLiveKeys)
}

// NewLeaseListCommand returns the cobra command for "lease list".
func NewLeaseListCommand() *cobra.Command {
lc := &cobra.Command{
Use: "list",
Short: "List all active leases",
Run: leaseListCommandFunc,
}
return lc
}

// leaseListCommandFunc executes the "lease list" command.
func leaseListCommandFunc(cmd *cobra.Command, args []string) {
resp, rerr := mustClientFromCmd(cmd).Leases(context.TODO())
if rerr != nil {
ExitWithError(ExitBadConnection, rerr)
}
display.Leases(*resp)
}

// NewLeaseKeepAliveCommand returns the cobra command for "lease keep-alive".
func NewLeaseKeepAliveCommand() *cobra.Command {
lc := &cobra.Command{
Expand Down
2 changes: 2 additions & 0 deletions etcdctl/ctlv3/command/printer.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ type printer interface {
Revoke(id v3.LeaseID, r v3.LeaseRevokeResponse)
KeepAlive(r v3.LeaseKeepAliveResponse)
TimeToLive(r v3.LeaseTimeToLiveResponse, keys bool)
Leases(r v3.LeaseLeasesResponse)

MemberAdd(v3.MemberAddResponse)
MemberRemove(id uint64, r v3.MemberRemoveResponse)
Expand Down Expand Up @@ -96,6 +97,7 @@ func (p *printerRPC) Grant(r v3.LeaseGrantResponse) { p.p(r
func (p *printerRPC) Revoke(id v3.LeaseID, r v3.LeaseRevokeResponse) { p.p(r) }
func (p *printerRPC) KeepAlive(r v3.LeaseKeepAliveResponse) { p.p(r) }
func (p *printerRPC) TimeToLive(r v3.LeaseTimeToLiveResponse, keys bool) { p.p(&r) }
func (p *printerRPC) Leases(r v3.LeaseLeasesResponse) { p.p(&r) }

func (p *printerRPC) MemberAdd(r v3.MemberAddResponse) { p.p((*pb.MemberAddResponse)(&r)) }
func (p *printerRPC) MemberRemove(id uint64, r v3.MemberRemoveResponse) {
Expand Down
7 changes: 7 additions & 0 deletions etcdctl/ctlv3/command/printer_fields.go
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,13 @@ func (p *fieldsPrinter) TimeToLive(r v3.LeaseTimeToLiveResponse, keys bool) {
}
}

func (p *fieldsPrinter) Leases(r v3.LeaseLeasesResponse) {
p.hdr(r.ResponseHeader)
for _, item := range r.Leases {
fmt.Println(`"ID" :`, item.ID)
}
}

func (p *fieldsPrinter) MemberList(r v3.MemberListResponse) {
p.hdr(r.Header)
for _, m := range r.Members {
Expand Down
7 changes: 7 additions & 0 deletions etcdctl/ctlv3/command/printer_simple.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,13 @@ func (s *simplePrinter) TimeToLive(resp v3.LeaseTimeToLiveResponse, keys bool) {
fmt.Println(txt)
}

func (s *simplePrinter) Leases(resp v3.LeaseLeasesResponse) {
fmt.Printf("found %d leases\n", len(resp.Leases))
for _, item := range resp.Leases {
fmt.Printf("%016x\n", item.ID)
}
}

func (s *simplePrinter) Alarm(resp v3.AlarmResponse) {
for _, e := range resp.Alarms {
fmt.Printf("%+v\n", e)
Expand Down
15 changes: 15 additions & 0 deletions etcdserver/api/v3rpc/lease.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,21 @@ func (ls *LeaseServer) LeaseTimeToLive(ctx context.Context, rr *pb.LeaseTimeToLi
return resp, nil
}

func (ls *LeaseServer) LeaseLeases(ctx context.Context, rr *pb.LeaseLeasesRequest) (*pb.LeaseLeasesResponse, error) {
resp, err := ls.le.LeaseLeases(ctx, rr)
if err != nil && err != lease.ErrLeaseNotFound {
return nil, togRPCError(err)
}
if err == lease.ErrLeaseNotFound {
resp = &pb.LeaseLeasesResponse{
Header: &pb.ResponseHeader{},
Leases: []*pb.LeaseStatus{},
}
}
ls.hdr.fill(resp.Header)
return resp, nil
}

func (ls *LeaseServer) LeaseKeepAlive(stream pb.Lease_LeaseKeepAliveServer) (err error) {
errc := make(chan error, 1)
go func() {
Expand Down
3 changes: 3 additions & 0 deletions etcdserver/etcdserverpb/etcdserver.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit deb0098

Please sign in to comment.