mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-05-07 00:37:36 +00:00
143 lines
4.5 KiB
Go
143 lines
4.5 KiB
Go
package monitoring
|
|
|
|
import (
|
|
"net"
|
|
"net/url"
|
|
"strings"
|
|
|
|
"github.com/rcourtman/pulse-go-rewrite/internal/config"
|
|
"github.com/rs/zerolog/log"
|
|
)
|
|
|
|
func (m *Monitor) buildClusterEndpointsForInit(pve config.PVEInstance) ([]string, map[string]string) {
|
|
// For clusters, check if endpoints have IPs/resolvable hosts
|
|
// If not, use the main host for all connections (Proxmox will route cluster API calls)
|
|
hasValidEndpoints := false
|
|
endpoints := make([]string, 0, len(pve.ClusterEndpoints))
|
|
endpointFingerprints := make(map[string]string)
|
|
discoveryCfg := monitorDiscoveryConfig(m)
|
|
|
|
hasFingerprint := pve.Fingerprint != ""
|
|
for _, ep := range pve.ClusterEndpoints {
|
|
effectiveURL := clusterEndpointRuntimeURL(ep, pve.VerifySSL, hasFingerprint, discoveryCfg)
|
|
if effectiveURL == "" {
|
|
log.Warn().
|
|
Str("node", ep.NodeName).
|
|
Msg("Skipping cluster endpoint with no allowed host/IP")
|
|
continue
|
|
}
|
|
|
|
if parsed, err := url.Parse(effectiveURL); err == nil {
|
|
hostname := parsed.Hostname()
|
|
if hostname != "" && (strings.Contains(hostname, ".") || net.ParseIP(hostname) != nil) {
|
|
hasValidEndpoints = true
|
|
}
|
|
} else {
|
|
hostname := normalizeEndpointHost(effectiveURL)
|
|
if hostname != "" && (strings.Contains(hostname, ".") || net.ParseIP(hostname) != nil) {
|
|
hasValidEndpoints = true
|
|
}
|
|
}
|
|
|
|
endpoints = append(endpoints, effectiveURL)
|
|
// Store per-endpoint fingerprint for TOFU (Trust On First Use)
|
|
if ep.Fingerprint != "" {
|
|
endpointFingerprints[effectiveURL] = ep.Fingerprint
|
|
}
|
|
}
|
|
|
|
// If endpoints are just node names (not FQDNs or IPs), use main host only
|
|
// This is common when cluster nodes are discovered but not directly reachable
|
|
if !hasValidEndpoints || len(endpoints) == 0 {
|
|
log.Info().
|
|
Str("instance", pve.Name).
|
|
Str("mainHost", pve.Host).
|
|
Msg("Cluster endpoints are not resolvable, using main host for all cluster operations")
|
|
fallback := ensureClusterEndpointURL(pve.Host)
|
|
if fallback == "" {
|
|
fallback = ensureClusterEndpointURL(pve.Host)
|
|
}
|
|
endpoints = []string{fallback}
|
|
} else {
|
|
// Always include the main host URL as a fallback endpoint.
|
|
// This handles remote cluster scenarios where Proxmox reports internal IPs
|
|
// that aren't reachable from Pulse's network. The user-provided URL is
|
|
// reachable, so include it as a fallback for cluster API routing.
|
|
mainHostURL := ensureClusterEndpointURL(pve.Host)
|
|
mainHostAlreadyIncluded := false
|
|
for _, ep := range endpoints {
|
|
if ep == mainHostURL {
|
|
mainHostAlreadyIncluded = true
|
|
break
|
|
}
|
|
}
|
|
if !mainHostAlreadyIncluded && mainHostURL != "" {
|
|
log.Info().
|
|
Str("instance", pve.Name).
|
|
Str("mainHost", mainHostURL).
|
|
Int("clusterEndpoints", len(endpoints)).
|
|
Msg("Adding main host as fallback for remote cluster access")
|
|
endpoints = append(endpoints, mainHostURL)
|
|
}
|
|
}
|
|
|
|
return endpoints, endpointFingerprints
|
|
}
|
|
|
|
func (m *Monitor) buildClusterEndpointsForReconnect(pve config.PVEInstance) ([]string, map[string]string) {
|
|
hasValidEndpoints := false
|
|
endpoints := make([]string, 0, len(pve.ClusterEndpoints))
|
|
endpointFingerprints := make(map[string]string)
|
|
discoveryCfg := monitorDiscoveryConfig(m)
|
|
hasFingerprint := pve.Fingerprint != ""
|
|
|
|
for _, ep := range pve.ClusterEndpoints {
|
|
host := clusterEndpointRuntimeURL(ep, pve.VerifySSL, hasFingerprint, discoveryCfg)
|
|
if host == "" {
|
|
continue
|
|
}
|
|
|
|
if parsed, err := url.Parse(host); err == nil {
|
|
hostname := parsed.Hostname()
|
|
if hostname != "" && (strings.Contains(hostname, ".") || net.ParseIP(hostname) != nil) {
|
|
hasValidEndpoints = true
|
|
}
|
|
} else {
|
|
hostname := normalizeEndpointHost(host)
|
|
if hostname != "" && (strings.Contains(hostname, ".") || net.ParseIP(hostname) != nil) {
|
|
hasValidEndpoints = true
|
|
}
|
|
}
|
|
|
|
if !strings.HasPrefix(host, "http") {
|
|
host = ensureClusterEndpointURL(host)
|
|
}
|
|
endpoints = append(endpoints, host)
|
|
if ep.Fingerprint != "" {
|
|
endpointFingerprints[host] = ep.Fingerprint
|
|
}
|
|
}
|
|
|
|
if !hasValidEndpoints || len(endpoints) == 0 {
|
|
fallback := ensureClusterEndpointURL(pve.Host)
|
|
if fallback == "" {
|
|
fallback = ensureClusterEndpointURL(pve.Host)
|
|
}
|
|
endpoints = []string{fallback}
|
|
return endpoints, endpointFingerprints
|
|
}
|
|
|
|
mainHostURL := ensureClusterEndpointURL(pve.Host)
|
|
mainHostAlreadyIncluded := false
|
|
for _, ep := range endpoints {
|
|
if ep == mainHostURL {
|
|
mainHostAlreadyIncluded = true
|
|
break
|
|
}
|
|
}
|
|
if !mainHostAlreadyIncluded && mainHostURL != "" {
|
|
endpoints = append(endpoints, mainHostURL)
|
|
}
|
|
|
|
return endpoints, endpointFingerprints
|
|
}
|