open-vault/vault/core_util_common.go

111 lines
3.5 KiB
Go

package vault
import (
"context"
"encoding/json"
"fmt"
"time"
"github.com/hashicorp/vault/sdk/logical"
)
const vaultVersionPath string = "core/versions/"
// StoreVersionTimestamp will store the version and timestamp pair to storage only if no entry
// for that version already exists in storage.
func (c *Core) StoreVersionTimestamp(ctx context.Context, version string, currentTime time.Time) (bool, error) {
timeStamp, err := c.barrier.Get(ctx, vaultVersionPath+version)
if err != nil {
return false, err
}
if timeStamp != nil {
return false, nil
}
vaultVersion := VaultVersion{TimestampInstalled: currentTime, Version: version}
marshalledVaultVersion, err := json.Marshal(vaultVersion)
if err != nil {
return false, err
}
err = c.barrier.Put(ctx, &logical.StorageEntry{
Key: vaultVersionPath + version,
Value: marshalledVaultVersion,
})
if err != nil {
return false, err
}
return true, nil
}
// FindMostRecentVersionTimestamp loads the current vault version and associated
// upgrade time from storage.
func (c *Core) FindMostRecentVersionTimestamp() (string, time.Time, error) {
if c.VersionTimestamps == nil || len(c.VersionTimestamps) == 0 {
return "", time.Time{}, fmt.Errorf("Version timestamps are not initialized")
}
var latestUpgradeTime time.Time
var mostRecentVersion string
for version, upgradeTime := range c.VersionTimestamps {
if upgradeTime.After(latestUpgradeTime) {
mostRecentVersion = version
latestUpgradeTime = upgradeTime
}
}
// This if-case should never be hit
if mostRecentVersion == "" {
return "", latestUpgradeTime, fmt.Errorf("Empty vault version was written to storage at time: %+v", latestUpgradeTime)
}
return mostRecentVersion, latestUpgradeTime, nil
}
// FindOldestVersionTimestamp searches for the vault version with the oldest
// upgrade timestamp from storage. The earliest version this can be (barring
// downgrades) is 1.9.0.
func (c *Core) FindOldestVersionTimestamp() (string, time.Time, error) {
if c.VersionTimestamps == nil || len(c.VersionTimestamps) == 0 {
return "", time.Time{}, fmt.Errorf("version timestamps are not initialized")
}
// initialize oldestUpgradeTime to current time
oldestUpgradeTime := time.Now()
var oldestVersion string
for version, upgradeTime := range c.VersionTimestamps {
if upgradeTime.Before(oldestUpgradeTime) {
oldestVersion = version
oldestUpgradeTime = upgradeTime
}
}
return oldestVersion, oldestUpgradeTime, nil
}
// HandleLoadVersionTimestamps loads all the vault versions and associated
// upgrade timestamps from storage.
func (c *Core) HandleLoadVersionTimestamps(ctx context.Context) (retErr error) {
vaultVersions, err := c.barrier.List(ctx, vaultVersionPath)
if err != nil {
return fmt.Errorf("unable to retrieve vault versions from storage: %+w", err)
}
for _, versionPath := range vaultVersions {
version, err := c.barrier.Get(ctx, vaultVersionPath+versionPath)
if err != nil {
return fmt.Errorf("unable to read vault version at path %s: err %+w", versionPath, err)
}
if version == nil {
return fmt.Errorf("nil version stored at path %s", versionPath)
}
var vaultVersion VaultVersion
err = json.Unmarshal(version.Value, &vaultVersion)
if err != nil {
return fmt.Errorf("unable to unmarshal vault version for path %s: err %w", versionPath, err)
}
if vaultVersion.Version == "" || vaultVersion.TimestampInstalled.IsZero() {
return fmt.Errorf("found empty serialized vault version at path %s", versionPath)
}
c.VersionTimestamps[vaultVersion.Version] = vaultVersion.TimestampInstalled
}
return nil
}