github.com/cilium/statedb@v0.3.2/reconciler/example/ops.go (about)

     1  // SPDX-License-Identifier: Apache-2.0
     2  // Copyright Authors of Cilium
     3  
     4  package main
     5  
     6  import (
     7  	"context"
     8  	"errors"
     9  	"iter"
    10  	"log/slog"
    11  	"os"
    12  	"path"
    13  
    14  	"github.com/cilium/hive/cell"
    15  	"github.com/cilium/statedb"
    16  	"github.com/cilium/statedb/reconciler"
    17  )
    18  
    19  // MemoOps writes [Memo]s to disk.
    20  // Implements the Reconciler.Operations[*Memo] API.
    21  type MemoOps struct {
    22  	log       *slog.Logger
    23  	directory string
    24  }
    25  
    26  // NewMemoOps creates the memo operations.
    27  func NewMemoOps(lc cell.Lifecycle, log *slog.Logger, cfg Config) reconciler.Operations[*Memo] {
    28  	ops := &MemoOps{directory: cfg.Directory, log: log}
    29  
    30  	// Register the Start and Stop methods to be called when the application
    31  	// starts and stops respectively. The start hook will create the
    32  	// memo directory.
    33  	lc.Append(ops)
    34  	return ops
    35  }
    36  
    37  // Delete a memo.
    38  func (ops *MemoOps) Delete(ctx context.Context, txn statedb.ReadTxn, memo *Memo) error {
    39  	filename := path.Join(ops.directory, memo.Name)
    40  	err := os.Remove(filename)
    41  	ops.log.Info("Delete", "filename", filename, "error", err)
    42  	return err
    43  }
    44  
    45  // Prune unexpected memos.
    46  func (ops *MemoOps) Prune(ctx context.Context, txn statedb.ReadTxn, objects iter.Seq2[*Memo, statedb.Revision]) error {
    47  	expected := map[string]struct{}{}
    48  
    49  	for memo := range objects {
    50  		expected[memo.Name] = struct{}{}
    51  	}
    52  
    53  	// Find unexpected files
    54  	unexpected := map[string]struct{}{}
    55  	if entries, err := os.ReadDir(ops.directory); err != nil {
    56  		return err
    57  	} else {
    58  		for _, entry := range entries {
    59  			if _, ok := expected[entry.Name()]; !ok {
    60  				unexpected[entry.Name()] = struct{}{}
    61  			}
    62  		}
    63  	}
    64  
    65  	// ... and remove them.
    66  	var errs []error
    67  	for name := range unexpected {
    68  		filename := path.Join(ops.directory, name)
    69  		err := os.Remove(filename)
    70  		ops.log.Info("Prune", "filename", filename, "error", err)
    71  		if err != nil {
    72  			errs = append(errs, err)
    73  		}
    74  	}
    75  	return errors.Join(errs...)
    76  }
    77  
    78  // Update a memo.
    79  func (ops *MemoOps) Update(ctx context.Context, txn statedb.ReadTxn, memo *Memo) error {
    80  	filename := path.Join(ops.directory, memo.Name)
    81  	err := os.WriteFile(filename, []byte(memo.Content), 0644)
    82  	ops.log.Info("Update", "filename", filename, "error", err)
    83  	return err
    84  }
    85  
    86  var _ reconciler.Operations[*Memo] = &MemoOps{}
    87  
    88  func (ops *MemoOps) Start(cell.HookContext) error {
    89  	return os.MkdirAll(ops.directory, 0755)
    90  }
    91  
    92  func (*MemoOps) Stop(cell.HookContext) error {
    93  	return nil
    94  }
    95  
    96  var _ cell.HookInterface = &MemoOps{}