first commit
This commit is contained in:
+212
@@ -0,0 +1,212 @@
|
||||
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()
|
||||
}
|
||||
Reference in New Issue
Block a user