mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-02-18 00:17:39 +01:00
Related to #595 This change adds support for custom SSH ports when collecting temperature data from Proxmox nodes, resolving issues for users who run SSH on non-standard ports. **Why SSH is still needed:** Temperature monitoring requires reading /sys/class/hwmon sensors on Proxmox nodes, which is not exposed via the Proxmox API. Even when using API tokens for authentication, Pulse needs SSH access to collect temperature data. **Changes:** - Add `sshPort` configuration to SystemSettings (system.json) - Add `SSHPort` field to Config with environment variable support (SSH_PORT) - Add per-node SSH port override capability for PVE, PBS, and PMG instances - Update TemperatureCollector to accept and use custom SSH port - Update SSH known_hosts manager to support non-standard ports - Add NewTemperatureCollectorWithPort() constructor with port parameter - Maintain backward compatibility with NewTemperatureCollector() (uses port 22) - Update frontend TypeScript types for SSH port configuration **Configuration methods:** 1. Environment variable: SSH_PORT=2222 2. system.json: {"sshPort": 2222} 3. Per-node override in nodes.enc (future UI support) **Default behavior:** - Defaults to port 22 if not configured - Maintains full backward compatibility - No changes required for existing deployments The implementation includes proper ssh-keyscan port handling and known_hosts management for non-standard ports using [host]:port notation per SSH standards.
105 lines
2.3 KiB
Go
105 lines
2.3 KiB
Go
package monitoring
|
|
|
|
import (
|
|
"context"
|
|
stderrors "errors"
|
|
"sync"
|
|
|
|
"github.com/rcourtman/pulse-go-rewrite/internal/models"
|
|
)
|
|
|
|
var (
|
|
// ErrTemperatureMonitoringDisabled indicates that temperature polling is disabled globally.
|
|
ErrTemperatureMonitoringDisabled = stderrors.New("temperature monitoring disabled")
|
|
// ErrTemperatureCollectorUnavailable indicates the collector could not be created or is misconfigured.
|
|
ErrTemperatureCollectorUnavailable = stderrors.New("temperature collector unavailable")
|
|
)
|
|
|
|
// TemperatureService defines the contract used by the monitor to collect temperature data.
|
|
type TemperatureService interface {
|
|
Enabled() bool
|
|
Collect(ctx context.Context, host, nodeName string) (*models.Temperature, error)
|
|
Enable()
|
|
Disable()
|
|
}
|
|
|
|
type temperatureService struct {
|
|
mu sync.RWMutex
|
|
enabled bool
|
|
user string
|
|
keyPath string
|
|
sshPort int
|
|
collector *TemperatureCollector
|
|
}
|
|
|
|
func newTemperatureService(enabled bool, user, keyPath string, sshPort int) TemperatureService {
|
|
if sshPort <= 0 {
|
|
sshPort = 22
|
|
}
|
|
return &temperatureService{
|
|
enabled: enabled,
|
|
user: user,
|
|
keyPath: keyPath,
|
|
sshPort: sshPort,
|
|
}
|
|
}
|
|
|
|
func (s *temperatureService) Enabled() bool {
|
|
s.mu.RLock()
|
|
defer s.mu.RUnlock()
|
|
return s.enabled
|
|
}
|
|
|
|
func (s *temperatureService) Enable() {
|
|
s.mu.Lock()
|
|
defer s.mu.Unlock()
|
|
|
|
if s.enabled {
|
|
return
|
|
}
|
|
|
|
s.enabled = true
|
|
if s.collector == nil && s.user != "" && s.keyPath != "" {
|
|
s.collector = NewTemperatureCollectorWithPort(s.user, s.keyPath, s.sshPort)
|
|
}
|
|
}
|
|
|
|
func (s *temperatureService) Disable() {
|
|
s.mu.Lock()
|
|
defer s.mu.Unlock()
|
|
|
|
s.enabled = false
|
|
s.collector = nil
|
|
}
|
|
|
|
func (s *temperatureService) Collect(ctx context.Context, host, nodeName string) (*models.Temperature, error) {
|
|
s.mu.RLock()
|
|
enabled := s.enabled
|
|
collector := s.collector
|
|
s.mu.RUnlock()
|
|
|
|
if !enabled {
|
|
return nil, ErrTemperatureMonitoringDisabled
|
|
}
|
|
|
|
if collector == nil {
|
|
s.mu.Lock()
|
|
if s.enabled && s.collector == nil && s.user != "" && s.keyPath != "" {
|
|
s.collector = NewTemperatureCollectorWithPort(s.user, s.keyPath, s.sshPort)
|
|
}
|
|
collector = s.collector
|
|
enabled = s.enabled
|
|
s.mu.Unlock()
|
|
|
|
if !enabled {
|
|
return nil, ErrTemperatureMonitoringDisabled
|
|
}
|
|
}
|
|
|
|
if collector == nil {
|
|
return nil, ErrTemperatureCollectorUnavailable
|
|
}
|
|
|
|
return collector.CollectTemperature(ctx, host, nodeName)
|
|
}
|