still working
This commit is contained in:
102
internal/service/storage/storage.go
Normal file
102
internal/service/storage/storage.go
Normal file
@@ -0,0 +1,102 @@
|
||||
package storage
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/example/storage-appliance/internal/audit"
|
||||
"github.com/example/storage-appliance/internal/domain"
|
||||
"github.com/example/storage-appliance/internal/infra/zfs"
|
||||
"github.com/example/storage-appliance/internal/service"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrForbidden = errors.New("forbidden")
|
||||
ErrDuplicatePool = errors.New("duplicate pool name")
|
||||
)
|
||||
|
||||
type StorageService struct {
|
||||
ZFS zfs.Adapter
|
||||
JobRunner service.JobRunner
|
||||
Audit audit.AuditLogger
|
||||
}
|
||||
|
||||
func NewStorageService(z *zfs.Adapter, jr service.JobRunner, al audit.AuditLogger) *StorageService {
|
||||
return &StorageService{ZFS: *z, JobRunner: jr, Audit: al}
|
||||
}
|
||||
|
||||
// ListPools returns pools via zfs adapter
|
||||
func (s *StorageService) ListPools(ctx context.Context) ([]domain.Pool, error) {
|
||||
return s.ZFS.ListPools(ctx)
|
||||
}
|
||||
|
||||
// CreatePool validates and enqueues a create pool job; user must be admin
|
||||
func (s *StorageService) CreatePool(ctx context.Context, user string, role string, name string, vdevs []string) (string, error) {
|
||||
if role != "admin" {
|
||||
return "", ErrForbidden
|
||||
}
|
||||
// Simple validation: new name not in existing pools
|
||||
pools, err := s.ZFS.ListPools(ctx)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
for _, p := range pools {
|
||||
if p.Name == name {
|
||||
return "", ErrDuplicatePool
|
||||
}
|
||||
}
|
||||
// Create a job to build a pool. For skeleton, we just create a job entry with type create-pool
|
||||
j := domain.Job{Type: "create-pool", Status: "queued", Owner: domain.UUID(user)}
|
||||
id, err := s.JobRunner.Enqueue(ctx, j)
|
||||
// Store details in audit
|
||||
if s.Audit != nil {
|
||||
s.Audit.Record(ctx, audit.Event{UserID: user, Action: "pool.create.request", ResourceType: "pool", ResourceID: name, Success: err == nil, Details: map[string]any{"vdevs": vdevs}})
|
||||
}
|
||||
return id, err
|
||||
}
|
||||
|
||||
// Snapshot dataset
|
||||
func (s *StorageService) Snapshot(ctx context.Context, user, role, dataset, snapName string) (string, error) {
|
||||
if role != "admin" && role != "operator" {
|
||||
return "", ErrForbidden
|
||||
}
|
||||
// call zfs snapshot, but do as job; enqueue
|
||||
j := domain.Job{Type: "snapshot", Status: "queued", Owner: domain.UUID(user)}
|
||||
id, err := s.JobRunner.Enqueue(ctx, j)
|
||||
if s.Audit != nil {
|
||||
s.Audit.Record(ctx, audit.Event{UserID: user, Action: "dataset.snapshot.request", ResourceType: "snapshot", ResourceID: fmt.Sprintf("%s@%s", dataset, snapName), Success: err == nil, Details: map[string]any{"dataset": dataset}})
|
||||
}
|
||||
return id, err
|
||||
}
|
||||
|
||||
func (s *StorageService) ScrubStart(ctx context.Context, user, role, pool string) (string, error) {
|
||||
if role != "admin" && role != "operator" {
|
||||
return "", ErrForbidden
|
||||
}
|
||||
j := domain.Job{Type: "scrub", Status: "queued", Owner: domain.UUID(user)}
|
||||
id, err := s.JobRunner.Enqueue(ctx, j)
|
||||
if s.Audit != nil {
|
||||
s.Audit.Record(ctx, audit.Event{UserID: user, Action: "pool.scrub.request", ResourceType: "pool", ResourceID: pool, Success: err == nil})
|
||||
}
|
||||
return id, err
|
||||
}
|
||||
|
||||
// ListDatasets returns datasets for a pool
|
||||
func (s *StorageService) ListDatasets(ctx context.Context, pool string) ([]domain.Dataset, error) {
|
||||
return s.ZFS.ListDatasets(ctx, pool)
|
||||
}
|
||||
|
||||
// CreateDataset creates dataset synchronously or as job; for skeleton, do sync
|
||||
func (s *StorageService) CreateDataset(ctx context.Context, user, role, name string, props map[string]string) error {
|
||||
if role != "admin" && role != "operator" {
|
||||
return ErrForbidden
|
||||
}
|
||||
return s.ZFS.CreateDataset(ctx, name, props)
|
||||
}
|
||||
|
||||
// GetPoolStatus calls the adapter
|
||||
func (s *StorageService) GetPoolStatus(ctx context.Context, pool string) (domain.PoolHealth, error) {
|
||||
return s.ZFS.GetPoolStatus(ctx, pool)
|
||||
}
|
||||
Reference in New Issue
Block a user