2026-04-17 11:56:39 +07:00

213 lines
5.3 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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()
}