backend structure build
This commit is contained in:
100
backend/internal/services/disk/mapping.go
Normal file
100
backend/internal/services/disk/mapping.go
Normal file
@@ -0,0 +1,100 @@
|
||||
package disk
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// MapToiSCSI maps a repository to an iSCSI LUN
|
||||
func (s *Service) MapToiSCSI(repoID string, targetID string, lunNumber int) error {
|
||||
s.logger.Info("Mapping repository to iSCSI", "repo", repoID, "target", targetID, "lun", lunNumber)
|
||||
|
||||
repo, err := s.GetRepository(repoID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Get device path for the repository
|
||||
var devicePath string
|
||||
if repo.Type == "lvm" {
|
||||
// LVM device path: /dev/vgname/lvname
|
||||
devicePath = fmt.Sprintf("/dev/%s/%s", repo.VGName, repo.Name)
|
||||
} else if repo.Type == "zfs" {
|
||||
// ZFS zvol path: /dev/zvol/poolname/volname
|
||||
devicePath = fmt.Sprintf("/dev/zvol/%s/%s", repo.PoolName, repo.Name)
|
||||
} else {
|
||||
return fmt.Errorf("unsupported repository type: %s", repo.Type)
|
||||
}
|
||||
|
||||
// Verify device exists
|
||||
if _, err := filepath.EvalSymlinks(devicePath); err != nil {
|
||||
return fmt.Errorf("device not found: %s", devicePath)
|
||||
}
|
||||
|
||||
// The actual mapping is done by the iSCSI service
|
||||
// This is just a helper to get the device path
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetDevicePath returns the device path for a repository
|
||||
func (s *Service) GetDevicePath(repoID string) (string, error) {
|
||||
repo, err := s.GetRepository(repoID)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if repo.Type == "lvm" {
|
||||
return fmt.Sprintf("/dev/%s/%s", repo.VGName, repo.Name), nil
|
||||
} else if repo.Type == "zfs" {
|
||||
return fmt.Sprintf("/dev/zvol/%s/%s", repo.PoolName, repo.Name), nil
|
||||
}
|
||||
|
||||
return "", fmt.Errorf("unsupported repository type: %s", repo.Type)
|
||||
}
|
||||
|
||||
// GetRepositoryInfo returns detailed information about a repository
|
||||
func (s *Service) GetRepositoryInfo(repoID string) (map[string]interface{}, error) {
|
||||
repo, err := s.GetRepository(repoID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
info := map[string]interface{}{
|
||||
"id": repo.ID,
|
||||
"name": repo.Name,
|
||||
"type": repo.Type,
|
||||
"size": repo.Size,
|
||||
"used": repo.Used,
|
||||
"status": repo.Status,
|
||||
"mount_point": repo.MountPoint,
|
||||
}
|
||||
|
||||
// Get device path
|
||||
devicePath, err := s.GetDevicePath(repoID)
|
||||
if err == nil {
|
||||
info["device_path"] = devicePath
|
||||
}
|
||||
|
||||
// Get filesystem info if mounted
|
||||
if repo.MountPoint != "" {
|
||||
cmd := exec.Command("df", "-h", repo.MountPoint)
|
||||
output, err := cmd.CombinedOutput()
|
||||
if err == nil {
|
||||
lines := strings.Split(string(output), "\n")
|
||||
if len(lines) > 1 {
|
||||
fields := strings.Fields(lines[1])
|
||||
if len(fields) >= 5 {
|
||||
info["filesystem"] = fields[0]
|
||||
info["total_size"] = fields[1]
|
||||
info["used_size"] = fields[2]
|
||||
info["available"] = fields[3]
|
||||
info["usage_percent"] = fields[4]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return info, nil
|
||||
}
|
||||
99
backend/internal/services/iscsi/lun.go
Normal file
99
backend/internal/services/iscsi/lun.go
Normal file
@@ -0,0 +1,99 @@
|
||||
package iscsi
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
// AddLUN adds a LUN to a target
|
||||
func (s *Service) AddLUN(targetID string, lunNumber int, devicePath string, lunType string) error {
|
||||
s.logger.Info("Adding LUN to target", "target", targetID, "lun", lunNumber, "device", devicePath, "type", lunType)
|
||||
|
||||
// Validate device exists
|
||||
if _, err := os.Stat(devicePath); err != nil {
|
||||
return fmt.Errorf("device not found: %s", devicePath)
|
||||
}
|
||||
|
||||
// Validate LUN type
|
||||
if lunType != "disk" && lunType != "tape" {
|
||||
return fmt.Errorf("invalid LUN type: %s (must be 'disk' or 'tape')", lunType)
|
||||
}
|
||||
|
||||
// For tape library:
|
||||
// LUN 0 = Media changer
|
||||
// LUN 1-8 = Tape drives
|
||||
if lunType == "tape" {
|
||||
if lunNumber == 0 {
|
||||
// Media changer
|
||||
devicePath = "/dev/sg0" // Default media changer
|
||||
} else if lunNumber >= 1 && lunNumber <= 8 {
|
||||
// Tape drive
|
||||
devicePath = fmt.Sprintf("/dev/nst%d", lunNumber-1)
|
||||
} else {
|
||||
return fmt.Errorf("invalid LUN number for tape: %d (must be 0-8)", lunNumber)
|
||||
}
|
||||
}
|
||||
|
||||
// Update target configuration
|
||||
target, err := s.GetTarget(targetID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Check if LUN already exists
|
||||
for _, lun := range target.LUNs {
|
||||
if lun.Number == lunNumber {
|
||||
return fmt.Errorf("LUN %d already exists", lunNumber)
|
||||
}
|
||||
}
|
||||
|
||||
// Add LUN
|
||||
target.LUNs = append(target.LUNs, LUN{
|
||||
Number: lunNumber,
|
||||
Device: devicePath,
|
||||
Type: lunType,
|
||||
})
|
||||
|
||||
// Write updated config
|
||||
return s.writeSCSTConfig(target)
|
||||
}
|
||||
|
||||
// RemoveLUN removes a LUN from a target
|
||||
func (s *Service) RemoveLUN(targetID string, lunNumber int) error {
|
||||
s.logger.Info("Removing LUN from target", "target", targetID, "lun", lunNumber)
|
||||
|
||||
target, err := s.GetTarget(targetID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Find and remove LUN
|
||||
found := false
|
||||
newLUNs := []LUN{}
|
||||
for _, lun := range target.LUNs {
|
||||
if lun.Number != lunNumber {
|
||||
newLUNs = append(newLUNs, lun)
|
||||
} else {
|
||||
found = true
|
||||
}
|
||||
}
|
||||
|
||||
if !found {
|
||||
return fmt.Errorf("LUN %d not found", lunNumber)
|
||||
}
|
||||
|
||||
target.LUNs = newLUNs
|
||||
return s.writeSCSTConfig(target)
|
||||
}
|
||||
|
||||
// MapRepositoryToLUN maps a disk repository to an iSCSI LUN
|
||||
func (s *Service) MapRepositoryToLUN(targetID string, repositoryPath string, lunNumber int) error {
|
||||
// Resolve repository path to device
|
||||
devicePath, err := filepath.EvalSymlinks(repositoryPath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to resolve repository path: %w", err)
|
||||
}
|
||||
|
||||
return s.AddLUN(targetID, lunNumber, devicePath, "disk")
|
||||
}
|
||||
Reference in New Issue
Block a user