fix(cluster): support custom peer port, fix netmask & vrid persistence, and fix static call
This commit is contained in:
1 parent
da0805fd5f
commit
b76490a4dc
4 files changed
+94
-31
No files matched your search
+69
-28
@@ -38,6 +38,7 @@ class ClusterManager
|
||||
'virtual_netmask' => '24',
|
||||
'interface' => 'eth0',
|
||||
'peer_ip' => '',
|
||||
'peer_port' => 8443,
|
||||
'cluster_secret' => bin2hex(random_bytes(16)),
|
||||
'vrid' => 51,
|
||||
'priority' => 100,
|
||||
@@ -48,6 +49,9 @@ class ClusterManager
|
||||
'last_sync_message' => '',
|
||||
];
|
||||
}
|
||||
if (empty($row['peer_port'])) {
|
||||
$row['peer_port'] = 8443;
|
||||
}
|
||||
return $row;
|
||||
}
|
||||
|
||||
@@ -61,13 +65,35 @@ class ClusterManager
|
||||
$virtualIp = trim((string)($data['virtual_ip'] ?? ''));
|
||||
$virtualNetmask = preg_replace('/[^0-9]/', '', (string)($data['virtual_netmask'] ?? '24')) ?: '24';
|
||||
$interface = preg_replace('/[^a-zA-Z0-9_\-\.]/', '', trim((string)($data['interface'] ?? 'eth0'))) ?: 'eth0';
|
||||
$peerIp = trim((string)($data['peer_ip'] ?? ''));
|
||||
$peerIpRaw = trim((string)($data['peer_ip'] ?? ''));
|
||||
$peerPort = (int)($data['peer_port'] ?? 0);
|
||||
$clusterSecret = trim((string)($data['cluster_secret'] ?? ''));
|
||||
$vrid = max(1, min(255, (int)($data['vrid'] ?? 51)));
|
||||
$priority = max(1, min(254, (int)($data['priority'] ?? ($role === 'master' ? 100 : 90))));
|
||||
$syncInterval = max(5, min(3600, (int)($data['sync_interval'] ?? 15)));
|
||||
$autoSync = !empty($data['auto_sync']) ? 1 : 0;
|
||||
|
||||
// Détection et parsing si le port est saisi dans l'IP (ex: 10.10.11.197:2356)
|
||||
if (str_contains($peerIpRaw, ':')) {
|
||||
$parts = explode(':', $peerIpRaw, 2);
|
||||
$peerIp = trim($parts[0]);
|
||||
$parsedPort = (int)trim($parts[1]);
|
||||
if ($parsedPort > 0 && $parsedPort <= 65535) {
|
||||
$peerPort = $parsedPort;
|
||||
}
|
||||
} else {
|
||||
$peerIp = $peerIpRaw;
|
||||
}
|
||||
|
||||
if ($peerPort <= 0 || $peerPort > 65535) {
|
||||
try {
|
||||
$st = $this->db->query("SELECT admin_https_port FROM settings WHERE id = 1")->fetch(PDO::FETCH_ASSOC);
|
||||
$peerPort = (int)($st['admin_https_port'] ?? 8443);
|
||||
} catch (\Throwable $e) {
|
||||
$peerPort = 8443;
|
||||
}
|
||||
}
|
||||
|
||||
if ($clusterSecret === '') {
|
||||
$clusterSecret = bin2hex(random_bytes(16));
|
||||
}
|
||||
@@ -94,18 +120,19 @@ class ClusterManager
|
||||
|
||||
$stmt = $this->db->prepare('
|
||||
UPDATE cluster_settings SET
|
||||
enabled = :enabled,
|
||||
role = :role,
|
||||
virtual_ip = :vip,
|
||||
enabled = :enabled,
|
||||
role = :role,
|
||||
virtual_ip = :vip,
|
||||
virtual_netmask = :vmask,
|
||||
interface = :iface,
|
||||
peer_ip = :peer,
|
||||
cluster_secret = :secret,
|
||||
vrid = :vrid,
|
||||
priority = :prio,
|
||||
sync_interval = :sync_int,
|
||||
auto_sync = :auto_sync,
|
||||
updated_at = CURRENT_TIMESTAMP
|
||||
interface = :iface,
|
||||
peer_ip = :peer,
|
||||
peer_port = :peer_port,
|
||||
cluster_secret = :secret,
|
||||
vrid = :vrid,
|
||||
priority = :prio,
|
||||
sync_interval = :sync_int,
|
||||
auto_sync = :auto_sync,
|
||||
updated_at = CURRENT_TIMESTAMP
|
||||
WHERE id = 1
|
||||
');
|
||||
|
||||
@@ -116,6 +143,7 @@ class ClusterManager
|
||||
':vmask' => $virtualNetmask,
|
||||
':iface' => $interface,
|
||||
':peer' => $peerIp,
|
||||
':peer_port' => $peerPort,
|
||||
':secret' => $clusterSecret,
|
||||
':vrid' => $vrid,
|
||||
':prio' => $priority,
|
||||
@@ -253,6 +281,11 @@ class ClusterManager
|
||||
'configured_role' => $settings['role'],
|
||||
'effective_state' => $effectiveState,
|
||||
'virtual_ip' => $vip,
|
||||
'virtual_netmask' => $settings['virtual_netmask'] ?? '24',
|
||||
'vrid' => (int)($settings['vrid'] ?? 51),
|
||||
'priority' => (int)($settings['priority'] ?? 100),
|
||||
'peer_port' => (int)($settings['peer_port'] ?? 8443),
|
||||
'auto_sync' => (bool)($settings['auto_sync'] ?? 1),
|
||||
'virtual_ip_active' => $isVipActive,
|
||||
'interface' => $settings['interface'],
|
||||
'peer_ip' => $peerIp,
|
||||
@@ -402,22 +435,24 @@ class ClusterManager
|
||||
{
|
||||
$settings = $this->getSettings();
|
||||
$peerIp = trim((string)($settings['peer_ip'] ?? ''));
|
||||
$peerPort = (int)($settings['peer_port'] ?? 8443);
|
||||
if ($peerPort <= 0 || $peerPort > 65535) {
|
||||
$peerPort = 8443;
|
||||
}
|
||||
$secret = trim((string)($settings['cluster_secret'] ?? ''));
|
||||
|
||||
if ($peerIp === '') {
|
||||
throw new RuntimeException("L'adresse IP du Nœud pair (Peer IP) n'est pas configurée.");
|
||||
}
|
||||
|
||||
// Port d'administration HTTPS configuré
|
||||
$adminPort = 8443;
|
||||
// Port d'administration HTTPS local configuré pour éventuel fallback
|
||||
$localAdminPort = 8443;
|
||||
try {
|
||||
$st = $this->db->query("SELECT admin_https_port FROM settings WHERE id = 1")->fetch(PDO::FETCH_ASSOC);
|
||||
if (!empty($st['admin_https_port'])) {
|
||||
$adminPort = (int)$st['admin_https_port'];
|
||||
$localAdminPort = (int)$st['admin_https_port'];
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
$adminPort = 8443;
|
||||
}
|
||||
} catch (\Throwable $e) {}
|
||||
|
||||
// Création de l'archive de réplication
|
||||
$dbPath = Database::getDatabasePath();
|
||||
@@ -451,16 +486,19 @@ class ClusterManager
|
||||
$jsonPayload = json_encode($payload);
|
||||
$signature = hash_hmac('sha256', $jsonPayload, $secret);
|
||||
|
||||
// URLs d'accès candidates vers l'API du second nœud
|
||||
// URLs d'accès candidates vers l'API du second nœud (priorité au port configuré)
|
||||
$candidateUrls = [
|
||||
"https://{$peerIp}:{$adminPort}/api.php?action=cluster_receive_sync",
|
||||
"https://{$peerIp}:{$peerPort}/api.php?action=cluster_receive_sync",
|
||||
];
|
||||
if ($adminPort !== 443) {
|
||||
$candidateUrls[] = "https://{$peerIp}/api.php?action=cluster_receive_sync";
|
||||
if ($peerPort !== $localAdminPort) {
|
||||
$candidateUrls[] = "https://{$peerIp}:{$localAdminPort}/api.php?action=cluster_receive_sync";
|
||||
}
|
||||
if ($adminPort !== 8443) {
|
||||
if ($peerPort !== 8443 && $localAdminPort !== 8443) {
|
||||
$candidateUrls[] = "https://{$peerIp}:8443/api.php?action=cluster_receive_sync";
|
||||
}
|
||||
if ($peerPort !== 443 && $localAdminPort !== 443) {
|
||||
$candidateUrls[] = "https://{$peerIp}/api.php?action=cluster_receive_sync";
|
||||
}
|
||||
$candidateUrls[] = "http://{$peerIp}/api.php?action=cluster_receive_sync";
|
||||
$candidateUrls = array_values(array_unique($candidateUrls));
|
||||
|
||||
@@ -494,7 +532,9 @@ class ClusterManager
|
||||
}
|
||||
$lastError = "Rejet par le pair ({$targetUrl}) : " . ($resJson['message'] ?? $resJson['error'] ?? 'Erreur inconnue');
|
||||
} else {
|
||||
$lastError = "Échec d'envoi vers {$targetUrl} (HTTP {$httpCode})" . ($err ? " : {$err}" : "");
|
||||
$resJson = json_decode((string)$response, true);
|
||||
$detail = !empty($resJson['message']) ? " - " . $resJson['message'] : ($err ? " : {$err}" : "");
|
||||
$lastError = "Échec d'envoi vers {$targetUrl} (HTTP {$httpCode}){$detail}";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -503,11 +543,11 @@ class ClusterManager
|
||||
throw new RuntimeException($lastError);
|
||||
}
|
||||
|
||||
$this->updateSyncStatus('success', "Synchronisation réussie avec le nœud {$peerIp}");
|
||||
$this->updateSyncStatus('success', "Synchronisation réussie avec le nœud {$peerIp}:{$peerPort}");
|
||||
|
||||
return [
|
||||
'success' => true,
|
||||
'message' => "Réplication transmise et appliquée sur le nœud pair {$peerIp} avec succès.",
|
||||
'message' => "Réplication transmise et appliquée sur le nœud pair {$peerIp}:{$peerPort} avec succès.",
|
||||
];
|
||||
}
|
||||
|
||||
@@ -571,6 +611,7 @@ class ClusterManager
|
||||
role = :role,
|
||||
interface = :iface,
|
||||
peer_ip = :peer_ip,
|
||||
peer_port = :peer_port,
|
||||
priority = :priority,
|
||||
virtual_ip = :virtual_ip,
|
||||
virtual_netmask = :virtual_netmask,
|
||||
@@ -584,6 +625,7 @@ class ClusterManager
|
||||
':role' => $localClusterSettings['role'] ?? 'backup',
|
||||
':iface' => $localClusterSettings['interface'] ?? 'eth0',
|
||||
':peer_ip' => $localClusterSettings['peer_ip'] ?? '',
|
||||
':peer_port' => (int)($localClusterSettings['peer_port'] ?? 8443),
|
||||
':priority' => $localClusterSettings['priority'] ?? 90,
|
||||
':virtual_ip' => $localClusterSettings['virtual_ip'] ?? '',
|
||||
':virtual_netmask' => $localClusterSettings['virtual_netmask'] ?? '24',
|
||||
@@ -607,8 +649,7 @@ class ClusterManager
|
||||
}
|
||||
|
||||
// Régénérer les configurations PJSIP et Asterisk
|
||||
$generator = new ConfigGenerator($newDb);
|
||||
$generator->generateAndApply();
|
||||
ConfigGenerator::generateAndApply($newDb);
|
||||
|
||||
// Si le cluster est actif, actualiser le service Keepalived
|
||||
if (!empty($localClusterSettings['enabled'])) {
|
||||
|
||||
Reference in new issue
Block a user