github.com/hashicorp/vault/sdk@v0.13.0/framework/wal.go (about) 1 // Copyright (c) HashiCorp, Inc. 2 // SPDX-License-Identifier: MPL-2.0 3 4 package framework 5 6 import ( 7 "context" 8 "encoding/json" 9 "strings" 10 "time" 11 12 uuid "github.com/hashicorp/go-uuid" 13 "github.com/hashicorp/vault/sdk/helper/jsonutil" 14 "github.com/hashicorp/vault/sdk/logical" 15 ) 16 17 // WALPrefix is the prefix within Storage where WAL entries will be written. 18 const WALPrefix = "wal/" 19 20 type WALEntry struct { 21 ID string `json:"-"` 22 Kind string `json:"type"` 23 Data interface{} `json:"data"` 24 CreatedAt int64 `json:"created_at"` 25 } 26 27 // PutWAL writes some data to the WAL. 28 // 29 // The kind parameter is used by the framework to allow users to store 30 // multiple kinds of WAL data and to easily disambiguate what data they're 31 // expecting. 32 // 33 // Data within the WAL that is uncommitted (CommitWAL hasn't be called) 34 // will be given to the rollback callback when an rollback operation is 35 // received, allowing the backend to clean up some partial states. 36 // 37 // The data must be JSON encodable. 38 // 39 // This returns a unique ID that can be used to reference this WAL data. 40 // WAL data cannot be modified. You can only add to the WAL and commit existing 41 // WAL entries. 42 func PutWAL(ctx context.Context, s logical.Storage, kind string, data interface{}) (string, error) { 43 value, err := json.Marshal(&WALEntry{ 44 Kind: kind, 45 Data: data, 46 CreatedAt: time.Now().UTC().Unix(), 47 }) 48 if err != nil { 49 return "", err 50 } 51 52 id, err := uuid.GenerateUUID() 53 if err != nil { 54 return "", err 55 } 56 57 return id, s.Put(ctx, &logical.StorageEntry{ 58 Key: WALPrefix + id, 59 Value: value, 60 }) 61 } 62 63 // GetWAL reads a specific entry from the WAL. If the entry doesn't exist, 64 // then nil value is returned. 65 // 66 // The kind, value, and error are returned. 67 func GetWAL(ctx context.Context, s logical.Storage, id string) (*WALEntry, error) { 68 entry, err := s.Get(ctx, WALPrefix+id) 69 if err != nil { 70 return nil, err 71 } 72 if entry == nil { 73 return nil, nil 74 } 75 76 var raw WALEntry 77 if err := jsonutil.DecodeJSON(entry.Value, &raw); err != nil { 78 return nil, err 79 } 80 raw.ID = id 81 82 return &raw, nil 83 } 84 85 // DeleteWAL commits the WAL entry with the given ID. Once committed, 86 // it is assumed that the operation was a success and doesn't need to 87 // be rolled back. 88 func DeleteWAL(ctx context.Context, s logical.Storage, id string) error { 89 return s.Delete(ctx, WALPrefix+id) 90 } 91 92 // ListWAL lists all the entries in the WAL. 93 func ListWAL(ctx context.Context, s logical.Storage) ([]string, error) { 94 keys, err := s.List(ctx, WALPrefix) 95 if err != nil { 96 return nil, err 97 } 98 99 for i, k := range keys { 100 keys[i] = strings.TrimPrefix(k, WALPrefix) 101 } 102 103 return keys, nil 104 }