Files
atlas/internal/storage/iscsi.go
othman.suseno 54e76d9304
Some checks failed
CI / test-build (push) Failing after 2m1s
add authentication method
2025-12-14 23:55:12 +07:00

183 lines
3.5 KiB
Go

package storage
import (
"errors"
"fmt"
"sync"
"gitea.avt.data-center.id/othman.suseno/atlas/internal/models"
)
var (
ErrISCSITargetNotFound = errors.New("iSCSI target not found")
ErrISCSITargetExists = errors.New("iSCSI target already exists")
ErrLUNNotFound = errors.New("LUN not found")
ErrLUNExists = errors.New("LUN already exists")
)
// ISCSIStore manages iSCSI targets and LUNs
type ISCSIStore struct {
mu sync.RWMutex
targets map[string]*models.ISCSITarget
nextID int
}
// NewISCSIStore creates a new iSCSI store
func NewISCSIStore() *ISCSIStore {
return &ISCSIStore{
targets: make(map[string]*models.ISCSITarget),
nextID: 1,
}
}
// List returns all iSCSI targets
func (s *ISCSIStore) List() []models.ISCSITarget {
s.mu.RLock()
defer s.mu.RUnlock()
targets := make([]models.ISCSITarget, 0, len(s.targets))
for _, target := range s.targets {
targets = append(targets, *target)
}
return targets
}
// Get returns a target by ID
func (s *ISCSIStore) Get(id string) (*models.ISCSITarget, error) {
s.mu.RLock()
defer s.mu.RUnlock()
target, ok := s.targets[id]
if !ok {
return nil, ErrISCSITargetNotFound
}
return target, nil
}
// GetByIQN returns a target by IQN
func (s *ISCSIStore) GetByIQN(iqn string) (*models.ISCSITarget, error) {
s.mu.RLock()
defer s.mu.RUnlock()
for _, target := range s.targets {
if target.IQN == iqn {
return target, nil
}
}
return nil, ErrISCSITargetNotFound
}
// Create creates a new iSCSI target
func (s *ISCSIStore) Create(iqn string, initiators []string) (*models.ISCSITarget, error) {
s.mu.Lock()
defer s.mu.Unlock()
// Check if IQN already exists
for _, target := range s.targets {
if target.IQN == iqn {
return nil, ErrISCSITargetExists
}
}
id := fmt.Sprintf("iscsi-%d", s.nextID)
s.nextID++
target := &models.ISCSITarget{
ID: id,
IQN: iqn,
LUNs: []models.LUN{},
Initiators: initiators,
Enabled: true,
}
s.targets[id] = target
return target, nil
}
// Update updates an existing target
func (s *ISCSIStore) Update(id string, initiators []string, enabled bool) error {
s.mu.Lock()
defer s.mu.Unlock()
target, ok := s.targets[id]
if !ok {
return ErrISCSITargetNotFound
}
target.Enabled = enabled
if initiators != nil {
target.Initiators = initiators
}
return nil
}
// Delete removes a target
func (s *ISCSIStore) Delete(id string) error {
s.mu.Lock()
defer s.mu.Unlock()
if _, ok := s.targets[id]; !ok {
return ErrISCSITargetNotFound
}
delete(s.targets, id)
return nil
}
// AddLUN adds a LUN to a target
func (s *ISCSIStore) AddLUN(targetID string, zvol string, size uint64) (*models.LUN, error) {
s.mu.Lock()
defer s.mu.Unlock()
target, ok := s.targets[targetID]
if !ok {
return nil, ErrISCSITargetNotFound
}
// Check if ZVOL already mapped
for _, lun := range target.LUNs {
if lun.ZVOL == zvol {
return nil, ErrLUNExists
}
}
// Find next available LUN ID
lunID := 0
for _, lun := range target.LUNs {
if lun.ID >= lunID {
lunID = lun.ID + 1
}
}
lun := models.LUN{
ID: lunID,
ZVOL: zvol,
Size: size,
Backend: "zvol",
}
target.LUNs = append(target.LUNs, lun)
return &lun, nil
}
// RemoveLUN removes a LUN from a target
func (s *ISCSIStore) RemoveLUN(targetID string, lunID int) error {
s.mu.Lock()
defer s.mu.Unlock()
target, ok := s.targets[targetID]
if !ok {
return ErrISCSITargetNotFound
}
for i, lun := range target.LUNs {
if lun.ID == lunID {
target.LUNs = append(target.LUNs[:i], target.LUNs[i+1:]...)
return nil
}
}
return ErrLUNNotFound
}