Subversion Repositories ALCASAR

Rev

Rev 3321 | Details | Compare with Previous | Last modification | View Log

Rev Author Line No. Line
3294 rexy 1
<?php
2
 
3320 rexy 3
// written by Alexandre BOUIJOUX (mainly) & Rexy
3294 rexy 4
 
5
/*******************
6
 * READ CONF FILES *
7
 ******************/
8
define('CONF_FILE', '/usr/local/etc/alcasar.conf');
9
 
10
$conf_files = [CONF_FILE];
11
 
12
// Files reading test
13
foreach ($conf_files as $file) {
14
	if (!file_exists($file)) {
15
		exit("Requested file $file isn't present");
16
	}
17
 
18
	if (!is_readable($file)) {
19
		exit("Can't read the file $file");
20
	}
21
}
22
 
23
// Read ALCASAR CONF_FILE
24
$file_conf = fopen(CONF_FILE, 'r');
25
if (!$file_conf) {
26
	exit('Error opening the file '.CONF_FILE);
27
}
28
while (!feof($file_conf)) {
29
	$buffer = fgets($file_conf, 4096);
30
	if ((strpos($buffer, '=') !== false) && (substr($buffer, 0, 1) !== '#')) {
31
		$tmp = explode('=', $buffer, 2);
32
		$conf[trim($tmp[0])] = trim($tmp[1]);
33
	}
34
}
35
 
36
// Handle error messages
37
// Move errors messages from cookies to array.
38
$errors_msg = [];
39
$cookies_keys = [ "add_replica_error", "change_replicas_state_error", "add_ssh_key_error", "delete_ssh_key_error" ];
40
foreach ($cookies_keys as $key) {
41
	// Ignore if error didn't happened
42
	if (!array_key_exists($key, $_COOKIE)) {
43
		continue;
44
	}
45
 
46
	// Store message in errors messages array
47
	$errors_msg[$key] = $_COOKIE[$key];
48
 
49
	// Delete the cookie
50
	unset($_COOKIE[$key]);
51
	setcookie($key, false, 1);
52
}
53
 
54
// Choice of language
55
$Language = 'en';
56
if (isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) {
57
	$Langue	  = explode(',', $_SERVER['HTTP_ACCEPT_LANGUAGE']);
58
	$Language = strtolower(substr(chop($Langue[0]), 0, 2));
59
}
60
if ($Language === 'fr') {
61
	$l_action		= "Action";
62
	$l_add_to_list		= "Ajouter";
63
	$l_algorithm		= "Algorithme";
64
	$l_apply		= "Appliquer les changements";
65
	$l_bind_port		= "Port de liaison";
66
	$l_cant_read_pubkey	= "Impossible de lire la clé publique de 'root'.";
67
	$l_confirm_uninstall	= "Êtes-vous certain de vouloir désinstaller la fédération ?";
3309 rexy 68
	$l_db_pwd		= "Mot de passe d'accès à la base de données";
69
	$l_db_user		= "Utilisateur de la base de données";
3294 rexy 70
	$l_delete		= "Supprimer";
71
	$l_error_details	= "Détails des erreurs";
72
	$l_field		= "Champ";
73
	$l_go_network_conf_page	= "Allez sur la page de configuration réseau.";
74
	$l_host_name		= "Nom d'hôte";
3320 rexy 75
	$l_hosts_settings	= "Paramètres de réplication des hôtes distants";
3321 rexy 76
	$l_import_ssh_key	= "Importez ici les clés publiques des secondaires";
3322 rexy 77
	$l_in_progress		= "En cours ...";
3294 rexy 78
	$l_install_repl		= "Installer la fédération";
3322 rexy 79
	$l_install_repl_s	= "Installer la fédération";
3294 rexy 80
	$l_ip_address		= "Adresse IP";
3314 rexy 81
	$l_no_host_connected = "Aucun hote connecté";
3308 rexy 82
	$l_no_ssh_key		= "Aucune clé SSH importée.";
3322 rexy 83
	$l_not_connected	= "localhost";
84
	$l_pubkey_to_deploy	= "Copiez la clé publique ci-dessous dans un fichier pour l'importez dans le primaire.";
3294 rexy 85
	$l_remote_access_mgmt	= "Gestion des accès distants";
86
	$l_remote_role		= "Rôle de l'hôte distant";
3314 rexy 87
	$l_repl_io_running	= "État de la réplication";
88
	$l_started		= "Démarré";
89
	$l_stopped		= "Arrêté";
3322 rexy 90
	$l_remote_hosts		= "Hôtes distants";
3294 rexy 91
	$l_replication_install	= "Installer la Fédération";
92
	$l_replication_title	= "Fédération";
3320 rexy 93
	$l_role			= "Rôle";
3294 rexy 94
	$l_role_primary		= "Primaire";
95
	$l_role_secondary	= "Secondaire";
3306 rexy 96
	$l_ssh_keys_for_primary	= "Liste des secondaires autorisées à se connecter";
3294 rexy 97
	$l_ssh_port		= "Port SSH";
98
	$l_ssh_user		= "Utilisateur SSH";
3309 rexy 99
	$l_ssh_wan_enabled	= "Le service SSH sur le WAN est activé.";
100
	$l_ssh_wan_must_be_on	= "Le service SSH sur le WAN doit être activé.";
3294 rexy 101
	$l_start		= "Démarrer";
102
	$l_stop			= "Arrêter";
103
	$l_uninstall_repl	= "Désinstaller la fédération";
104
	$l_value		= "Valeur";
3314 rexy 105
	$l_want_server_as_prim	= "Voulez-vous que le serveur soit primaire ?";
3294 rexy 106
} else if ($Language === 'es') {
3309 rexy 107
	$l_action		= "Acción";
108
	$l_add_to_list		= "Añadir";
109
	$l_algorithm		= "Algoritmo";
110
	$l_apply		= "Aplicar los cambios";
111
	$l_bind_port		= "Puerto de conexión";
112
	$l_cant_read_pubkey	= "No se puede leer la clave pública de «root».";
3294 rexy 113
	$l_confirm_uninstall	= "¿Estás seguro de que quieres desinstalar la federación?";
3309 rexy 114
	$l_db_pwd		= "Contraseña de acceso a la base de datos";
115
	$l_db_user		= "Usuario de la base de datos";
116
	$l_delete		= "Eliminar";
117
	$l_error_details	= "Detalles de los errores";
118
	$l_field		= "campo";
119
	$l_go_network_conf_page	= "Vaya a la página de configuración de red";
120
	$l_host_name		= "Nombre de host";
3320 rexy 121
	$l_hosts_settings	= "Configuración de replicación de hosts remotos";
3321 rexy 122
	$l_import_ssh_key	= "Importe aquí las claves públicas de los servidores secundarios";
3322 rexy 123
	$l_in_progress		= "En curso ...";
3294 rexy 124
	$l_install_repl		= "Creación de la federación";
3320 rexy 125
	$l_remote_hosts		= "Hosts remotos";
3309 rexy 126
	$l_ip_address		= "dirección IP";
3314 rexy 127
	$l_no_host_connected = "No hay ningún host conectado.";
3309 rexy 128
	$l_no_ssh_key		= "No se ha importado ninguna clave SSH.";
3322 rexy 129
	$l_not_connected	= "localhost";
130
	$l_pubkey_to_deploy	= "Copie la clave pública que aparece a continuación en un archivo para importarla al primario.";
3309 rexy 131
	$l_remote_access_mgmt	= "Gestión de accesos remotos";
132
	$l_remote_role		= "Función del host remoto";
3314 rexy 133
	$l_repl_io_running	= "estado de replicación";
134
	$l_started		= "Iniciado";
135
	$l_stopped		= "Decreto";
3294 rexy 136
	$l_replication_install	= "Creación de la federación";
137
	$l_replication_title	= "Federación";
3320 rexy 138
	$l_role			= "Papel";
3309 rexy 139
	$l_role_primary		= "Primaria";
140
	$l_role_secondary	= "Secundaria";
141
	$l_ssh_keys_for_primary	= "Lista de claves autorizadas para conectarse al usuario local «replication».";
142
	$l_ssh_port		= "Puerto SSH";
143
	$l_ssh_user		= "Usuario SSH";
144
	$l_ssh_wan_enabled	= "El servicio SSH en la WAN está activado.";
145
	$l_ssh_wan_must_be_on	= "El servicio SSH en la WAN debe estar activado.";
146
	$l_start		= "Iniciar";
147
	$l_stop			= "Detener";
3294 rexy 148
	$l_uninstall_repl	= "Desinstalar la federación";
3309 rexy 149
	$l_value		= "Valor";
150
	$l_want_server_as_prim	= "¿Quiere que el servidor sea primario?";
3294 rexy 151
} else {
152
	$l_action		= "Action";
153
	$l_add_to_list		= "Add";
154
	$l_algorithm		= "Algorithm";
155
	$l_apply		= "Apply changes";
156
	$l_bind_port		= "Bind port";
157
	$l_cant_read_pubkey	= "Can't read root's public key.";
158
	$l_confirm_uninstall	= "Are you sure you want to uninstall the federation?";
3309 rexy 159
	$l_db_pwd		= "Database access password";
3294 rexy 160
	$l_db_user		= "Database user";
161
	$l_delete		= "Delete";
162
	$l_error_details	= "Error details";
163
	$l_field		= "Field";
164
	$l_go_network_conf_page	= "Go to network config page.";
165
	$l_host_name		= "Host name";
3320 rexy 166
	$l_hosts_settings	= "Remote replicated hosts settings";
3321 rexy 167
	$l_import_ssh_key	= "Import here the public keys of the secondary servers";
3322 rexy 168
	$l_in_progress		= "In progress...";
3294 rexy 169
	$l_install_repl		= "Setting up the federation";
3320 rexy 170
	$l_remote_hosts		= "Remote hosts";
3294 rexy 171
	$l_ip_address		= "IP address";
3314 rexy 172
	$l_no_host_connected = "No host connected";
3308 rexy 173
	$l_no_ssh_key		= "No SSH key imported.";
3322 rexy 174
	$l_not_connected	= "localhost";
175
	$l_pubkey_to_deploy	= "Copy the public key below into a file to import it into the primary.";
3294 rexy 176
	$l_remote_access_mgmt	= "Remote access management";
177
	$l_remote_role		= "Remote role";
3314 rexy 178
	$l_repl_io_running	= "Replication state";
179
	$l_started		= "Started";
180
	$l_stopped		= "Stopped";
3294 rexy 181
	$l_replication_install	= "Setting up the federation";
182
	$l_replication_title	= "Federation";
3320 rexy 183
	$l_role			= "Role";
3294 rexy 184
	$l_role_primary		= "Primary";
185
	$l_role_secondary	= "Secondary";
186
	$l_ssh_keys_for_primary	= "List of keys allowed to connect to local 'replication' user.";
187
	$l_ssh_port		= "SSH port";
188
	$l_ssh_user		= "SSH user";
3309 rexy 189
	$l_ssh_wan_enabled	= "SSH service on WAN is enabled.";
190
	$l_ssh_wan_must_be_on	= "SSH service on WAN must be enabled.";
3294 rexy 191
	$l_start		= "Start";
192
	$l_stop			= "Stop";
193
	$l_uninstall_repl	= "Uninstall the federation";
194
	$l_value		= "Value";
195
	$l_want_server_as_prim	= "Want server to be a primary?";
196
}
197
 
198
$reg_ip      = '^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$';
199
$reg_ip_port = '^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\:([1-9]|[1-9][0-9]|[1-9][0-9]{2}|[1-9][0-9]{3}|[1-5][0-9]{4}|6[0-4][0-9]{3}|65[0-4][0-9]{2}|655[0-2][0-9]|6553[0-5]))$';
3322 rexy 200
$reg_host    = '^[a-zA-Z0-9-_.]+$';
3294 rexy 201
$reg_ssh_key = "^(ssh-dss AAAAB3NzaC1kc3|ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNT|sk-ecdsa-sha2-nistp256@openssh.com AAAAInNrLWVjZHNhLXNoYTItbmlzdHAyNTZAb3BlbnNzaC5jb2|ssh-ed25519 AAAAC3NzaC1lZDI1NTE5|sk-ssh-ed25519@openssh.com AAAAGnNrLXNzaC1lZDI1NTE5QG9wZW5zc2guY29t|ssh-rsa AAAAB3NzaC1yc2)[0-9A-Za-z+/]+[=]{0,3}(\s.*)?$";
202
$reg_linux_user = "[a-z_][a-z0-9_-]*[$]?";
203
$reg_mariadb_user = "^[a-z]{1,32}$";
204
 
205
// Allow new SSH file size of 128kB;
206
$max_ssh_file_size = 131072;
207
 
208
$choice = $_POST['choice'] ?? "";
209
switch ($choice) {
3322 rexy 210
	case 'install_replication_p':
211
		if (isset($conf['REPLICATION']) && ($conf['REPLICATION'] == "primary" || $conf['REPLICATION'] == "secondary"))  {
3294 rexy 212
			exit("Replication already installed.");}
213
		$stdout = [];
3322 rexy 214
		exec('sudo /usr/local/bin/alcasar-replication-install.sh -p 2>&1', $stdout);
3294 rexy 215
		header('Location: '.$_SERVER['PHP_SELF']);
216
		break;
3322 rexy 217
	case 'install_replication_s':
218
		if (isset($conf['REPLICATION']) && ($conf['REPLICATION'] == "primary" || $conf['REPLICATION'] == "secondary"))  {
219
			exit("Replication already installed.");}
220
		$stdout = [];
221
		exec('sudo /usr/local/bin/alcasar-replication-install.sh -s 2>&1', $stdout);
222
		header('Location: '.$_SERVER['PHP_SELF']);
223
		break;
3294 rexy 224
	case 'uninstall_replication':
225
		if (!isset($conf['REPLICATION']) || $conf['REPLICATION'] == "off") {
226
			exit("Replication not installed.");}
227
		$stdout = [];
228
		exec('sudo /usr/local/bin/alcasar-replication-uninstall.sh 2>&1', $stdout);
229
		header('Location: '.$_SERVER['PHP_SELF']);
230
		break;
231
	case 'add_replica':
232
		$role = trim($_POST['role'] ?? "");
233
		$name = trim($_POST['name'] ?? "");
234
		$ip = trim($_POST['ip'] ?? "");
235
		$port = trim($_POST['port'] ?? "");
3320 rexy 236
		// we fix ssh_user, db_user to simplify ACC
3308 rexy 237
		// $user = trim($_POST['user'] ?? "");
3320 rexy 238
		// $db_user = trim($_POST['db_user'] ?? "");
3308 rexy 239
		$user = "replication" ;
240
		$db_user = "db_replication";
3320 rexy 241
		// we retrieve db_pwd via SSH to simplify ACC
242
		//$db_pwd = trim($_POST['db_pwd'] ?? "");
243
		$db_pwd = "no more used : set via ssh";
3294 rexy 244
		$bind_port = trim($_POST['bind_port'] ?? "");
245
		$stdout = [];
246
		$return = 0;
247
		switch ($role) {
248
			case 'primary':
249
				exec("sudo /usr/local/bin/alcasar-replication-add.sh --to-primary"." --name=".escapeshellarg($name)." --address=".escapeshellarg($ip)." --port=".escapeshellarg($port)." --user=". escapeshellarg($user)." --db-user=".escapeshellarg($db_user)." --db-password=".escapeshellarg($db_pwd)." 2>&1", $stdout, $return);
250
				break;
251
			case 'secondary':
252
				exec("sudo /usr/local/bin/alcasar-replication-add.sh --to-secondary"." --name=".escapeshellarg($name)." --bind-port=".escapeshellarg($bind_port)." --db-user=".escapeshellarg($db_user)." --db-password=".escapeshellarg($db_pwd)." 2>&1", $stdout, $return);
253
				break;
254
			default:
255
				// Error
256
				exit();}
257
		// If script went wrong
258
		if ($return) {
259
			$key = $choice . "_error";
260
			// Concatenate stdout lines
261
			$value = implode(PHP_EOL, $stdout);
262
			// Save error message in cookies
263
			setcookie($key, $value);
264
		}
265
		header('Location: '.$_SERVER['PHP_SELF']);
266
		break;
267
	case 'change_replicas_state':
268
		$stdout = [];
269
		$return = 0;
270
		$key_prefix = "action_primary_";
271
		// Search for action_primary_<hostname> key
272
		foreach ($_POST as $key => $value) {
273
			if (!str_starts_with($key, $key_prefix)) {
274
				continue;}
275
			// Get the remote name
276
			$name = explode($key_prefix, $key)[1];
277
			switch ($value) {
278
				case 'start':
279
					exec("sudo /usr/local/bin/alcasar-replication-start.sh --name=".escapeshellarg($name)." 2>&1", $stdout, $return);
280
					break;
281
				case 'stop':
282
					exec("sudo /usr/local/bin/alcasar-replication-stop.sh --name=".escapeshellarg($name)." 2>&1", $stdout, $return);
283
					break;
284
				case 'delete':
285
					exec("sudo /usr/local/bin/alcasar-replication-delete.sh --name=".escapeshellarg($name)." 2>&1", $stdout, $return);
286
					break;
287
				default:
288
					break;
289
			}
290
		}
291
		// If script went wrong
292
		if ($return) {
293
			$key = $choice . "_error";
294
			// Concatenate stdout lines
295
			$value = implode(PHP_EOL, $stdout);
296
			// Save error message in cookies
297
			setcookie($key, $value);
298
		}
299
		header('Location: '.$_SERVER['PHP_SELF']);
300
		break;
301
	case 'add_ssh_key':
302
		$file = $_FILES['new_ssh_key_input'] ?? "";
303
		$stdout = [];
304
		$return = 0;
305
		// Stop if file doesn't exist
306
		if (empty($file)) {
307
			break;}
308
		// Check file size
309
		if ($file['size'] > $max_ssh_file_size) {
310
			break;}
311
		// Add new key(s) to authorized keys list
312
		$tmp_file = $file['tmp_name'];
313
		exec("sudo /usr/local/bin/alcasar-replication-ssh-keys-management.sh --add --file=$tmp_file 2>&1", $stdout, $return);
314
		// If script went wrong
315
		if ($return) {
316
			$key = $choice . "_error";
317
			// Concatenate stdout lines
318
			$value = implode(PHP_EOL, $stdout);
319
			// Save error message in cookies
320
			setcookie($key, $value);
321
		}
322
		header('Location: '.$_SERVER['PHP_SELF']);
323
		break;
324
	case 'delete_ssh_key':
325
		$stdout = [];
326
		$return = 0;
327
		$key_prefix = "action_ssh_key_";
328
		foreach ($_POST as $key => $value) {
329
			if (!str_starts_with($key, $key_prefix)) {
330
				continue;}
331
			$decoded_value = htmlspecialchars_decode($value);
332
			// Delete key
333
			exec("sudo /usr/local/bin/alcasar-replication-ssh-keys-management.sh --delete --regex=$decoded_value 2>&1", $stdout, $return);
334
			// If script went wrong
335
			if ($return) {
336
				$key = $choice . "_error";
337
				// Concatenate stdout lines
338
				$value = implode(PHP_EOL, $stdout);
339
				// Save error message in cookies
340
				setcookie($key, $value);
341
			}
342
		}
343
		header('Location: '.$_SERVER['PHP_SELF']);
344
		break;
345
	default:
346
		break;
347
}
348
 
349
?>
350
<!DOCTYPE HTML>
351
<html>
352
<head>
353
	<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
354
	<title><?= $l_replication_title ?></title>
355
	<link rel="stylesheet" href="/css/acc.css" type="text/css">
356
	<script src="/js/jquery.min.js"></script>
357
	<script src="/js/jquery.connections.js"></script>
358
	<script type="text/javascript">
3320 rexy 359
		// listener to enable submitbutton only when forms are completed
360
		document.addEventListener('DOMContentLoaded', function() {
361
			const rolePrimaryRadio = document.getElementById('role_primary');
362
			const roleSecondaryRadio = document.getElementById('role_secondary');
363
			const nameInput = document.getElementById('input_name');
364
			const ipInput = document.getElementById('input_ip');
365
			const bindPortInput = document.getElementById('input_bind_port');
366
			const portInput = document.getElementById('input_port');
367
			const submitButton = document.getElementById('apply_add_remote');
368
			// madatory fields in relation to role
369
			function checkRequiredFields() {
370
				let allFilled = false;
371
				if (rolePrimaryRadio.checked) {
372
			// primary : name, ip, port
373
				allFilled = nameInput.value.trim() !== '' &&
374
					ipInput.value.trim() !== '' &&
375
					portInput.value.trim() !== '';
376
				} else if (roleSecondaryRadio.checked) {
377
			// secondary : name, bind_port
378
				allFilled = nameInput.value.trim() !== '' &&
379
				bindPortInput.value.trim() !== '';
380
				}
381
			submitButton.disabled = !allFilled;
382
			}
383
			// Events listening
384
			nameInput.addEventListener('input', checkRequiredFields);
385
			ipInput.addEventListener('input', checkRequiredFields);
386
			bindPortInput.addEventListener('input', checkRequiredFields);
387
			portInput.addEventListener('input', checkRequiredFields);
388
			// disable on load
389
			submitButton.disabled = true;
390
		});
3294 rexy 391
		window.onload = main;
392
		function main() {
3322 rexy 393
			const rolePrimaryRadio = document.getElementById('role_primary');
394
			const roleSecondaryRadio = document.getElementById('role_secondary');
395
			if (roleSecondaryRadio.checked) { show_fields_for_new_secondary(); }
396
			if (rolePrimaryRadio.checked) { show_fields_for_new_primary(); }
3294 rexy 397
			set_required_on_common_fields();
3320 rexy 398
			enable_apply_btn_if_selected_remote_action();
3294 rexy 399
			enable_apply_btn_if_selected_ssh_key_action();
400
		}
401
		// Set 'required' attribute on fields needed by both primary and secondary
402
		function set_required_on_common_fields() {
403
			document.querySelectorAll(".role_primary.role_secondary").forEach((input) => {
404
				input.setAttribute("required", "");
405
			});
406
		}
407
		// Only enable fields needed for new primary remote
408
		function show_fields_for_new_primary() {
409
			// Toggle 'disabled' and 'required' attributes
410
			document.querySelectorAll("input[class='role_primary']").forEach((input) => {
411
				input.removeAttribute("disabled");
412
				input.setAttribute("required", "");
413
			});
414
			document.querySelectorAll("input[class='role_secondary']").forEach((input) => {
415
				input.setAttribute("disabled", "");
416
				input.removeAttribute("required");
417
			});
418
		}
419
		function show_fields_for_new_secondary() {
420
			// Toggle 'disabled' and 'required' attributes
421
			document.querySelectorAll("input[class='role_primary']").forEach((input) => {
422
				input.removeAttribute("required");
423
				input.setAttribute("disabled", "");
424
			});
425
			document.querySelectorAll("input[class='role_secondary']").forEach((input) => {
426
				input.setAttribute("required", "");
427
				input.removeAttribute("disabled");
428
			});
429
		}
430
		// Enable the remote's list Apply button if there are any pending actions
3320 rexy 431
		function enable_apply_btn_if_selected_remote_action() {
432
			let btn = document.querySelector("#apply_changes_remote_btn");
3294 rexy 433
			if (!btn) {
434
				return;}
435
			let change_to_apply = false;
436
			// Check for any pending change
437
			document.querySelectorAll(".primary_action_select").forEach((element) => {
438
				if (element.value != "") {
439
					btn.removeAttribute("disabled");
440
					change_to_apply = true;
441
				}
442
			});
443
			// Disable button if there are no pending changes
444
			if (!change_to_apply) {
445
				btn.setAttribute("disabled", "");
446
			}
447
		}
448
		// Enable the SSH keys's list Apply button if there are any pending actions
449
		function enable_apply_btn_if_selected_ssh_key_action() {
450
			let btn = document.querySelector("#apply_changes_ssh_key_btn");
451
			if (!btn) {
452
				return;
453
			}
454
			let change_to_apply = false;
455
			// Check for any pending change
456
			document.querySelectorAll(".ssh_key_action_input").forEach((element) => {
457
				if (element.checked) {
458
					btn.removeAttribute("disabled");
459
					change_to_apply = true;
460
				}
461
			});
462
			// Disable button if there are no pending changes
463
			if (!change_to_apply) {
464
				btn.setAttribute("disabled", "");
465
			}
466
		}
467
	</script>
468
</head>
469
<body>
470
<div id="ldoverlay" class="overlay">
471
	<div class="lds-spinner" id="spinner"><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div></div>
472
</div>
3322 rexy 473
<?php if ($conf['REPLICATION'] == "primary" || $conf['REPLICATION'] == "secondary") { ?>
3294 rexy 474
<div class="panel">
475
	<div class="panel-header"><?= $l_hosts_settings ?></div>
476
</div>
477
<div>
478
<table width="100%" cellspacing="0" cellpadding="5" border="1">
479
	<tr>
480
		<td width="50%" align="center">
481
			<?php $section = "change_replicas_state" ?>
482
			<form action="<?= htmlspecialchars($_SERVER['PHP_SELF']) ?>" method="POST">
483
			<input type="hidden" name="choice" value="<?= $section ?>">
3320 rexy 484
			<center><?= $l_remote_hosts ?></center>
3294 rexy 485
			<table cellspacing="2" cellpadding="3" border="1" style="table-layout: auto; min-width: 10em;">
486
				<tr>
487
					<th><?= $l_ip_address ?></th>
488
					<th><?= $l_host_name ?></th>
3320 rexy 489
					<th><?= $l_role ?></th>
3294 rexy 490
					<th><?= $l_repl_io_running ?></th>
491
					<th><?= $l_bind_port ?></th>
492
					<th><?= $l_action ?></th>
493
				</tr>
494
				<?php
495
				$stdout = [];
496
				$return = 0;
497
				exec("sudo /usr/local/bin/alcasar-replication-list.sh --all 2>&1", $stdout, $return);
498
				// If script went wrong
499
				if ($return) {
500
					// Print error message
501
					$errors_msg[$section."_error"] = implode(PHP_EOL, $stdout);
502
				// Successfully fetched remotes stats
503
				} else {
504
					$connected_prims = [];
505
					$current_prim = "";
506
					// Parse stdout in keys-array
507
					foreach ($stdout as $row) {
508
						// Skip useless delimiter
509
						if (str_starts_with($row, '*')) {
510
							continue;
511
						}
512
						// Split key: value
513
						$exploded = explode(": ", $row);
514
						$key = $exploded[0];
515
						$value = $exploded[1] ?? "";
516
						// Create subarray when starting to display a new remote
517
						if (!strcmp($key, "Connection_name")) {
518
							$current_prim = $value;
519
							$connected_prims[$current_prim] = [];
520
						}
521
						// Put value in prim's subarray
522
						($connected_prims[$current_prim])[$key] = $value;
523
					}
524
					// Skip resetted replicas,
525
					// they will stay displayed still the next database restart.
526
					foreach ($connected_prims as $prim) {
527
						if (empty($prim["Relay_Log_File"])) {
528
							unset($connected_prims[$prim["Connection_name"]]);
529
						}
530
					}
531
					// List each connection
532
					foreach ($connected_prims as $prim) {
533
						?>
534
						<tr>
3322 rexy 535
							<td><?php 
3294 rexy 536
								$master_host = $prim["Master_Host"];
3322 rexy 537
								if ($master_host = "127.0.0.1") {
3294 rexy 538
									echo "$master_host";
539
								} else {
540
									echo "$l_not_connected";
541
								}
542
							?></td>
543
							<td><?= $prim["Connection_name"] ?></td>
3320 rexy 544
							<td><?php
545
								if ($conf['REPLICATION_TO'] == "") { echo "$l_role_secondary"; }
546
									else { echo "$l_role_primary"; }
547
								?></td>
3313 rexy 548
							<td>
3314 rexy 549
							<? if ($prim["Slave_IO_Running"] == "Yes") { echo "$l_started"; }
550
							   if ($prim["Slave_IO_Running"] == "No") { echo "$l_stopped"; }
551
							   if ($prim["Slave_IO_Running"] == "Connecting") { echo "$l_in_progress"; }
3313 rexy 552
							?>
553
							</td>
3294 rexy 554
							<td><?= $prim["Master_Port"] ?></td>
555
							<td>
3320 rexy 556
								<select name="action_primary_<?= $prim["Connection_name"] ?>" class="primary_action_select" onchange="enable_apply_btn_if_selected_remote_action()">
3294 rexy 557
									<option value=""></option>
558
									<?php
559
										// Actions available on all remotes
560
										$options = array(
561
											"start" => "$l_start",
562
											"stop" => "$l_stop",
563
											"delete" => "$l_delete"
564
										);
565
										// Remove some options depending on the current remote state
566
										switch ($prim["Slave_IO_Running"]) {
567
										case 'Yes':
568
										case 'Connecting':
569
											unset($options["start"]);
570
											unset($options["delete"]);
571
											break;
572
										case 'No':
573
											unset($options["stop"]);
574
											break;
575
										default:
576
											break;
577
										}
578
										// Print options
579
										foreach ($options as $key => $value) { ?>
580
											<option value="<?= $key ?>"><?= $value ?></option>
581
										<?php }
582
									 ?>
583
								</select>
584
							</td>
585
						</tr>
586
					<?php }
587
					// Show submit button if there are primary servers connected
3320 rexy 588
					echo "<tr><td colspan=6 valign='middle' align='center'>";
3294 rexy 589
					if (sizeof($connected_prims)) { ?>
3320 rexy 590
						<input type="submit" id="apply_changes_remote_btn" value="<?= $l_apply ?>" onClick="document.getElementById('ldoverlay').style.display='block';">
3294 rexy 591
					<?php } else { ?>
3314 rexy 592
						<p><?= $l_no_host_connected ?></p>
3294 rexy 593
					<?php }
594
					echo "</td></tr>";
595
				} ?>
596
			</table>
597
			</form>
598
			<?php if (isset($errors_msg[$section."_error"])) { ?>
599
				<details open>
600
					<summary><?= $l_error_details ?></summary>
601
					<textarea readonly cols=50 rows=10><?= $errors_msg[$section."_error"] ?></textarea>
602
				</details>
603
			<?php } ?>
604
		</td>
3322 rexy 605
		<?php if (isset($conf['REPLICATION']) && ($conf['REPLICATION'] == "secondary")) { ?>
3294 rexy 606
		<td width="50%" valign="middle" align="center">
607
			<?php $section = "add_replica" ?>
3320 rexy 608
			<form id="form_add_remote" action="<?= htmlspecialchars($_SERVER['PHP_SELF']) ?>" method="POST">
3294 rexy 609
			<input type="hidden" name="choice" value="<?= $section ?>">
610
				<table cellspacing="2" cellpadding="3" border="1">
611
					<tr>
612
						<th><?= $l_field ?></th>
613
						<th><?= $l_value ?></th>
614
					</tr>
615
					<tr>
616
						<td><?= $l_remote_role ?></td>
617
						<td>
618
							<fieldset>
619
								<div>
3322 rexy 620
									<input type="radio" id="role_primary" name="role" value="primary"
621
									<?= (isset($conf['REPLICATION']) && $conf['REPLICATION'] == "secondary") ? 'checked' : '' ?>
622
									onClick="show_fields_for_new_primary()"/>
3294 rexy 623
									<label for="role_primary"><?= $l_role_primary ?></label>
3322 rexy 624
									<input type="radio" id="role_secondary" name="role" value="secondary"
625
									<?= (isset($conf['REPLICATION']) && $conf['REPLICATION'] == "primary") ? 'checked' : '' ?>
626
									onClick="show_fields_for_new_secondary()"/>
3294 rexy 627
									<label for="role_secondary"><?= $l_role_secondary ?></label>
628
								</div>
629
							</fieldset>
630
						</td>
631
					</tr>
632
					<tr>
633
						<td><label for="input_name"><?= $l_host_name ?></label></td>
634
						<td><input type="text" id="input_name" name="name" class="role_primary role_secondary" pattern="<?= $reg_host ?>"></td>
635
					</tr>
636
					<tr>
637
						<td><label for="input_ip"><?= $l_ip_address ?></label></td>
638
						<td><input type="text" id="input_ip" name="ip" class="role_primary" pattern="<?= $reg_ip ?>"></td>
639
					</tr>
640
					<tr>
641
						<td><label for="input_bind_port"><?= $l_bind_port ?></label></td>
642
						<td><input type="number" id="input_bind_port" name="bind_port" min="0" max="65535" class="role_secondary" pattern="<?= $reg_ip_port ?>"></td>
643
					</tr>
644
					<tr>
645
						<td><label for="input_port"><?= $l_ssh_port ?></label></td>
3313 rexy 646
						<td><input type="number" id="input_port" name="port" min="0" max="65535" class="role_primary" pattern="<?= $reg_ip_port ?>"></td>
3294 rexy 647
					</tr>
3320 rexy 648
<!--					<tr>
649
						<td><label for="input_db_user"><?= $l_db_user ?></label></td>
650
						<td><input type="text" id="input_db_user" name="db_user" class="role_primary role_secondary" pattern="<?= $reg_mariadb_user ?>"></td>
651
					</tr>
3294 rexy 652
					<tr>
3308 rexy 653
					<td><label for="input_db_pwd"><?= $l_db_pwd ?></label></td>
3294 rexy 654
						<td><input type="password" id="input_db_pwd" name="db_pwd" class="role_primary role_secondary"></td>
3320 rexy 655
					</tr> -->
3294 rexy 656
					<tr>
657
						<td colspan=2 valign="middle" align="center">
3320 rexy 658
							<input type="submit" id="apply_add_remote" class="button" value="<?= $l_add_to_list ?>" onClick="document.getElementById('ldoverlay').style.display='block';">
3294 rexy 659
						</td>
660
					</tr>
661
				</table>
662
			</form>
663
			<?php if (isset($errors_msg[$section."_error"])) { ?>
664
				<details open>
665
					<summary><?= $l_error_details ?></summary>
666
					<textarea readonly cols=50 rows=10><?= htmlspecialchars($errors_msg[$section."_error"]) ?></textarea>
667
				</details>
668
			<?php } ?>
669
		</td>
3322 rexy 670
		<?php } ?>
3294 rexy 671
	</tr>
672
</table>
673
</div>
674
<br>
675
<div class="panel">
676
	<div class="panel-header"><?= $l_remote_access_mgmt ?></div>
677
</div>
678
<div>
679
<table width="100%" cellspacing="0" cellpadding="5" border="1">
680
	<tr>
3322 rexy 681
		<?php if (isset($conf['REPLICATION']) && ($conf['REPLICATION'] == "secondary")) { ?>
682
			<td width="100%" valign="middle" align="center">
683
				<center><?= $l_pubkey_to_deploy ?><br></center>
684
				<br>
685
				<?php
686
				$stdout = [];
687
				$return = 0;
688
				exec("sudo /usr/local/bin/alcasar-replication-ssh-keys-management.sh --show-pubkey 2>&1", $stdout, $return);
689
				// If script went wrong
690
				if ($return != 0) {
691
					echo "<p>$l_cant_read_pubkey</p>";
692
				} else { 
693
					 $pubkey = htmlspecialchars(implode(PHP_EOL, $stdout), ENT_QUOTES, 'UTF-8'); ?>
694
				<textarea id="pubkey_stdout" readonly style="width: 75%; min-height: 100px; resize: vertical; white-space: pre-wrap; font-family: monospace;"><?= $pubkey ?></textarea>
695
				<?php }
696
			} ?>
697
		<?php if (isset($conf['REPLICATION']) && ($conf['REPLICATION'] == "primary")) { ?>
698
			<td width="50%" align="center">
3321 rexy 699
			<center><?= $l_ssh_keys_for_primary ?></center>
3294 rexy 700
			<?php $section = "delete_ssh_key" ?>
701
			<form action="<?= htmlspecialchars($_SERVER['PHP_SELF']) ?>" method="POST">
702
			<input type="hidden" name="choice" value="<?= $section ?>">
703
			<table cellspacing="2" cellpadding="3" border="1" style="table-layout: auto; min-width: 10em;">
704
				<tr>
705
					<th><?= $l_host_name ?></th>
706
					<th><?= $l_algorithm ?></th>
707
					<th><?= $l_delete ?></th>
708
				</tr>
709
				<?php
710
				$stdout = [];
711
				$return = 0;
3321 rexy 712
				$public_key_exist=False;
3294 rexy 713
				exec("sudo /usr/local/bin/alcasar-replication-ssh-keys-management.sh --list 2>&1", $stdout, $return);
714
				// If script went wrong
715
				if ($return) {
716
					// Print error message
717
					$errors_msg[$section."_error"] = implode(PHP_EOL, $stdout);
718
				// Successfully fetched remotes stats
719
				} else {
720
					// List each key
721
					foreach ($stdout as $line) {
722
						// Skip empty lines
723
						if (str_starts_with($line, ' ')) {
724
							continue;
725
						}
726
						// Split args
3321 rexy 727
						$public_key_exist=True;
3294 rexy 728
						$exploded = explode(' ', $line);
729
						$algo = $exploded[0] ?? "";
3319 rexy 730
						$full_hostname = explode('@', $exploded[2] ?? "");
731
						$hostname = $full_hostname[1];
3294 rexy 732
						?>
733
						<tr>
734
							<td><?= $hostname ?></td>
735
							<td><?= $algo ?></td>
736
							<td>
737
								<input type="checkbox" name="action_ssh_key_<?= htmlspecialchars($hostname) ?>" value="<?= htmlspecialchars($hostname) ?>" class="ssh_key_action_input" onchange="enable_apply_btn_if_selected_ssh_key_action()">
738
							</td>
739
						</tr>
740
					<?php }
741
					// Show submit button if there are primary servers connected
3308 rexy 742
					echo "<tr><td colspan=3 valign='middle' align='center'>";
3294 rexy 743
					if (sizeof($stdout)) { ?>
744
						<input type="submit" id="apply_changes_ssh_key_btn" value="<?= $l_apply ?>" onClick="document.getElementById('ldoverlay').style.display='block';">
745
					<?php } else { ?>
746
						<p><?= $l_no_ssh_key ?></p>
747
					<?php }
3308 rexy 748
					echo "</td></tr>";
3294 rexy 749
				} ?>
750
			</table>
751
			</form>
752
			<?php if (isset($errors_msg[$section."_error"])) { ?>
753
				<details open>
754
					<summary><?= $l_error_details ?></summary>
755
					<textarea readonly cols=50 rows=10><?= $errors_msg[$section."_error"] ?></textarea>
756
				</details>
757
			<?php } ?>
758
		</td>
3321 rexy 759
		<td width="<?php if ($public_key_exist) { echo "50"; } else { echo "25";} ?>%" valign="middle" align="center">
3294 rexy 760
			<?php $section = "add_ssh_key" ?>
761
			<form action="<?= htmlspecialchars($_SERVER['PHP_SELF']) ?>" method="POST" enctype="multipart/form-data">
762
			<input type="hidden" name="choice" value="<?= $section ?>">
763
				<input type="hidden" name="MAX_FILE_SIZE" value="<?= $max_ssh_file_size ?>" />
3321 rexy 764
				<center><?= $l_import_ssh_key ?><br></center>
3294 rexy 765
				<br>
766
				<input type="file" name="new_ssh_key_input" id="new_ssh_key_input" accept=".pub">
767
				<br>
768
				<input type="submit" class="button" value="<?= $l_add_to_list ?>" onClick="document.getElementById('ldoverlay').style.display='block';">
769
			</form>
770
			<?php if (isset($errors_msg[$section."_error"])) { ?>
771
				<details open>
772
					<summary><?= $l_error_details ?></summary>
773
					<textarea readonly cols=50 rows=10><?= $errors_msg[$section."_error"] ?></textarea>
774
				</details>
775
			<?php } ?>
776
		</td>
3322 rexy 777
		<?php } ?>
3294 rexy 778
	</tr>
779
</table>
780
</div>
781
<br>
782
<?php } ?>
783
<div class="panel">
784
	<div class="panel-header"><?= $l_replication_title ?></div>
785
</div>
786
<table width="100%" cellspacing="0" cellpadding="5" border="1">
787
	<tr>
3322 rexy 788
		<?php if (isset($conf['REPLICATION']) && ($conf['REPLICATION'] == "primary" || $conf['REPLICATION'] == "secondary")) { ?>
789
			<td width="50%" valign="middle" align="center">
3294 rexy 790
				<form action="<?= htmlspecialchars($_SERVER['PHP_SELF']) ?>" method="POST" onsubmit="return confirm('<?= $l_confirm_uninstall ?>');">
791
					<input type="hidden" name="choice" value="uninstall_replication">
792
					<input type="submit" value="<?= $l_uninstall_repl ?>" onClick="document.getElementById('ldoverlay').style.display='block';">
793
				</form>
3322 rexy 794
			</td>
3294 rexy 795
			<?php } else { ?>
3322 rexy 796
			<td width="50%" valign="middle" align="center">
3294 rexy 797
				<form action="<?= htmlspecialchars($_SERVER['PHP_SELF']) ?>" method="POST">
3322 rexy 798
					<input type="hidden" name="choice" value="install_replication_p">
799
					<input type="submit" value="<?= $l_install_repl." (".$l_role."=".$l_role_primary.")" ?>" onClick="document.getElementById('ldoverlay').style.display='block';">
3294 rexy 800
				</form>
3322 rexy 801
			</td><td width="50%" valign="middle" align="center">
802
				<form action="<?= htmlspecialchars($_SERVER['PHP_SELF']) ?>" method="POST">
803
					<input type="hidden" name="choice" value="install_replication_s">
804
					<input type="submit" value="<?= $l_install_repl." (".$l_role."=".$l_role_secondary.")" ?>" onClick="document.getElementById('ldoverlay').style.display='block';">
805
				</form>
806
			</td>
3294 rexy 807
			<?php } ?>
3322 rexy 808
		<?php if (isset($conf['REPLICATION']) && $conf['REPLICATION'] == "primary") { ?>
3294 rexy 809
			<td width="50%" valign="middle" align="center">
810
				<?php if ($conf['SSH_WAN'] !== '0') { ?>
811
					<input type="checkbox" id="togglessh" checked disabled>
812
					<label for="togglessh"><?= $l_ssh_wan_enabled ?></label>
813
				<?php } else { ?>
814
				<p><?= $l_want_server_as_prim ?></p>
815
					<input type="checkbox" id="togglessh" disabled>
816
					<label for="togglessh"><b><?= $l_ssh_wan_must_be_on ?></b> <a href="/acc/admin/network.php"><?= $l_go_network_conf_page ?></a></label>
817
				<?php } ?>
818
		<?php } ?>
819
	</tr>
820
</table>
821
</body>
822
</html>