Skip to content

Commit

Permalink
Add command to look up a lease by ID (hashicorp#11129)
Browse files Browse the repository at this point in the history
* snapshot

* basic test

* update command and add documentation

* update help text

* typo

* add changelog for lease lookup command

* run go mod vendor

* remove tabs from help output
  • Loading branch information
catsby authored and jartek committed Sep 11, 2021
1 parent 6192bad commit cb4eb0f
Show file tree
Hide file tree
Showing 9 changed files with 304 additions and 0 deletions.
21 changes: 21 additions & 0 deletions api/sys_leases.go
Expand Up @@ -27,6 +27,27 @@ func (c *Sys) Renew(id string, increment int) (*Secret, error) {
return ParseSecret(resp.Body)
}

func (c *Sys) Lookup(id string) (*Secret, error) {
r := c.c.NewRequest("PUT", "/v1/sys/leases/lookup")

body := map[string]interface{}{
"lease_id": id,
}
if err := r.SetJSONBody(body); err != nil {
return nil, err
}

ctx, cancelFunc := context.WithCancel(context.Background())
defer cancelFunc()
resp, err := c.c.RawRequestWithContext(ctx, r)
if err != nil {
return nil, err
}
defer resp.Body.Close()

return ParseSecret(resp.Body)
}

func (c *Sys) Revoke(id string) error {
r := c.c.NewRequest("PUT", "/v1/sys/leases/revoke")
body := map[string]interface{}{
Expand Down
3 changes: 3 additions & 0 deletions changelog/11129.txt
@@ -0,0 +1,3 @@
```release-note:feature
cli/api: Add lease lookup command
```
5 changes: 5 additions & 0 deletions command/commands.go
Expand Up @@ -286,6 +286,11 @@ func initCommands(ui, serverCmdUi cli.Ui, runOpts *RunOptions) {
BaseCommand: getBaseCommand(),
}, nil
},
"lease lookup": func() (cli.Command, error) {
return &LeaseLookupCommand{
BaseCommand: getBaseCommand(),
}, nil
},
"lease revoke": func() (cli.Command, error) {
return &LeaseRevokeCommand{
BaseCommand: getBaseCommand(),
Expand Down
89 changes: 89 additions & 0 deletions command/lease_lookup.go
@@ -0,0 +1,89 @@
package command

import (
"fmt"
"strings"

"github.com/mitchellh/cli"
"github.com/posener/complete"
)

var _ cli.Command = (*LeaseLookupCommand)(nil)
var _ cli.CommandAutocomplete = (*LeaseLookupCommand)(nil)

type LeaseLookupCommand struct {
*BaseCommand
}

func (c *LeaseLookupCommand) Synopsis() string {
return "Lookup the lease of a secret"
}

func (c *LeaseLookupCommand) Help() string {
helpText := `
Usage: vault lease lookup ID
Lookup the lease information of a secret.
Every secret in Vault has a lease associated with it. Users can look up
information on the lease by referencing the lease ID.
Lookup lease of a secret:
$ vault lease lookup database/creds/readonly/2f6a614c...
` + c.Flags().Help()

return strings.TrimSpace(helpText)
}

func (c *LeaseLookupCommand) Flags() *FlagSets {
set := c.flagSet(FlagSetHTTP | FlagSetOutputFormat)

return set
}

func (c *LeaseLookupCommand) AutocompleteArgs() complete.Predictor {
return complete.PredictAnything
}

func (c *LeaseLookupCommand) AutocompleteFlags() complete.Flags {
return c.Flags().Completions()
}

func (c *LeaseLookupCommand) Run(args []string) int {
f := c.Flags()

if err := f.Parse(args); err != nil {
c.UI.Error(err.Error())
return 1
}

leaseID := ""

args = f.Args()
switch len(args) {
case 0:
c.UI.Error("Missing ID!")
return 1
case 1:
leaseID = strings.TrimSpace(args[0])
default:
c.UI.Error(fmt.Sprintf("Too many arguments (expected 1, got %d)", len(args)))
return 1
}

client, err := c.Client()
if err != nil {
c.UI.Error(err.Error())
return 2
}

secret, err := client.Sys().Lookup(leaseID)
if err != nil {
c.UI.Error(fmt.Sprintf("error looking up lease id %s: %s", leaseID, err))
return 2
}

return OutputSecret(c.UI, secret)
}
100 changes: 100 additions & 0 deletions command/lease_lookup_test.go
@@ -0,0 +1,100 @@
package command

import (
"strings"
"testing"

"github.com/hashicorp/vault/api"
"github.com/mitchellh/cli"
)

func testLeaseLookupCommand(tb testing.TB) (*cli.MockUi, *LeaseLookupCommand) {
tb.Helper()

ui := cli.NewMockUi()
return ui, &LeaseLookupCommand{
BaseCommand: &BaseCommand{
UI: ui,
},
}
}

// testLeaseLookupCommandMountAndLease mounts a leased secret backend and returns
// the leaseID of an item.
func testLeaseLookupCommandMountAndLease(tb testing.TB, client *api.Client) string {
if err := client.Sys().Mount("testing", &api.MountInput{
Type: "generic-leased",
}); err != nil {
tb.Fatal(err)
}

if _, err := client.Logical().Write("testing/foo", map[string]interface{}{
"key": "value",
"lease": "5m",
}); err != nil {
tb.Fatal(err)
}

// Read the secret back to get the leaseID
secret, err := client.Logical().Read("testing/foo")
if err != nil {
tb.Fatal(err)
}
if secret == nil || secret.LeaseID == "" {
tb.Fatalf("missing secret or lease: %#v", secret)
}

return secret.LeaseID
}

// TestLeaseLookupCommand_Run tests basic lookup
func TestLeaseLookupCommand_Run(t *testing.T) {
t.Parallel()

t.Run("empty", func(t *testing.T) {
t.Parallel()

client, closer := testVaultServer(t)
defer closer()

_ = testLeaseLookupCommandMountAndLease(t, client)

ui, cmd := testLeaseLookupCommand(t)
cmd.client = client

code := cmd.Run(nil)
if exp := 1; code != exp {
t.Errorf("expected %d to be %d", code, exp)
}

combined := ui.OutputWriter.String() + ui.ErrorWriter.String()
expectedMsg := "Missing ID!"
if !strings.Contains(combined, expectedMsg) {
t.Errorf("expected %q to contain %q", combined, expectedMsg)
}
})

t.Run("integration", func(t *testing.T) {
t.Parallel()

client, closer := testVaultServer(t)
defer closer()

leaseID := testLeaseLookupCommandMountAndLease(t, client)

_, cmd := testLeaseLookupCommand(t)
cmd.client = client

code := cmd.Run([]string{leaseID})
if exp := 0; code != exp {
t.Errorf("expected %d to be %d", code, exp)
}
})

t.Run("no_tabs", func(t *testing.T) {
t.Parallel()

_, cmd := testLeaseLookupCommand(t)
assertNoTabs(t, cmd)
})
}
21 changes: 21 additions & 0 deletions vendor/github.com/hashicorp/vault/api/sys_leases.go

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

15 changes: 15 additions & 0 deletions website/content/docs/commands/lease.mdx
Expand Up @@ -14,6 +14,20 @@ secrets. For leases attached to tokens, use the [`vault token`](/docs/commands/t

## Examples

Lookup a lease:

```shell-session
$ vault lease lookup database/creds/readonly/27e1b9a1-27b8-83d9-9fe0-d99d786bdc83
Key Value
--- -----
expire_time 2021-03-17T11:55:50.755313-05:00
id database/creds/readonly/27e1b9a1-27b8-83d9-9fe0-d99d786bdc83
issue_time 2021-03-17T11:45:50.755312-05:00
last_renewal <nil>
renewable true
ttl 9m52s
```

Renew a lease:

```shell-session
Expand All @@ -40,6 +54,7 @@ Usage: vault lease <subcommand> [options] [args]
# ...
Subcommands:
lookup Lookup lease information by lease id
renew Renews the lease of a secret
revoke Revokes leases and secrets
```
Expand Down
15 changes: 15 additions & 0 deletions website/content/docs/commands/lease/index.mdx
Expand Up @@ -14,6 +14,20 @@ secrets. For leases attached to tokens, use the [`vault token`](/docs/commands/t

## Examples

Lookup a lease:

```shell-session
$ vault lease lookup database/creds/readonly/27e1b9a1-27b8-83d9-9fe0-d99d786bdc83
Key Value
--- -----
expire_time 2021-03-17T11:55:50.755313-05:00
id database/creds/readonly/27e1b9a1-27b8-83d9-9fe0-d99d786bdc83
issue_time 2021-03-17T11:45:50.755312-05:00
last_renewal <nil>
renewable true
ttl 9m52s
```

Renew a lease:

```shell-session
Expand All @@ -40,6 +54,7 @@ Usage: vault lease <subcommand> [options] [args]
# ...
Subcommands:
lookup Lookup lease information by lease id
renew Renews the lease of a secret
revoke Revokes leases and secrets
```
Expand Down
35 changes: 35 additions & 0 deletions website/content/docs/commands/lease/lookup.mdx
@@ -0,0 +1,35 @@
---
layout: docs
page_title: lease lookup - Command
sidebar_title: <code>lookup</code>
description: |-
The "lease lookup" command retrieves information about a lease.
---

# lease lookup

The `lease lookup` command retrieves information on the lease of a secret.

Every secret in Vault has a lease associated with it. Users can look up
information on the lease by referencing the lease ID.

## Examples

Lookup a lease:

```shell-session
$ vault lease lookup database/creds/readonly/27e1b9a1-27b8-83d9-9fe0-d99d786bdc83
Key Value
--- -----
expire_time 2021-03-17T11:55:50.755313-05:00
id database/creds/readonly/27e1b9a1-27b8-83d9-9fe0-d99d786bdc83
issue_time 2021-03-17T11:45:50.755312-05:00
last_renewal <nil>
renewable true
ttl 9m52s
```

## Usage

There are no flags beyond the [standard set of flags](/docs/commands)
included on all commands.

0 comments on commit cb4eb0f

Please sign in to comment.