Files
vault/command/version_history.go
Chris Capurso c76896ff0c Add sys/version-history endpoint and associated command (#13766)
* store version history as utc; add self-heal logic

* add sys/version-history endpoint

* change version history from GET to LIST, require auth

* add "vault version-history" CLI command

* add vault-version CLI error message for version string parsing

* adding version-history API and CLI docs

* add changelog entry

* some version-history command fixes

* remove extraneous cmd args

* fix version-history command help text

* specify in docs that endpoint was added in 1.10.0

Co-authored-by: Nick Cabatoff <ncabatoff@hashicorp.com>

* enforce UTC within storeVersionTimestamp directly

* fix improper use of %w in logger.Warn

* remove extra err check and erroneous return from loadVersionTimestamps

* add >= 1.10.0 warning to version-history cmd

* move sys/version-history tests

Co-authored-by: Nick Cabatoff <ncabatoff@hashicorp.com>
2022-02-14 15:26:57 -05:00

131 lines
2.8 KiB
Go

package command
import (
"fmt"
"github.com/mitchellh/cli"
"github.com/posener/complete"
"github.com/ryanuber/columnize"
"strings"
)
var (
_ cli.Command = (*VersionHistoryCommand)(nil)
_ cli.CommandAutocomplete = (*VersionHistoryCommand)(nil)
)
// VersionHistoryCommand is a Command implementation prints the version.
type VersionHistoryCommand struct {
*BaseCommand
}
func (c *VersionHistoryCommand) Synopsis() string {
return "Prints the version history of the target Vault server"
}
func (c *VersionHistoryCommand) Help() string {
helpText := `
Usage: vault version-history
Prints the version history of the target Vault server.
Print the version history:
$ vault version-history
` + c.Flags().Help()
return strings.TrimSpace(helpText)
}
func (c *VersionHistoryCommand) Flags() *FlagSets {
return c.flagSet(FlagSetOutputFormat)
}
func (c *VersionHistoryCommand) AutocompleteArgs() complete.Predictor {
return complete.PredictNothing
}
func (c *VersionHistoryCommand) AutocompleteFlags() complete.Flags {
return c.Flags().Completions()
}
const versionTrackingWarning = `Note:
Use of this command requires a server running Vault 1.10.0 or greater.
Version tracking was added in 1.9.0. Earlier versions have not been tracked.
`
func (c *VersionHistoryCommand) Run(args []string) int {
f := c.Flags()
if err := f.Parse(args); err != nil {
c.UI.Error(err.Error())
return 1
}
client, err := c.Client()
if err != nil {
c.UI.Error(err.Error())
return 2
}
resp, err := client.Logical().List("sys/version-history")
if err != nil {
c.UI.Error(fmt.Sprintf("Error reading version history: %s", err))
return 2
}
if resp == nil || resp.Data == nil {
c.UI.Error("Invalid response returned from Vault")
return 2
}
if c.flagFormat == "json" {
c.UI.Warn("")
c.UI.Warn(versionTrackingWarning)
c.UI.Warn("")
return OutputData(c.UI, resp)
}
var keyInfo map[string]interface{}
keys, ok := extractListData(resp)
if !ok {
c.UI.Error("Expected keys in response to be an array")
return 2
}
keyInfo, ok = resp.Data["key_info"].(map[string]interface{})
if !ok {
c.UI.Error("Expected key_info in response to be a map")
return 2
}
table := []string{"Version | Installation Time"}
columnConfig := columnize.DefaultConfig()
for _, versionRaw := range keys {
version, ok := versionRaw.(string)
if !ok {
c.UI.Error("Expected version to be string")
return 2
}
versionInfoRaw := keyInfo[version]
versionInfo, ok := versionInfoRaw.(map[string]interface{})
if !ok {
c.UI.Error(fmt.Sprintf("Expected version info for %q to be map", version))
return 2
}
table = append(table, fmt.Sprintf("%s | %s", version, versionInfo["timestamp_installed"]))
}
c.UI.Warn("")
c.UI.Warn(versionTrackingWarning)
c.UI.Warn("")
c.UI.Output(tableOutput(table, columnConfig))
return 0
}