open-vault/command/version_history.go

135 lines
2.9 KiB
Go

// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0
package command
import (
"fmt"
"strings"
"github.com/mitchellh/cli"
"github.com/posener/complete"
"github.com/ryanuber/columnize"
)
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 | Build Date"}
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 | %s", version, versionInfo["timestamp_installed"], versionInfo["build_date"]))
}
c.UI.Warn("")
c.UI.Warn(versionTrackingWarning)
c.UI.Warn("")
c.UI.Output(tableOutput(table, columnConfig))
return 0
}