add some changes
This commit is contained in:
@@ -15,14 +15,17 @@ import (
|
||||
|
||||
// Handler handles storage-related API requests
|
||||
type Handler struct {
|
||||
diskService *DiskService
|
||||
lvmService *LVMService
|
||||
zfsService *ZFSService
|
||||
arcService *ARCService
|
||||
taskEngine *tasks.Engine
|
||||
db *database.DB
|
||||
logger *logger.Logger
|
||||
cache *cache.Cache // Cache for invalidation
|
||||
diskService *DiskService
|
||||
lvmService *LVMService
|
||||
zfsService *ZFSService
|
||||
snapshotService *SnapshotService
|
||||
snapshotScheduleService *SnapshotScheduleService
|
||||
replicationService *ReplicationService
|
||||
arcService *ARCService
|
||||
taskEngine *tasks.Engine
|
||||
db *database.DB
|
||||
logger *logger.Logger
|
||||
cache *cache.Cache // Cache for invalidation
|
||||
}
|
||||
|
||||
// SetCache sets the cache instance for cache invalidation
|
||||
@@ -32,14 +35,18 @@ func (h *Handler) SetCache(c *cache.Cache) {
|
||||
|
||||
// NewHandler creates a new storage handler
|
||||
func NewHandler(db *database.DB, log *logger.Logger) *Handler {
|
||||
snapshotService := NewSnapshotService(db, log)
|
||||
return &Handler{
|
||||
diskService: NewDiskService(db, log),
|
||||
lvmService: NewLVMService(db, log),
|
||||
zfsService: NewZFSService(db, log),
|
||||
arcService: NewARCService(log),
|
||||
taskEngine: tasks.NewEngine(db, log),
|
||||
db: db,
|
||||
logger: log,
|
||||
diskService: NewDiskService(db, log),
|
||||
lvmService: NewLVMService(db, log),
|
||||
zfsService: NewZFSService(db, log),
|
||||
snapshotService: snapshotService,
|
||||
snapshotScheduleService: NewSnapshotScheduleService(db, log, snapshotService),
|
||||
replicationService: NewReplicationService(db, log),
|
||||
arcService: NewARCService(log),
|
||||
taskEngine: tasks.NewEngine(db, log),
|
||||
db: db,
|
||||
logger: log,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -509,3 +516,417 @@ func (h *Handler) GetARCStats(c *gin.Context) {
|
||||
|
||||
c.JSON(http.StatusOK, stats)
|
||||
}
|
||||
|
||||
// ListSnapshots lists all snapshots, optionally filtered by dataset
|
||||
func (h *Handler) ListSnapshots(c *gin.Context) {
|
||||
datasetFilter := c.DefaultQuery("dataset", "")
|
||||
|
||||
snapshots, err := h.snapshotService.ListSnapshots(c.Request.Context(), datasetFilter)
|
||||
if err != nil {
|
||||
h.logger.Error("Failed to list snapshots", "error", err, "dataset", datasetFilter)
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to list snapshots: " + err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{"snapshots": snapshots})
|
||||
}
|
||||
|
||||
// CreateSnapshotRequest represents a request to create a snapshot
|
||||
type CreateSnapshotRequest struct {
|
||||
Dataset string `json:"dataset" binding:"required"`
|
||||
Name string `json:"name" binding:"required"`
|
||||
Recursive bool `json:"recursive"`
|
||||
}
|
||||
|
||||
// CreateSnapshot creates a new snapshot
|
||||
func (h *Handler) CreateSnapshot(c *gin.Context) {
|
||||
var req CreateSnapshotRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
h.logger.Error("Invalid create snapshot request", "error", err)
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid request: " + err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
if err := h.snapshotService.CreateSnapshot(c.Request.Context(), req.Dataset, req.Name, req.Recursive); err != nil {
|
||||
h.logger.Error("Failed to create snapshot", "error", err, "dataset", req.Dataset, "name", req.Name)
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to create snapshot: " + err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusCreated, gin.H{"message": "snapshot created successfully"})
|
||||
}
|
||||
|
||||
// DeleteSnapshot deletes a snapshot
|
||||
func (h *Handler) DeleteSnapshot(c *gin.Context) {
|
||||
snapshotName := c.Param("name")
|
||||
recursive := c.DefaultQuery("recursive", "false") == "true"
|
||||
|
||||
if err := h.snapshotService.DeleteSnapshot(c.Request.Context(), snapshotName, recursive); err != nil {
|
||||
h.logger.Error("Failed to delete snapshot", "error", err, "snapshot", snapshotName)
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to delete snapshot: " + err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{"message": "snapshot deleted successfully"})
|
||||
}
|
||||
|
||||
// RollbackSnapshotRequest represents a request to rollback to a snapshot
|
||||
type RollbackSnapshotRequest struct {
|
||||
Force bool `json:"force"`
|
||||
}
|
||||
|
||||
// RollbackSnapshot rolls back a dataset to a snapshot
|
||||
func (h *Handler) RollbackSnapshot(c *gin.Context) {
|
||||
snapshotName := c.Param("name")
|
||||
|
||||
var req RollbackSnapshotRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
// Default to false if not provided
|
||||
req.Force = false
|
||||
}
|
||||
|
||||
if err := h.snapshotService.RollbackSnapshot(c.Request.Context(), snapshotName, req.Force); err != nil {
|
||||
h.logger.Error("Failed to rollback snapshot", "error", err, "snapshot", snapshotName)
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to rollback snapshot: " + err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{"message": "snapshot rollback completed successfully"})
|
||||
}
|
||||
|
||||
// CloneSnapshotRequest represents a request to clone a snapshot
|
||||
type CloneSnapshotRequest struct {
|
||||
CloneName string `json:"clone_name" binding:"required"`
|
||||
}
|
||||
|
||||
// CloneSnapshot clones a snapshot to a new dataset
|
||||
func (h *Handler) CloneSnapshot(c *gin.Context) {
|
||||
snapshotName := c.Param("name")
|
||||
|
||||
var req CloneSnapshotRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
h.logger.Error("Invalid clone snapshot request", "error", err)
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid request: " + err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
if err := h.snapshotService.CloneSnapshot(c.Request.Context(), snapshotName, req.CloneName); err != nil {
|
||||
h.logger.Error("Failed to clone snapshot", "error", err, "snapshot", snapshotName, "clone", req.CloneName)
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to clone snapshot: " + err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusCreated, gin.H{"message": "snapshot cloned successfully", "clone_name": req.CloneName})
|
||||
}
|
||||
|
||||
// ListSnapshotSchedules lists all snapshot schedules
|
||||
func (h *Handler) ListSnapshotSchedules(c *gin.Context) {
|
||||
schedules, err := h.snapshotScheduleService.ListSchedules(c.Request.Context())
|
||||
if err != nil {
|
||||
h.logger.Error("Failed to list snapshot schedules", "error", err)
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to list snapshot schedules: " + err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{"schedules": schedules})
|
||||
}
|
||||
|
||||
// GetSnapshotSchedule retrieves a snapshot schedule by ID
|
||||
func (h *Handler) GetSnapshotSchedule(c *gin.Context) {
|
||||
id := c.Param("id")
|
||||
|
||||
schedule, err := h.snapshotScheduleService.GetSchedule(c.Request.Context(), id)
|
||||
if err != nil {
|
||||
if err.Error() == "schedule not found" {
|
||||
c.JSON(http.StatusNotFound, gin.H{"error": "schedule not found"})
|
||||
return
|
||||
}
|
||||
h.logger.Error("Failed to get snapshot schedule", "error", err, "id", id)
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to get snapshot schedule: " + err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, schedule)
|
||||
}
|
||||
|
||||
// CreateSnapshotScheduleRequest represents a request to create a snapshot schedule
|
||||
type CreateSnapshotScheduleRequest struct {
|
||||
Name string `json:"name" binding:"required"`
|
||||
Dataset string `json:"dataset" binding:"required"`
|
||||
SnapshotNameTemplate string `json:"snapshot_name_template" binding:"required"`
|
||||
ScheduleType string `json:"schedule_type" binding:"required"`
|
||||
ScheduleConfig map[string]interface{} `json:"schedule_config" binding:"required"`
|
||||
Recursive bool `json:"recursive"`
|
||||
RetentionCount *int `json:"retention_count"`
|
||||
RetentionDays *int `json:"retention_days"`
|
||||
}
|
||||
|
||||
// CreateSnapshotSchedule creates a new snapshot schedule
|
||||
func (h *Handler) CreateSnapshotSchedule(c *gin.Context) {
|
||||
var req CreateSnapshotScheduleRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
h.logger.Error("Invalid create snapshot schedule request", "error", err)
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid request: " + err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
userID, _ := c.Get("user_id")
|
||||
userIDStr := ""
|
||||
if userID != nil {
|
||||
userIDStr = userID.(string)
|
||||
}
|
||||
|
||||
schedule, err := h.snapshotScheduleService.CreateSchedule(c.Request.Context(), &CreateScheduleRequest{
|
||||
Name: req.Name,
|
||||
Dataset: req.Dataset,
|
||||
SnapshotNameTemplate: req.SnapshotNameTemplate,
|
||||
ScheduleType: req.ScheduleType,
|
||||
ScheduleConfig: req.ScheduleConfig,
|
||||
Recursive: req.Recursive,
|
||||
RetentionCount: req.RetentionCount,
|
||||
RetentionDays: req.RetentionDays,
|
||||
}, userIDStr)
|
||||
if err != nil {
|
||||
h.logger.Error("Failed to create snapshot schedule", "error", err)
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to create snapshot schedule: " + err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusCreated, schedule)
|
||||
}
|
||||
|
||||
// UpdateSnapshotSchedule updates an existing snapshot schedule
|
||||
func (h *Handler) UpdateSnapshotSchedule(c *gin.Context) {
|
||||
id := c.Param("id")
|
||||
|
||||
var req CreateSnapshotScheduleRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
h.logger.Error("Invalid update snapshot schedule request", "error", err)
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid request: " + err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
schedule, err := h.snapshotScheduleService.UpdateSchedule(c.Request.Context(), id, &CreateScheduleRequest{
|
||||
Name: req.Name,
|
||||
Dataset: req.Dataset,
|
||||
SnapshotNameTemplate: req.SnapshotNameTemplate,
|
||||
ScheduleType: req.ScheduleType,
|
||||
ScheduleConfig: req.ScheduleConfig,
|
||||
Recursive: req.Recursive,
|
||||
RetentionCount: req.RetentionCount,
|
||||
RetentionDays: req.RetentionDays,
|
||||
})
|
||||
if err != nil {
|
||||
if err.Error() == "schedule not found" {
|
||||
c.JSON(http.StatusNotFound, gin.H{"error": "schedule not found"})
|
||||
return
|
||||
}
|
||||
h.logger.Error("Failed to update snapshot schedule", "error", err, "id", id)
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to update snapshot schedule: " + err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, schedule)
|
||||
}
|
||||
|
||||
// DeleteSnapshotSchedule deletes a snapshot schedule
|
||||
func (h *Handler) DeleteSnapshotSchedule(c *gin.Context) {
|
||||
id := c.Param("id")
|
||||
|
||||
if err := h.snapshotScheduleService.DeleteSchedule(c.Request.Context(), id); err != nil {
|
||||
if err.Error() == "schedule not found" {
|
||||
c.JSON(http.StatusNotFound, gin.H{"error": "schedule not found"})
|
||||
return
|
||||
}
|
||||
h.logger.Error("Failed to delete snapshot schedule", "error", err, "id", id)
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to delete snapshot schedule: " + err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{"message": "snapshot schedule deleted successfully"})
|
||||
}
|
||||
|
||||
// ToggleSnapshotSchedule enables or disables a snapshot schedule
|
||||
func (h *Handler) ToggleSnapshotSchedule(c *gin.Context) {
|
||||
id := c.Param("id")
|
||||
|
||||
var req struct {
|
||||
Enabled bool `json:"enabled" binding:"required"`
|
||||
}
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
h.logger.Error("Invalid toggle snapshot schedule request", "error", err)
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid request: " + err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
if err := h.snapshotScheduleService.ToggleSchedule(c.Request.Context(), id, req.Enabled); err != nil {
|
||||
if err.Error() == "schedule not found" {
|
||||
c.JSON(http.StatusNotFound, gin.H{"error": "schedule not found"})
|
||||
return
|
||||
}
|
||||
h.logger.Error("Failed to toggle snapshot schedule", "error", err, "id", id)
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to toggle snapshot schedule: " + err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{"message": "snapshot schedule toggled successfully"})
|
||||
}
|
||||
|
||||
// ListReplicationTasks lists all replication tasks
|
||||
func (h *Handler) ListReplicationTasks(c *gin.Context) {
|
||||
direction := c.Query("direction") // Optional filter: "outbound" or "inbound"
|
||||
tasks, err := h.replicationService.ListReplicationTasks(c.Request.Context(), direction)
|
||||
if err != nil {
|
||||
h.logger.Error("Failed to list replication tasks", "error", err)
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to list replication tasks: " + err.Error()})
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusOK, gin.H{"tasks": tasks})
|
||||
}
|
||||
|
||||
// GetReplicationTask retrieves a replication task by ID
|
||||
func (h *Handler) GetReplicationTask(c *gin.Context) {
|
||||
id := c.Param("id")
|
||||
task, err := h.replicationService.GetReplicationTask(c.Request.Context(), id)
|
||||
if err != nil {
|
||||
if err.Error() == "replication task not found" {
|
||||
c.JSON(http.StatusNotFound, gin.H{"error": "replication task not found"})
|
||||
return
|
||||
}
|
||||
h.logger.Error("Failed to get replication task", "error", err, "id", id)
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to get replication task: " + err.Error()})
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusOK, task)
|
||||
}
|
||||
|
||||
// CreateReplicationTaskRequest represents a request to create a replication task
|
||||
type CreateReplicationTaskRequest struct {
|
||||
Name string `json:"name" binding:"required"`
|
||||
Direction string `json:"direction" binding:"required"`
|
||||
SourceDataset *string `json:"source_dataset"`
|
||||
TargetHost *string `json:"target_host"`
|
||||
TargetPort *int `json:"target_port"`
|
||||
TargetUser *string `json:"target_user"`
|
||||
TargetDataset *string `json:"target_dataset"`
|
||||
TargetSSHKeyPath *string `json:"target_ssh_key_path"`
|
||||
SourceHost *string `json:"source_host"`
|
||||
SourcePort *int `json:"source_port"`
|
||||
SourceUser *string `json:"source_user"`
|
||||
LocalDataset *string `json:"local_dataset"`
|
||||
ScheduleType *string `json:"schedule_type"`
|
||||
ScheduleConfig map[string]interface{} `json:"schedule_config"`
|
||||
Compression string `json:"compression"`
|
||||
Encryption bool `json:"encryption"`
|
||||
Recursive bool `json:"recursive"`
|
||||
Incremental bool `json:"incremental"`
|
||||
AutoSnapshot bool `json:"auto_snapshot"`
|
||||
Enabled bool `json:"enabled"`
|
||||
}
|
||||
|
||||
// CreateReplicationTask creates a new replication task
|
||||
func (h *Handler) CreateReplicationTask(c *gin.Context) {
|
||||
var req CreateReplicationTaskRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
h.logger.Error("Invalid create replication task request", "error", err)
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid request: " + err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
userID, _ := c.Get("user_id")
|
||||
userIDStr := ""
|
||||
if userID != nil {
|
||||
userIDStr = userID.(string)
|
||||
}
|
||||
|
||||
task, err := h.replicationService.CreateReplicationTask(c.Request.Context(), &CreateReplicationRequest{
|
||||
Name: req.Name,
|
||||
Direction: req.Direction,
|
||||
SourceDataset: req.SourceDataset,
|
||||
TargetHost: req.TargetHost,
|
||||
TargetPort: req.TargetPort,
|
||||
TargetUser: req.TargetUser,
|
||||
TargetDataset: req.TargetDataset,
|
||||
TargetSSHKeyPath: req.TargetSSHKeyPath,
|
||||
SourceHost: req.SourceHost,
|
||||
SourcePort: req.SourcePort,
|
||||
SourceUser: req.SourceUser,
|
||||
LocalDataset: req.LocalDataset,
|
||||
ScheduleType: req.ScheduleType,
|
||||
ScheduleConfig: req.ScheduleConfig,
|
||||
Compression: req.Compression,
|
||||
Encryption: req.Encryption,
|
||||
Recursive: req.Recursive,
|
||||
Incremental: req.Incremental,
|
||||
AutoSnapshot: req.AutoSnapshot,
|
||||
Enabled: req.Enabled,
|
||||
}, userIDStr)
|
||||
if err != nil {
|
||||
h.logger.Error("Failed to create replication task", "error", err)
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to create replication task: " + err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusCreated, task)
|
||||
}
|
||||
|
||||
// UpdateReplicationTask updates an existing replication task
|
||||
func (h *Handler) UpdateReplicationTask(c *gin.Context) {
|
||||
id := c.Param("id")
|
||||
var req CreateReplicationTaskRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
h.logger.Error("Invalid update replication task request", "error", err)
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid request: " + err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
task, err := h.replicationService.UpdateReplicationTask(c.Request.Context(), id, &CreateReplicationRequest{
|
||||
Name: req.Name,
|
||||
Direction: req.Direction,
|
||||
SourceDataset: req.SourceDataset,
|
||||
TargetHost: req.TargetHost,
|
||||
TargetPort: req.TargetPort,
|
||||
TargetUser: req.TargetUser,
|
||||
TargetDataset: req.TargetDataset,
|
||||
TargetSSHKeyPath: req.TargetSSHKeyPath,
|
||||
SourceHost: req.SourceHost,
|
||||
SourcePort: req.SourcePort,
|
||||
SourceUser: req.SourceUser,
|
||||
LocalDataset: req.LocalDataset,
|
||||
ScheduleType: req.ScheduleType,
|
||||
ScheduleConfig: req.ScheduleConfig,
|
||||
Compression: req.Compression,
|
||||
Encryption: req.Encryption,
|
||||
Recursive: req.Recursive,
|
||||
Incremental: req.Incremental,
|
||||
AutoSnapshot: req.AutoSnapshot,
|
||||
Enabled: req.Enabled,
|
||||
})
|
||||
if err != nil {
|
||||
if err.Error() == "replication task not found" {
|
||||
c.JSON(http.StatusNotFound, gin.H{"error": "replication task not found"})
|
||||
return
|
||||
}
|
||||
h.logger.Error("Failed to update replication task", "error", err, "id", id)
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to update replication task: " + err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, task)
|
||||
}
|
||||
|
||||
// DeleteReplicationTask deletes a replication task
|
||||
func (h *Handler) DeleteReplicationTask(c *gin.Context) {
|
||||
id := c.Param("id")
|
||||
if err := h.replicationService.DeleteReplicationTask(c.Request.Context(), id); err != nil {
|
||||
if err.Error() == "replication task not found" {
|
||||
c.JSON(http.StatusNotFound, gin.H{"error": "replication task not found"})
|
||||
return
|
||||
}
|
||||
h.logger.Error("Failed to delete replication task", "error", err, "id", id)
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to delete replication task: " + err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{"message": "replication task deleted successfully"})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user