**Phase 1: State Management & Leader Election** * **Goal**: A functional embedded etcd and leader election mechanism. * **Tasks**: 1. Implement the `StateStore` interface (RFC 5.1) with an etcd backend (`internal/store/etcd.go`). 2. Integrate embedded etcd server into `kat-agent` (RFC 2.2, 5.2), configurable via `cluster.kat` parameters. 3. Implement leader election using `go.etcd.io/etcd/client/v3/concurrency` (RFC 5.3). 4. Basic `kat-agent init` functionality: * Parse `cluster.kat`. * Start single-node embedded etcd. * Campaign for and become leader. * Store initial cluster configuration (UID, CIDRs from `cluster.kat`) in etcd. * **Milestone**: * A single `kat-agent init --config cluster.kat` process starts, initializes etcd, and logs that it has become the leader. * The cluster configuration from `cluster.kat` can be verified in etcd using an etcd client. * `StateStore` interface methods (`Put`, `Get`, `Delete`, `List`) are testable against the embedded etcd. Reviewed-on: #1
90 lines
3.2 KiB
Go
90 lines
3.2 KiB
Go
package store
|
|
|
|
import (
|
|
"context"
|
|
)
|
|
|
|
// KV represents a key-value pair from the store.
|
|
type KV struct {
|
|
Key string
|
|
Value []byte
|
|
Version int64 // etcd ModRevision or similar versioning
|
|
}
|
|
|
|
// EventType defines the type of change observed by a Watch.
|
|
type EventType int
|
|
|
|
const (
|
|
// EventTypePut indicates a key was created or updated.
|
|
EventTypePut EventType = iota
|
|
// EventTypeDelete indicates a key was deleted.
|
|
EventTypeDelete
|
|
)
|
|
|
|
// WatchEvent represents a single event from a Watch operation.
|
|
type WatchEvent struct {
|
|
Type EventType
|
|
KV KV
|
|
PrevKV *KV // Previous KV, if available and applicable (e.g., for updates)
|
|
}
|
|
|
|
// Compare is used in transactions to check a key's version.
|
|
type Compare struct {
|
|
Key string
|
|
ExpectedVersion int64 // 0 means key should not exist. >0 means key must have this version.
|
|
}
|
|
|
|
// OpType defines the type of operation in a transaction.
|
|
type OpType int
|
|
|
|
const (
|
|
// OpPut represents a put operation.
|
|
OpPut OpType = iota
|
|
// OpDelete represents a delete operation.
|
|
OpDelete
|
|
// OpGet is not typically used in Txn success/fail ops but included for completeness if needed.
|
|
OpGet
|
|
)
|
|
|
|
// Op represents an operation to be performed within a transaction.
|
|
type Op struct {
|
|
Type OpType
|
|
Key string
|
|
Value []byte // Used for OpPut
|
|
}
|
|
|
|
// StateStore defines the interface for interacting with the underlying key-value store.
|
|
// It's designed based on RFC 5.1.
|
|
type StateStore interface {
|
|
// Put stores a key-value pair.
|
|
Put(ctx context.Context, key string, value []byte) error
|
|
// Get retrieves a key-value pair. Returns an error if key not found.
|
|
Get(ctx context.Context, key string) (*KV, error)
|
|
// Delete removes a key.
|
|
Delete(ctx context.Context, key string) error
|
|
// List retrieves all key-value pairs matching a prefix.
|
|
List(ctx context.Context, prefix string) ([]KV, error)
|
|
// Watch observes changes to a key or prefix, starting from a given revision.
|
|
// startRevision = 0 means watch from current.
|
|
Watch(ctx context.Context, keyOrPrefix string, startRevision int64) (<-chan WatchEvent, error)
|
|
// Close releases any resources held by the store client.
|
|
Close() error
|
|
|
|
// Campaign attempts to acquire leadership for the given leaderID.
|
|
// It returns a leadershipCtx that is cancelled when leadership is lost or Resign is called.
|
|
// leaseTTLSeconds specifies the TTL for the leader's lease.
|
|
Campaign(ctx context.Context, leaderID string, leaseTTLSeconds int64) (leadershipCtx context.Context, err error)
|
|
// Resign relinquishes leadership if currently held.
|
|
// The context passed should ideally be the one associated with the current leadership term or a parent.
|
|
Resign(ctx context.Context) error
|
|
// GetLeader retrieves the ID of the current leader.
|
|
GetLeader(ctx context.Context) (leaderID string, err error)
|
|
|
|
// DoTransaction executes a list of operations atomically if all checks pass.
|
|
// checks are conditions that must be true.
|
|
// onSuccess operations are performed if checks pass.
|
|
// onFailure operations are performed if checks fail (not typically supported by etcd Txn else).
|
|
// Returns true if the transaction was committed (onSuccess ops were applied).
|
|
DoTransaction(ctx context.Context, checks []Compare, onSuccess []Op, onFailure []Op) (committed bool, err error)
|
|
}
|