1// Copyright 2016 The etcd Authors 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// http://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14 15package command 16 17import ( 18 "context" 19 "fmt" 20 "strconv" 21 22 v3 "github.com/coreos/etcd/clientv3" 23 24 "github.com/spf13/cobra" 25) 26 27// NewLeaseCommand returns the cobra command for "lease". 28func NewLeaseCommand() *cobra.Command { 29 lc := &cobra.Command{ 30 Use: "lease <subcommand>", 31 Short: "Lease related commands", 32 } 33 34 lc.AddCommand(NewLeaseGrantCommand()) 35 lc.AddCommand(NewLeaseRevokeCommand()) 36 lc.AddCommand(NewLeaseTimeToLiveCommand()) 37 lc.AddCommand(NewLeaseListCommand()) 38 lc.AddCommand(NewLeaseKeepAliveCommand()) 39 40 return lc 41} 42 43// NewLeaseGrantCommand returns the cobra command for "lease grant". 44func NewLeaseGrantCommand() *cobra.Command { 45 lc := &cobra.Command{ 46 Use: "grant <ttl>", 47 Short: "Creates leases", 48 49 Run: leaseGrantCommandFunc, 50 } 51 52 return lc 53} 54 55// leaseGrantCommandFunc executes the "lease grant" command. 56func leaseGrantCommandFunc(cmd *cobra.Command, args []string) { 57 if len(args) != 1 { 58 ExitWithError(ExitBadArgs, fmt.Errorf("lease grant command needs TTL argument.")) 59 } 60 61 ttl, err := strconv.ParseInt(args[0], 10, 64) 62 if err != nil { 63 ExitWithError(ExitBadArgs, fmt.Errorf("bad TTL (%v)", err)) 64 } 65 66 ctx, cancel := commandCtx(cmd) 67 resp, err := mustClientFromCmd(cmd).Grant(ctx, ttl) 68 cancel() 69 if err != nil { 70 ExitWithError(ExitError, fmt.Errorf("failed to grant lease (%v)\n", err)) 71 } 72 display.Grant(*resp) 73} 74 75// NewLeaseRevokeCommand returns the cobra command for "lease revoke". 76func NewLeaseRevokeCommand() *cobra.Command { 77 lc := &cobra.Command{ 78 Use: "revoke <leaseID>", 79 Short: "Revokes leases", 80 81 Run: leaseRevokeCommandFunc, 82 } 83 84 return lc 85} 86 87// leaseRevokeCommandFunc executes the "lease grant" command. 88func leaseRevokeCommandFunc(cmd *cobra.Command, args []string) { 89 if len(args) != 1 { 90 ExitWithError(ExitBadArgs, fmt.Errorf("lease revoke command needs 1 argument")) 91 } 92 93 id := leaseFromArgs(args[0]) 94 ctx, cancel := commandCtx(cmd) 95 resp, err := mustClientFromCmd(cmd).Revoke(ctx, id) 96 cancel() 97 if err != nil { 98 ExitWithError(ExitError, fmt.Errorf("failed to revoke lease (%v)\n", err)) 99 } 100 display.Revoke(id, *resp) 101} 102 103var timeToLiveKeys bool 104 105// NewLeaseTimeToLiveCommand returns the cobra command for "lease timetolive". 106func NewLeaseTimeToLiveCommand() *cobra.Command { 107 lc := &cobra.Command{ 108 Use: "timetolive <leaseID> [options]", 109 Short: "Get lease information", 110 111 Run: leaseTimeToLiveCommandFunc, 112 } 113 lc.Flags().BoolVar(&timeToLiveKeys, "keys", false, "Get keys attached to this lease") 114 115 return lc 116} 117 118// leaseTimeToLiveCommandFunc executes the "lease timetolive" command. 119func leaseTimeToLiveCommandFunc(cmd *cobra.Command, args []string) { 120 if len(args) != 1 { 121 ExitWithError(ExitBadArgs, fmt.Errorf("lease timetolive command needs lease ID as argument")) 122 } 123 var opts []v3.LeaseOption 124 if timeToLiveKeys { 125 opts = append(opts, v3.WithAttachedKeys()) 126 } 127 resp, rerr := mustClientFromCmd(cmd).TimeToLive(context.TODO(), leaseFromArgs(args[0]), opts...) 128 if rerr != nil { 129 ExitWithError(ExitBadConnection, rerr) 130 } 131 display.TimeToLive(*resp, timeToLiveKeys) 132} 133 134// NewLeaseListCommand returns the cobra command for "lease list". 135func NewLeaseListCommand() *cobra.Command { 136 lc := &cobra.Command{ 137 Use: "list", 138 Short: "List all active leases", 139 Run: leaseListCommandFunc, 140 } 141 return lc 142} 143 144// leaseListCommandFunc executes the "lease list" command. 145func leaseListCommandFunc(cmd *cobra.Command, args []string) { 146 resp, rerr := mustClientFromCmd(cmd).Leases(context.TODO()) 147 if rerr != nil { 148 ExitWithError(ExitBadConnection, rerr) 149 } 150 display.Leases(*resp) 151} 152 153var ( 154 leaseKeepAliveOnce bool 155) 156 157// NewLeaseKeepAliveCommand returns the cobra command for "lease keep-alive". 158func NewLeaseKeepAliveCommand() *cobra.Command { 159 lc := &cobra.Command{ 160 Use: "keep-alive [options] <leaseID>", 161 Short: "Keeps leases alive (renew)", 162 163 Run: leaseKeepAliveCommandFunc, 164 } 165 166 lc.Flags().BoolVar(&leaseKeepAliveOnce, "once", false, "Resets the keep-alive time to its original value and exits immediately") 167 168 return lc 169} 170 171// leaseKeepAliveCommandFunc executes the "lease keep-alive" command. 172func leaseKeepAliveCommandFunc(cmd *cobra.Command, args []string) { 173 if len(args) != 1 { 174 ExitWithError(ExitBadArgs, fmt.Errorf("lease keep-alive command needs lease ID as argument")) 175 } 176 177 id := leaseFromArgs(args[0]) 178 179 if leaseKeepAliveOnce { 180 respc, kerr := mustClientFromCmd(cmd).KeepAliveOnce(context.TODO(), id) 181 if kerr != nil { 182 ExitWithError(ExitBadConnection, kerr) 183 } 184 display.KeepAlive(*respc) 185 return 186 } 187 188 respc, kerr := mustClientFromCmd(cmd).KeepAlive(context.TODO(), id) 189 if kerr != nil { 190 ExitWithError(ExitBadConnection, kerr) 191 } 192 for resp := range respc { 193 display.KeepAlive(*resp) 194 } 195 196 if _, ok := (display).(*simplePrinter); ok { 197 fmt.Printf("lease %016x expired or revoked.\n", id) 198 } 199} 200 201func leaseFromArgs(arg string) v3.LeaseID { 202 id, err := strconv.ParseInt(arg, 16, 64) 203 if err != nil { 204 ExitWithError(ExitBadArgs, fmt.Errorf("bad lease ID arg (%v), expecting ID in Hex", err)) 205 } 206 return v3.LeaseID(id) 207} 208