package iscsi import ( "fmt" "os" "os/exec" "strings" "github.com/bams/backend/internal/config" "github.com/bams/backend/internal/logger" ) type Target struct { ID string `json:"id"` IQN string `json:"iqn"` Portals []string `json:"portals"` Initiators []string `json:"initiators"` LUNs []LUN `json:"luns"` Status string `json:"status"` } type LUN struct { Number int `json:"number"` Device string `json:"device"` Type string `json:"type"` // "disk" or "tape" } type Session struct { TargetIQN string `json:"target_iqn"` InitiatorIQN string `json:"initiator_iqn"` IP string `json:"ip"` State string `json:"state"` } type Service struct { config *config.Config logger *logger.Logger } func NewService(cfg *config.Config, log *logger.Logger) *Service { return &Service{ config: cfg, logger: log, } } func (s *Service) ListTargets() ([]*Target, error) { s.logger.Debug("Listing iSCSI targets") // Read SCST configuration targets := []*Target{} // Parse SCST config file if _, err := os.Stat(s.config.SCSTConfig); err == nil { data, err := os.ReadFile(s.config.SCSTConfig) if err == nil { targets = s.parseSCSTConfig(string(data)) } } return targets, nil } func (s *Service) GetTarget(id string) (*Target, error) { targets, err := s.ListTargets() if err != nil { return nil, err } for _, target := range targets { if target.ID == id || target.IQN == id { return target, nil } } return nil, fmt.Errorf("target not found: %s", id) } func (s *Service) CreateTarget(iqn string, portals, initiators []string) (*Target, error) { s.logger.Info("Creating iSCSI target", "iqn", iqn) target := &Target{ ID: iqn, IQN: iqn, Portals: portals, Initiators: initiators, LUNs: []LUN{}, Status: "pending", } // Write to SCST config if err := s.writeSCSTConfig(target); err != nil { return nil, fmt.Errorf("failed to write SCST config: %w", err) } return target, nil } func (s *Service) UpdateTarget(id string, portals, initiators []string) (*Target, error) { target, err := s.GetTarget(id) if err != nil { return nil, err } target.Portals = portals target.Initiators = initiators if err := s.writeSCSTConfig(target); err != nil { return nil, fmt.Errorf("failed to update SCST config: %w", err) } return target, nil } func (s *Service) DeleteTarget(id string) error { s.logger.Info("Deleting iSCSI target", "id", id) // Remove from SCST config // TODO: Implement actual deletion return nil } func (s *Service) ApplyTarget(id string) error { s.logger.Info("Applying iSCSI target configuration", "id", id) // Reload SCST configuration cmd := exec.Command("scstadmin", "-config", s.config.SCSTConfig) output, err := cmd.CombinedOutput() if err != nil { s.logger.Error("Failed to apply SCST config", "error", string(output)) return fmt.Errorf("failed to apply SCST config: %w", err) } return nil } func (s *Service) ListSessions() ([]*Session, error) { s.logger.Debug("Listing iSCSI sessions") sessions := []*Session{} // Query SCST for active sessions cmd := exec.Command("scstadmin", "-list_sessions") output, err := cmd.CombinedOutput() if err == nil { sessions = s.parseSCSTSessions(string(output)) } return sessions, nil } func (s *Service) parseSCSTConfig(data string) []*Target { targets := []*Target{} // Simplified parsing - real implementation would parse SCST config format lines := strings.Split(data, "\n") currentTarget := &Target{} for _, line := range lines { line = strings.TrimSpace(line) if strings.HasPrefix(line, "TARGET") { if currentTarget.IQN != "" { targets = append(targets, currentTarget) } currentTarget = &Target{ IQN: strings.Fields(line)[1], ID: strings.Fields(line)[1], Portals: []string{}, Initiators: []string{}, LUNs: []LUN{}, Status: "active", } } } if currentTarget.IQN != "" { targets = append(targets, currentTarget) } return targets } func (s *Service) parseSCSTSessions(data string) []*Session { sessions := []*Session{} // Parse SCST session output lines := strings.Split(data, "\n") for _, line := range lines { if strings.Contains(line, "session") { // Parse session information session := &Session{ State: "active", } sessions = append(sessions, session) } } return sessions } func (s *Service) writeSCSTConfig(target *Target) error { // Generate SCST configuration config := fmt.Sprintf(`TARGET %s { enabled 1 `, target.IQN) for _, portal := range target.Portals { config += fmt.Sprintf(" portal %s {\n", portal) config += " enabled 1\n" config += " }\n" } for _, initiator := range target.Initiators { config += fmt.Sprintf(" initiator %s {\n", initiator) config += " enabled 1\n" config += " }\n" } config += "}\n" // Append to config file (simplified - real implementation would merge properly) return os.WriteFile(s.config.SCSTConfig, []byte(config), 0644) }