package nfs import ( "fmt" "os" "os/exec" "sync" "time" "github.com/sirupsen/logrus" ) // Manager управляет NFS монтированием type Manager struct { mu sync.RWMutex enabled bool server string exportPath string mountPoint string options string mounted bool mountTime time.Time } var ( // DefaultManager - глобальный менеджер NFS DefaultManager *Manager initOnce sync.Once ) // Config конфигурация NFS type Config struct { Enabled bool Server string ExportPath string MountPoint string Options string } // Init инициализирует глобальный менеджер NFS func Init(cfg Config) { initOnce.Do(func() { DefaultManager = &Manager{ enabled: cfg.Enabled, server: cfg.Server, exportPath: cfg.ExportPath, mountPoint: cfg.MountPoint, options: cfg.Options, mounted: false, } if cfg.Enabled { logrus.Infof("NFS manager initialized: %s:%s -> %s", cfg.Server, cfg.ExportPath, cfg.MountPoint) } else { logrus.Info("NFS manager initialized but disabled") } }) } // IsEnabled возвращает статус включения NFS func (m *Manager) IsEnabled() bool { m.mu.RLock() defer m.mu.RUnlock() return m.enabled } // IsMounted проверяет, смонтирован ли NFS func (m *Manager) IsMounted() bool { m.mu.RLock() defer m.mu.RUnlock() if !m.mounted { return false } // Проверяем актуальность монтирования через filesystem return checkMountPoint(m.mountPoint) } // Mount монтирует NFS share func (m *Manager) Mount() error { m.mu.Lock() defer m.mu.Unlock() if !m.enabled { logrus.Debug("NFS mounting skipped: disabled") return nil } // Проверяем, уже ли смонтировано if checkMountPoint(m.mountPoint) { logrus.Debugf("NFS already mounted at %s", m.mountPoint) m.mounted = true m.mountTime = time.Now() return nil } logrus.Infof("Attempting to mount NFS: %s:%s -> %s", m.server, m.exportPath, m.mountPoint) // Создаем точку монтирования если не существует if err := os.MkdirAll(m.mountPoint, 0755); err != nil { logrus.Errorf("Failed to create mount point %s: %v", m.mountPoint, err) return fmt.Errorf("failed to create mount point: %w", err) } // Формируем опции монтирования mountOptions := m.options if mountOptions == "" { mountOptions = "rw,vers=4.1,timeo=50,retrans=2" } // Выполняем команду mount cmd := exec.Command("mount", "-t", "nfs", fmt.Sprintf("%s:%s", m.server, m.exportPath), m.mountPoint, "-o", mountOptions) output, err := cmd.CombinedOutput() if err != nil { logrus.Errorf("Failed to mount NFS: %v, output: %s", err, string(output)) m.mounted = false return fmt.Errorf("failed to mount NFS: %w, output: %s", err, string(output)) } m.mounted = true m.mountTime = time.Now() logrus.Infof("NFS mounted successfully: %s:%s -> %s", m.server, m.exportPath, m.mountPoint) return nil } // Unmount размонтирует NFS share func (m *Manager) Unmount() error { m.mu.Lock() defer m.mu.Unlock() if !m.enabled { logrus.Debug("NFS unmounting skipped: disabled") return nil } logrus.Infof("Unmounting NFS from %s", m.mountPoint) cmd := exec.Command("umount", m.mountPoint) output, err := cmd.CombinedOutput() if err != nil { logrus.Errorf("Failed to unmount NFS: %v, output: %s", err, string(output)) return fmt.Errorf("failed to unmount NFS: %w, output: %s", err, string(output)) } m.mounted = false logrus.Infof("NFS unmounted successfully from %s", m.mountPoint) return nil } // CheckHealth проверяет доступность NFS mount point func (m *Manager) CheckHealth() error { m.mu.RLock() defer m.mu.RUnlock() if !m.enabled { return nil } return checkMountPointWithDetails(m.mountPoint) } // Remount пытается перемонтировать NFS если он размонтирован func (m *Manager) Remount() error { if !m.IsMounted() { logrus.Warn("NFS not mounted, attempting remount...") return m.Mount() } return nil } // GetMountPoint возвращает точку монтирования func (m *Manager) GetMountPoint() string { m.mu.RLock() defer m.mu.RUnlock() return m.mountPoint } // checkMountPoint проверяет, смонтирована ли точка func checkMountPoint(mountPoint string) bool { // Проверяем через statfs (на Linux) // Если точка смонтирована, то она будет иметь другой device ID чем родитель cmd := exec.Command("mountpoint", "-q", mountPoint) err := cmd.Run() return err == nil } // checkMountPointWithDetails проверяет с логированием func checkMountPointWithDetails(mountPoint string) error { if !checkMountPoint(mountPoint) { return fmt.Errorf("mount point %s is not mounted", mountPoint) } return nil } // EnsureMounted гарантирует что NFS смонтирован, монтирует если нужно func EnsureMounted() error { if DefaultManager == nil { logrus.Debug("NFS manager not initialized") return nil } return DefaultManager.Remount() }