Add initial implementation of Agate snapshot library
Introduces core functionality for the Agate library, including snapshot creation, restoration, listing, and deletion. Adds examples for basic usage, gRPC proto definitions, and build/configuration files such as `go.mod` and `Makefile`. The implementation establishes the framework for store integration and placeholder server functionality.
This commit is contained in:
177
api.go
Normal file
177
api.go
Normal file
@ -0,0 +1,177 @@
|
||||
package agate
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"unprism.ru/KRBL/agate/store"
|
||||
)
|
||||
|
||||
// AgateOptions defines configuration options for the Agate library.
|
||||
type AgateOptions struct {
|
||||
// WorkDir is the directory where snapshots will be stored and managed.
|
||||
WorkDir string
|
||||
|
||||
// OpenFunc is called after a snapshot is restored to initialize resources.
|
||||
// The parameter is the directory where the snapshot was extracted.
|
||||
OpenFunc func(dir string) error
|
||||
|
||||
// CloseFunc is called before a snapshot is created or restored to clean up resources.
|
||||
CloseFunc func() error
|
||||
|
||||
// MetadataStore is the implementation of the metadata store to use.
|
||||
// Use the stores package to initialize the default implementation:
|
||||
// metadataStore, err := stores.NewDefaultMetadataStore(metadataDir)
|
||||
MetadataStore store.MetadataStore
|
||||
|
||||
// BlobStore is the implementation of the blob store to use.
|
||||
// Use the stores package to initialize the default implementation:
|
||||
// blobStore, err := stores.NewDefaultBlobStore(blobsDir)
|
||||
BlobStore store.BlobStore
|
||||
}
|
||||
|
||||
// Agate is the main entry point for the snapshot library.
|
||||
type Agate struct {
|
||||
manager SnapshotManager
|
||||
options AgateOptions
|
||||
metadataDir string
|
||||
blobsDir string
|
||||
}
|
||||
|
||||
// New initializes a new instance of the Agate library with the given options.
|
||||
func New(options AgateOptions) (*Agate, error) {
|
||||
if options.WorkDir == "" {
|
||||
return nil, errors.New("work directory cannot be empty")
|
||||
}
|
||||
|
||||
// Create the work directory if it doesn't exist
|
||||
if err := os.MkdirAll(options.WorkDir, 0755); err != nil {
|
||||
return nil, fmt.Errorf("failed to create work directory: %w", err)
|
||||
}
|
||||
|
||||
// Create subdirectories for metadata and blobs
|
||||
metadataDir := filepath.Join(options.WorkDir, "metadata")
|
||||
blobsDir := filepath.Join(options.WorkDir, "blobs")
|
||||
|
||||
if err := os.MkdirAll(metadataDir, 0755); err != nil {
|
||||
return nil, fmt.Errorf("failed to create metadata directory: %w", err)
|
||||
}
|
||||
|
||||
if err := os.MkdirAll(blobsDir, 0755); err != nil {
|
||||
return nil, fmt.Errorf("failed to create blobs directory: %w", err)
|
||||
}
|
||||
|
||||
var metadataStore store.MetadataStore
|
||||
var blobStore store.BlobStore
|
||||
var err error
|
||||
|
||||
// Use provided stores or initialize default ones
|
||||
if options.MetadataStore != nil {
|
||||
metadataStore = options.MetadataStore
|
||||
} else {
|
||||
// For default implementation, the user needs to initialize and provide the stores
|
||||
return nil, errors.New("metadata store must be provided")
|
||||
}
|
||||
|
||||
if options.BlobStore != nil {
|
||||
blobStore = options.BlobStore
|
||||
} else {
|
||||
// For default implementation, the user needs to initialize and provide the stores
|
||||
return nil, errors.New("blob store must be provided")
|
||||
}
|
||||
|
||||
// Create the snapshot manager
|
||||
manager, err := CreateSnapshotManager(metadataStore, blobStore)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create snapshot manager: %w", err)
|
||||
}
|
||||
|
||||
return &Agate{
|
||||
manager: manager,
|
||||
options: options,
|
||||
metadataDir: metadataDir,
|
||||
blobsDir: blobsDir,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// SaveSnapshot creates a new snapshot from the current state of the work directory.
|
||||
// If parentID is provided, it will be set as the parent of the new snapshot.
|
||||
// Returns the ID of the created snapshot.
|
||||
func (a *Agate) SaveSnapshot(ctx context.Context, name string, parentID string) (string, error) {
|
||||
// Call CloseFunc if provided
|
||||
if a.options.CloseFunc != nil {
|
||||
if err := a.options.CloseFunc(); err != nil {
|
||||
return "", fmt.Errorf("failed to close resources before snapshot: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Create the snapshot
|
||||
snapshot, err := a.manager.CreateSnapshot(ctx, a.options.WorkDir, name, parentID)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to create snapshot: %w", err)
|
||||
}
|
||||
|
||||
// Call OpenFunc if provided
|
||||
if a.options.OpenFunc != nil {
|
||||
if err := a.options.OpenFunc(a.options.WorkDir); err != nil {
|
||||
return "", fmt.Errorf("failed to open resources after snapshot: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
return snapshot.ID, nil
|
||||
}
|
||||
|
||||
// RestoreSnapshot extracts a snapshot to the work directory.
|
||||
func (a *Agate) RestoreSnapshot(ctx context.Context, snapshotID string) error {
|
||||
// Call CloseFunc if provided
|
||||
if a.options.CloseFunc != nil {
|
||||
if err := a.options.CloseFunc(); err != nil {
|
||||
return fmt.Errorf("failed to close resources before restore: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Extract the snapshot
|
||||
if err := a.manager.ExtractSnapshot(ctx, snapshotID, a.options.WorkDir); err != nil {
|
||||
return fmt.Errorf("failed to extract snapshot: %w", err)
|
||||
}
|
||||
|
||||
// Call OpenFunc if provided
|
||||
if a.options.OpenFunc != nil {
|
||||
if err := a.options.OpenFunc(a.options.WorkDir); err != nil {
|
||||
return fmt.Errorf("failed to open resources after restore: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ListSnapshots returns a list of all available snapshots.
|
||||
func (a *Agate) ListSnapshots(ctx context.Context) ([]store.SnapshotInfo, error) {
|
||||
return a.manager.ListSnapshots(ctx)
|
||||
}
|
||||
|
||||
// GetSnapshotDetails returns detailed information about a specific snapshot.
|
||||
func (a *Agate) GetSnapshotDetails(ctx context.Context, snapshotID string) (*store.Snapshot, error) {
|
||||
return a.manager.GetSnapshotDetails(ctx, snapshotID)
|
||||
}
|
||||
|
||||
// DeleteSnapshot removes a snapshot.
|
||||
func (a *Agate) DeleteSnapshot(ctx context.Context, snapshotID string) error {
|
||||
return a.manager.DeleteSnapshot(ctx, snapshotID)
|
||||
}
|
||||
|
||||
// Close releases all resources used by the Agate instance.
|
||||
func (a *Agate) Close() error {
|
||||
// Currently, we don't have a way to close the manager directly
|
||||
// This would be a good addition in the future
|
||||
return nil
|
||||
}
|
||||
|
||||
// StartServer starts a gRPC server to share snapshots.
|
||||
// This is a placeholder for future implementation.
|
||||
func (a *Agate) StartServer(ctx context.Context, address string) error {
|
||||
return errors.New("server functionality not implemented yet")
|
||||
}
|
Reference in New Issue
Block a user