2021-10-14 16:10:59 +00:00
|
|
|
package vault
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"encoding/json"
|
|
|
|
"fmt"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
"github.com/hashicorp/vault/sdk/logical"
|
|
|
|
)
|
|
|
|
|
|
|
|
const vaultVersionPath string = "core/versions/"
|
|
|
|
|
2021-11-08 15:04:17 +00:00
|
|
|
// storeVersionTimestamp will store the version and timestamp pair to storage only if no entry
|
2021-10-14 16:10:59 +00:00
|
|
|
// for that version already exists in storage.
|
2021-11-08 15:04:17 +00:00
|
|
|
func (c *Core) storeVersionTimestamp(ctx context.Context, version string, currentTime time.Time) (bool, error) {
|
2021-10-14 16:10:59 +00:00
|
|
|
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
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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) {
|
2021-11-16 20:05:59 +00:00
|
|
|
if c.versionTimestamps == nil || len(c.versionTimestamps) == 0 {
|
2021-10-14 16:10:59 +00:00
|
|
|
return "", time.Time{}, fmt.Errorf("version timestamps are not initialized")
|
|
|
|
}
|
|
|
|
|
|
|
|
// initialize oldestUpgradeTime to current time
|
|
|
|
oldestUpgradeTime := time.Now()
|
|
|
|
var oldestVersion string
|
2021-11-16 20:05:59 +00:00
|
|
|
for version, upgradeTime := range c.versionTimestamps {
|
2021-10-14 16:10:59 +00:00
|
|
|
if upgradeTime.Before(oldestUpgradeTime) {
|
|
|
|
oldestVersion = version
|
|
|
|
oldestUpgradeTime = upgradeTime
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return oldestVersion, oldestUpgradeTime, nil
|
|
|
|
}
|
|
|
|
|
2021-11-08 15:04:17 +00:00
|
|
|
// loadVersionTimestamps loads all the vault versions and associated
|
2021-10-14 16:10:59 +00:00
|
|
|
// upgrade timestamps from storage.
|
2021-11-08 15:04:17 +00:00
|
|
|
func (c *Core) loadVersionTimestamps(ctx context.Context) (retErr error) {
|
2021-10-14 16:10:59 +00:00
|
|
|
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)
|
|
|
|
}
|
2021-11-16 20:05:59 +00:00
|
|
|
c.versionTimestamps[vaultVersion.Version] = vaultVersion.TimestampInstalled
|
2021-10-14 16:10:59 +00:00
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|