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  }