working on the backup management parts
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
package scst
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/atlasos/calypso/internal/common/database"
|
||||
@@ -11,19 +12,19 @@ import (
|
||||
|
||||
// Handler handles SCST-related API requests
|
||||
type Handler struct {
|
||||
service *Service
|
||||
service *Service
|
||||
taskEngine *tasks.Engine
|
||||
db *database.DB
|
||||
logger *logger.Logger
|
||||
db *database.DB
|
||||
logger *logger.Logger
|
||||
}
|
||||
|
||||
// NewHandler creates a new SCST handler
|
||||
func NewHandler(db *database.DB, log *logger.Logger) *Handler {
|
||||
return &Handler{
|
||||
service: NewService(db, log),
|
||||
service: NewService(db, log),
|
||||
taskEngine: tasks.NewEngine(db, log),
|
||||
db: db,
|
||||
logger: log,
|
||||
db: db,
|
||||
logger: log,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,21 +56,34 @@ func (h *Handler) GetTarget(c *gin.Context) {
|
||||
}
|
||||
|
||||
// Get LUNs
|
||||
luns, _ := h.service.GetTargetLUNs(c.Request.Context(), targetID)
|
||||
luns, err := h.service.GetTargetLUNs(c.Request.Context(), targetID)
|
||||
if err != nil {
|
||||
h.logger.Warn("Failed to get LUNs", "target_id", targetID, "error", err)
|
||||
// Return empty array instead of nil
|
||||
luns = []LUN{}
|
||||
}
|
||||
|
||||
// Get initiator groups
|
||||
groups, err2 := h.service.GetTargetInitiatorGroups(c.Request.Context(), targetID)
|
||||
if err2 != nil {
|
||||
h.logger.Warn("Failed to get initiator groups", "target_id", targetID, "error", err2)
|
||||
groups = []InitiatorGroup{}
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"target": target,
|
||||
"luns": luns,
|
||||
"target": target,
|
||||
"luns": luns,
|
||||
"initiator_groups": groups,
|
||||
})
|
||||
}
|
||||
|
||||
// CreateTargetRequest represents a target creation request
|
||||
type CreateTargetRequest struct {
|
||||
IQN string `json:"iqn" binding:"required"`
|
||||
TargetType string `json:"target_type" binding:"required"`
|
||||
Name string `json:"name" binding:"required"`
|
||||
Description string `json:"description"`
|
||||
SingleInitiatorOnly bool `json:"single_initiator_only"`
|
||||
IQN string `json:"iqn" binding:"required"`
|
||||
TargetType string `json:"target_type" binding:"required"`
|
||||
Name string `json:"name" binding:"required"`
|
||||
Description string `json:"description"`
|
||||
SingleInitiatorOnly bool `json:"single_initiator_only"`
|
||||
}
|
||||
|
||||
// CreateTarget creates a new SCST target
|
||||
@@ -83,13 +97,13 @@ func (h *Handler) CreateTarget(c *gin.Context) {
|
||||
userID, _ := c.Get("user_id")
|
||||
|
||||
target := &Target{
|
||||
IQN: req.IQN,
|
||||
TargetType: req.TargetType,
|
||||
Name: req.Name,
|
||||
Description: req.Description,
|
||||
IsActive: true,
|
||||
IQN: req.IQN,
|
||||
TargetType: req.TargetType,
|
||||
Name: req.Name,
|
||||
Description: req.Description,
|
||||
IsActive: true,
|
||||
SingleInitiatorOnly: req.SingleInitiatorOnly || req.TargetType == "vtl" || req.TargetType == "physical_tape",
|
||||
CreatedBy: userID.(string),
|
||||
CreatedBy: userID.(string),
|
||||
}
|
||||
|
||||
if err := h.service.CreateTarget(c.Request.Context(), target); err != nil {
|
||||
@@ -103,9 +117,9 @@ func (h *Handler) CreateTarget(c *gin.Context) {
|
||||
|
||||
// AddLUNRequest represents a LUN addition request
|
||||
type AddLUNRequest struct {
|
||||
DeviceName string `json:"device_name" binding:"required"`
|
||||
DevicePath string `json:"device_path" binding:"required"`
|
||||
LUNNumber int `json:"lun_number" binding:"required"`
|
||||
DeviceName string `json:"device_name" binding:"required"`
|
||||
DevicePath string `json:"device_path" binding:"required"`
|
||||
LUNNumber int `json:"lun_number" binding:"required"`
|
||||
HandlerType string `json:"handler_type" binding:"required"`
|
||||
}
|
||||
|
||||
@@ -121,7 +135,15 @@ func (h *Handler) AddLUN(c *gin.Context) {
|
||||
|
||||
var req AddLUNRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid request"})
|
||||
h.logger.Error("Failed to bind AddLUN request", "error", err)
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": fmt.Sprintf("invalid request: %v", err)})
|
||||
return
|
||||
}
|
||||
|
||||
// Validate required fields
|
||||
if req.DeviceName == "" || req.DevicePath == "" || req.HandlerType == "" {
|
||||
h.logger.Error("Missing required fields in AddLUN request", "device_name", req.DeviceName, "device_path", req.DevicePath, "handler_type", req.HandlerType)
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "device_name, device_path, and handler_type are required"})
|
||||
return
|
||||
}
|
||||
|
||||
@@ -164,6 +186,110 @@ func (h *Handler) AddInitiator(c *gin.Context) {
|
||||
c.JSON(http.StatusOK, gin.H{"message": "Initiator added successfully"})
|
||||
}
|
||||
|
||||
// ListAllInitiators lists all initiators across all targets
|
||||
func (h *Handler) ListAllInitiators(c *gin.Context) {
|
||||
initiators, err := h.service.ListAllInitiators(c.Request.Context())
|
||||
if err != nil {
|
||||
h.logger.Error("Failed to list initiators", "error", err)
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to list initiators"})
|
||||
return
|
||||
}
|
||||
|
||||
if initiators == nil {
|
||||
initiators = []InitiatorWithTarget{}
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{"initiators": initiators})
|
||||
}
|
||||
|
||||
// RemoveInitiator removes an initiator
|
||||
func (h *Handler) RemoveInitiator(c *gin.Context) {
|
||||
initiatorID := c.Param("id")
|
||||
|
||||
if err := h.service.RemoveInitiator(c.Request.Context(), initiatorID); err != nil {
|
||||
if err.Error() == "initiator not found" {
|
||||
c.JSON(http.StatusNotFound, gin.H{"error": "initiator not found"})
|
||||
return
|
||||
}
|
||||
h.logger.Error("Failed to remove initiator", "error", err)
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{"message": "Initiator removed successfully"})
|
||||
}
|
||||
|
||||
// GetInitiator retrieves an initiator by ID
|
||||
func (h *Handler) GetInitiator(c *gin.Context) {
|
||||
initiatorID := c.Param("id")
|
||||
|
||||
initiator, err := h.service.GetInitiator(c.Request.Context(), initiatorID)
|
||||
if err != nil {
|
||||
if err.Error() == "initiator not found" {
|
||||
c.JSON(http.StatusNotFound, gin.H{"error": "initiator not found"})
|
||||
return
|
||||
}
|
||||
h.logger.Error("Failed to get initiator", "error", err)
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to get initiator"})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, initiator)
|
||||
}
|
||||
|
||||
// ListExtents lists all device extents
|
||||
func (h *Handler) ListExtents(c *gin.Context) {
|
||||
extents, err := h.service.ListExtents(c.Request.Context())
|
||||
if err != nil {
|
||||
h.logger.Error("Failed to list extents", "error", err)
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to list extents"})
|
||||
return
|
||||
}
|
||||
|
||||
if extents == nil {
|
||||
extents = []Extent{}
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{"extents": extents})
|
||||
}
|
||||
|
||||
// CreateExtentRequest represents a request to create an extent
|
||||
type CreateExtentRequest struct {
|
||||
DeviceName string `json:"device_name" binding:"required"`
|
||||
DevicePath string `json:"device_path" binding:"required"`
|
||||
HandlerType string `json:"handler_type" binding:"required"`
|
||||
}
|
||||
|
||||
// CreateExtent creates a new device extent
|
||||
func (h *Handler) CreateExtent(c *gin.Context) {
|
||||
var req CreateExtentRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid request"})
|
||||
return
|
||||
}
|
||||
|
||||
if err := h.service.CreateExtent(c.Request.Context(), req.DeviceName, req.DevicePath, req.HandlerType); err != nil {
|
||||
h.logger.Error("Failed to create extent", "error", err)
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusCreated, gin.H{"message": "Extent created successfully"})
|
||||
}
|
||||
|
||||
// DeleteExtent deletes a device extent
|
||||
func (h *Handler) DeleteExtent(c *gin.Context) {
|
||||
deviceName := c.Param("device")
|
||||
|
||||
if err := h.service.DeleteExtent(c.Request.Context(), deviceName); err != nil {
|
||||
h.logger.Error("Failed to delete extent", "error", err)
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{"message": "Extent deleted successfully"})
|
||||
}
|
||||
|
||||
// ApplyConfig applies SCST configuration
|
||||
func (h *Handler) ApplyConfig(c *gin.Context) {
|
||||
userID, _ := c.Get("user_id")
|
||||
@@ -209,3 +335,142 @@ func (h *Handler) ListHandlers(c *gin.Context) {
|
||||
c.JSON(http.StatusOK, gin.H{"handlers": handlers})
|
||||
}
|
||||
|
||||
// ListPortals lists all iSCSI portals
|
||||
func (h *Handler) ListPortals(c *gin.Context) {
|
||||
portals, err := h.service.ListPortals(c.Request.Context())
|
||||
if err != nil {
|
||||
h.logger.Error("Failed to list portals", "error", err)
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to list portals"})
|
||||
return
|
||||
}
|
||||
|
||||
// Ensure we return an empty array instead of null
|
||||
if portals == nil {
|
||||
portals = []Portal{}
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{"portals": portals})
|
||||
}
|
||||
|
||||
// CreatePortal creates a new portal
|
||||
func (h *Handler) CreatePortal(c *gin.Context) {
|
||||
var portal Portal
|
||||
if err := c.ShouldBindJSON(&portal); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid request"})
|
||||
return
|
||||
}
|
||||
|
||||
if err := h.service.CreatePortal(c.Request.Context(), &portal); err != nil {
|
||||
h.logger.Error("Failed to create portal", "error", err)
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusCreated, portal)
|
||||
}
|
||||
|
||||
// UpdatePortal updates a portal
|
||||
func (h *Handler) UpdatePortal(c *gin.Context) {
|
||||
id := c.Param("id")
|
||||
|
||||
var portal Portal
|
||||
if err := c.ShouldBindJSON(&portal); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid request"})
|
||||
return
|
||||
}
|
||||
|
||||
if err := h.service.UpdatePortal(c.Request.Context(), id, &portal); err != nil {
|
||||
if err.Error() == "portal not found" {
|
||||
c.JSON(http.StatusNotFound, gin.H{"error": "portal not found"})
|
||||
return
|
||||
}
|
||||
h.logger.Error("Failed to update portal", "error", err)
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, portal)
|
||||
}
|
||||
|
||||
// EnableTarget enables a target
|
||||
func (h *Handler) EnableTarget(c *gin.Context) {
|
||||
targetID := c.Param("id")
|
||||
|
||||
target, err := h.service.GetTarget(c.Request.Context(), targetID)
|
||||
if err != nil {
|
||||
if err.Error() == "target not found" {
|
||||
c.JSON(http.StatusNotFound, gin.H{"error": "target not found"})
|
||||
return
|
||||
}
|
||||
h.logger.Error("Failed to get target", "error", err)
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to get target"})
|
||||
return
|
||||
}
|
||||
|
||||
if err := h.service.EnableTarget(c.Request.Context(), target.IQN); err != nil {
|
||||
h.logger.Error("Failed to enable target", "error", err)
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{"message": "Target enabled successfully"})
|
||||
}
|
||||
|
||||
// DisableTarget disables a target
|
||||
func (h *Handler) DisableTarget(c *gin.Context) {
|
||||
targetID := c.Param("id")
|
||||
|
||||
target, err := h.service.GetTarget(c.Request.Context(), targetID)
|
||||
if err != nil {
|
||||
if err.Error() == "target not found" {
|
||||
c.JSON(http.StatusNotFound, gin.H{"error": "target not found"})
|
||||
return
|
||||
}
|
||||
h.logger.Error("Failed to get target", "error", err)
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to get target"})
|
||||
return
|
||||
}
|
||||
|
||||
if err := h.service.DisableTarget(c.Request.Context(), target.IQN); err != nil {
|
||||
h.logger.Error("Failed to disable target", "error", err)
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{"message": "Target disabled successfully"})
|
||||
}
|
||||
|
||||
// DeletePortal deletes a portal
|
||||
func (h *Handler) DeletePortal(c *gin.Context) {
|
||||
id := c.Param("id")
|
||||
|
||||
if err := h.service.DeletePortal(c.Request.Context(), id); err != nil {
|
||||
if err.Error() == "portal not found" {
|
||||
c.JSON(http.StatusNotFound, gin.H{"error": "portal not found"})
|
||||
return
|
||||
}
|
||||
h.logger.Error("Failed to delete portal", "error", err)
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{"message": "Portal deleted successfully"})
|
||||
}
|
||||
|
||||
// GetPortal retrieves a portal by ID
|
||||
func (h *Handler) GetPortal(c *gin.Context) {
|
||||
id := c.Param("id")
|
||||
|
||||
portal, err := h.service.GetPortal(c.Request.Context(), id)
|
||||
if err != nil {
|
||||
if err.Error() == "portal not found" {
|
||||
c.JSON(http.StatusNotFound, gin.H{"error": "portal not found"})
|
||||
return
|
||||
}
|
||||
h.logger.Error("Failed to get portal", "error", err)
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to get portal"})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, portal)
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user