From 00e63cf61cde5555d0f6161597db314f84389cbd Mon Sep 17 00:00:00 2001 From: Gyu-Ho Lee Date: Wed, 2 Aug 2017 13:57:44 -0700 Subject: [PATCH] etcdctl/ctlv3: add 'lease list' command Signed-off-by: Gyu-Ho Lee --- e2e/ctl_v3_lease_test.go | 21 +++++++++++++++++++++ etcdctl/README.md | 20 ++++++++++++++++++++ etcdctl/ctlv3/command/lease_command.go | 20 ++++++++++++++++++++ etcdctl/ctlv3/command/printer.go | 2 ++ etcdctl/ctlv3/command/printer_fields.go | 8 ++++++++ etcdctl/ctlv3/command/printer_simple.go | 7 +++++++ 6 files changed, 78 insertions(+) diff --git a/e2e/ctl_v3_lease_test.go b/e2e/ctl_v3_lease_test.go index d27060a6430f..f13ffbd430c0 100644 --- a/e2e/ctl_v3_lease_test.go +++ b/e2e/ctl_v3_lease_test.go @@ -22,6 +22,7 @@ import ( ) func TestCtlV3LeaseGrantTimeToLive(t *testing.T) { testCtl(t, leaseTestGrantTimeToLive) } +func TestCtlV3LeaseGrantList(t *testing.T) { testCtl(t, leaseTestGrantList) } func TestCtlV3LeaseKeepAlive(t *testing.T) { testCtl(t, leaseTestKeepAlive) } func TestCtlV3LeaseRevoke(t *testing.T) { testCtl(t, leaseTestRevoke) } @@ -51,6 +52,26 @@ func leaseTestGrantTimeToLive(cx ctlCtx) { } } +func leaseTestGrantList(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(fmt.Sprintf("%s (TTL: %ds)", id, 10)) + 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) diff --git a/etcdctl/README.md b/etcdctl/README.md index 6823e7c8ff62..3612b273b634 100644 --- a/etcdctl/README.md +++ b/etcdctl/README.md @@ -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 with TTL values. + +RPC: LeaseList + +#### Output + +Prints a message with a list of granted leases. + +#### Example + +```bash +./etcdctl lease grant 10 +# lease 32695410dcc0ca06 granted with TTL(10s) + +./etcdctl lease list +32695410dcc0ca06 (TTL: 10s) +``` + ### LEASE KEEP-ALIVE \ LEASE KEEP-ALIVE periodically refreshes a lease so it does not expire. diff --git a/etcdctl/ctlv3/command/lease_command.go b/etcdctl/ctlv3/command/lease_command.go index 0afb3d69c7cf..9aeb646a0f6b 100644 --- a/etcdctl/ctlv3/command/lease_command.go +++ b/etcdctl/ctlv3/command/lease_command.go @@ -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 @@ -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 leases", + Run: leaseListCommandFunc, + } + return lc +} + +// leaseListCommandFunc executes the "lease list" command. +func leaseListCommandFunc(cmd *cobra.Command, args []string) { + resp, rerr := mustClientFromCmd(cmd).List(context.TODO()) + if rerr != nil { + ExitWithError(ExitBadConnection, rerr) + } + display.List(*resp) +} + // NewLeaseKeepAliveCommand returns the cobra command for "lease keep-alive". func NewLeaseKeepAliveCommand() *cobra.Command { lc := &cobra.Command{ diff --git a/etcdctl/ctlv3/command/printer.go b/etcdctl/ctlv3/command/printer.go index 613c555ebe60..366a8298c36a 100644 --- a/etcdctl/ctlv3/command/printer.go +++ b/etcdctl/ctlv3/command/printer.go @@ -36,6 +36,7 @@ type printer interface { Revoke(id v3.LeaseID, r v3.LeaseRevokeResponse) KeepAlive(r v3.LeaseKeepAliveResponse) TimeToLive(r v3.LeaseTimeToLiveResponse, keys bool) + List(r v3.LeaseListResponse) MemberAdd(v3.MemberAddResponse) MemberRemove(id uint64, r v3.MemberRemoveResponse) @@ -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) List(r v3.LeaseListResponse) { p.p(&r) } func (p *printerRPC) MemberAdd(r v3.MemberAddResponse) { p.p((*pb.MemberAddResponse)(&r)) } func (p *printerRPC) MemberRemove(id uint64, r v3.MemberRemoveResponse) { diff --git a/etcdctl/ctlv3/command/printer_fields.go b/etcdctl/ctlv3/command/printer_fields.go index f7d1cae59155..ccea5bed1b65 100644 --- a/etcdctl/ctlv3/command/printer_fields.go +++ b/etcdctl/ctlv3/command/printer_fields.go @@ -118,6 +118,14 @@ func (p *fieldsPrinter) TimeToLive(r v3.LeaseTimeToLiveResponse, keys bool) { } } +func (p *fieldsPrinter) List(r v3.LeaseListResponse) { + p.hdr(r.ResponseHeader) + for _, item := range r.LeaseItems { + fmt.Println(`"ID" :`, item.ID) + fmt.Println(`"TTL" :`, item.TTL) + } +} + func (p *fieldsPrinter) MemberList(r v3.MemberListResponse) { p.hdr(r.Header) for _, m := range r.Members { diff --git a/etcdctl/ctlv3/command/printer_simple.go b/etcdctl/ctlv3/command/printer_simple.go index 5e0ae9d3fd20..ec5adc81cfac 100644 --- a/etcdctl/ctlv3/command/printer_simple.go +++ b/etcdctl/ctlv3/command/printer_simple.go @@ -104,6 +104,13 @@ func (s *simplePrinter) TimeToLive(resp v3.LeaseTimeToLiveResponse, keys bool) { fmt.Println(txt) } +func (s *simplePrinter) List(resp v3.LeaseListResponse) { + fmt.Printf("found %d leases\n", len(resp.LeaseItems)) + for _, item := range resp.LeaseItems { + fmt.Printf("%016x (TTL: %ds)\n", item.ID, item.TTL) + } +} + func (s *simplePrinter) Alarm(resp v3.AlarmResponse) { for _, e := range resp.Alarms { fmt.Printf("%+v\n", e)