Subversion Repositories ALCASAR

Rev

Details | Last modification | View Log

Rev Author Line No. Line
3294 rexy 1
<?php
2
 
3
// written by Alexandre BOUIJOUX
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 ?";
68
	$l_db_pwd		= "Mot de passe BDD";
69
	$l_db_user		= "Utilisateur BDD";
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";
75
	$l_hosts_settings	= "Paramètres de réplication des hôtes";
76
	$l_import_ssh_key	= "Importer une clé SSH";
77
	$l_install_repl		= "Installer la fédération";
78
	$l_ip_address		= "Adresse IP";
79
	$l_no_primary_connected = "Aucun primaire connecté";
80
	$l_no_ssh_key		= "Pas de clé SSH.";
81
	$l_not_connected	= "Non connecté";
82
	$l_pubkey_to_deploy	= "La clé doit être déployée sur les serveurs primaires.";
83
	$l_remote_access_mgmt	= "Gestion des accès distants";
84
	$l_remote_role		= "Rôle de l'hôte distant";
85
	$l_repl_io_running	= "État";
86
	$l_replication_install	= "Installer la Fédération";
87
	$l_replication_title	= "Fédération";
88
	$l_role_primary		= "Primaire";
89
	$l_role_secondary	= "Secondaire";
90
	$l_ssh_keys_for_primary	= "Liste des clés autorisées à se connecter à l'utilisateur local 'replication'.";
91
	$l_ssh_port		= "Port SSH";
92
	$l_ssh_user		= "Utilisateur SSH";
93
	$l_ssh_wan_enabled	= "Le SSH sur le WAN est activé.";
94
	$l_ssh_wan_must_be_on	= "Le SSH sur le WAN doit être activé.";
95
	$l_start		= "Démarrer";
96
	$l_stop			= "Arrêter";
97
	$l_uninstall_repl	= "Désinstaller la fédération";
98
	$l_value		= "Valeur";
99
	$l_want_server_as_prim	= "Vous voulez que le serveur soit primaire ?";
100
} else if ($Language === 'es') {
101
	$l_action		= "Action";
102
	$l_add_to_list		= "Ajouter";
103
	$l_algorithm		= "Algorithme";
104
	$l_apply		= "Appliquer les changements";
105
	$l_bind_port		= "Port de liaison";
106
	$l_cant_read_pubkey	= "Impossible de lire la clé publique de 'root'.";
107
	$l_confirm_uninstall	= "¿Estás seguro de que quieres desinstalar la federación?";
108
	$l_db_pwd		= "Mot de passe BDD";
109
	$l_db_user		= "Utilisateur BDD";
110
	$l_delete		= "Supprimer";
111
	$l_error_details	= "Détails des erreurs";
112
	$l_field		= "Champ";
113
	$l_go_network_conf_page	= "Allez sur la page de configuration réseau.";
114
	$l_host_name		= "Nom d'hôte";
115
	$l_hosts_settings	= "Paramètres de réplication des hôtes";
116
	$l_import_ssh_key	= "Importer une clé SSH";
117
	$l_install_repl		= "Creación de la federación";
118
	$l_ip_address		= "Adresse IP";
119
	$l_no_primary_connected = "Aucun primaire connecté";
120
	$l_no_ssh_key		= "Pas de clé SSH.";
121
	$l_not_connected	= "Non connecté";
122
	$l_pubkey_to_deploy	= "La clé doit être déployée sur les serveurs primaires.";
123
	$l_remote_access_mgmt	= "Gestion des accès distants";
124
	$l_remote_role		= "Rôle de l'hôte distant";
125
	$l_repl_io_running	= "État";
126
	$l_replication_install	= "Creación de la federación";
127
	$l_replication_title	= "Federación";
128
	$l_role_primary		= "Primaire";
129
	$l_role_secondary	= "Secondaire";
130
	$l_ssh_keys_for_primary	= "Liste des clés autorisées à se connecter à l'utilisateur local 'replication'.";
131
	$l_ssh_port		= "Port SSH";
132
	$l_ssh_user		= "Utilisateur SSH";
133
	$l_ssh_wan_enabled	= "Le SSH sur le WAN est activé.";
134
	$l_ssh_wan_must_be_on	= "Le SSH sur le WAN doit être activé.";
135
	$l_start		= "Démarrer";
136
	$l_stop			= "Arrêter";
137
	$l_uninstall_repl	= "Desinstalar la federación";
138
	$l_value		= "Valeur";
139
	$l_want_server_as_prim	= "Vous voulez que le serveur soit primaire ?";
140
} else {
141
	$l_action		= "Action";
142
	$l_add_to_list		= "Add";
143
	$l_algorithm		= "Algorithm";
144
	$l_apply		= "Apply changes";
145
	$l_bind_port		= "Bind port";
146
	$l_cant_read_pubkey	= "Can't read root's public key.";
147
	$l_confirm_uninstall	= "Are you sure you want to uninstall the federation?";
148
	$l_db_pwd		= "Database password";
149
	$l_db_user		= "Database user";
150
	$l_delete		= "Delete";
151
	$l_error_details	= "Error details";
152
	$l_field		= "Field";
153
	$l_go_network_conf_page	= "Go to network config page.";
154
	$l_host_name		= "Host name";
155
	$l_hosts_settings	= "Replicated hosts settings";
156
	$l_import_ssh_key	= "Import a SSH key";
157
	$l_install_repl		= "Setting up the federation";
158
	$l_ip_address		= "IP address";
159
	$l_no_primary_connected = "No primary connected";
160
	$l_no_ssh_key		= "No SSH key.";
161
	$l_not_connected	= "Not connected";
162
	$l_pubkey_to_deploy	= "The following public key has to be deployed on remote primary servers.";
163
	$l_remote_access_mgmt	= "Remote access management";
164
	$l_remote_role		= "Remote role";
165
	$l_repl_io_running	= "State";
166
	$l_replication_install	= "Setting up the federation";
167
	$l_replication_title	= "Federation";
168
	$l_role_primary		= "Primary";
169
	$l_role_secondary	= "Secondary";
170
	$l_ssh_keys_for_primary	= "List of keys allowed to connect to local 'replication' user.";
171
	$l_ssh_port		= "SSH port";
172
	$l_ssh_user		= "SSH user";
173
	$l_ssh_wan_enabled	= "SSH on WAN is enabled.";
174
	$l_ssh_wan_must_be_on	= "SSH on WAN must be enabled.";
175
	$l_start		= "Start";
176
	$l_stop			= "Stop";
177
	$l_uninstall_repl	= "Uninstall the federation";
178
	$l_value		= "Value";
179
	$l_want_server_as_prim	= "Want server to be a primary?";
180
}
181
 
182
$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])$';
183
$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]))$';
184
$reg_host    = '^[a-zA-Z0-9-_]+$';
185
$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.*)?$";
186
$reg_linux_user = "[a-z_][a-z0-9_-]*[$]?";
187
$reg_mariadb_user = "^[a-z]{1,32}$";
188
 
189
// Allow new SSH file size of 128kB;
190
$max_ssh_file_size = 131072;
191
 
192
$choice = $_POST['choice'] ?? "";
193
switch ($choice) {
194
	case 'install_replication':
195
		if (isset($conf['REPLICATION']) && $conf['REPLICATION'] == "on") {
196
			exit("Replication already installed.");}
197
		$stdout = [];
198
		exec('sudo /usr/local/bin/alcasar-replication-install.sh 2>&1', $stdout);
199
		header('Location: '.$_SERVER['PHP_SELF']);
200
		break;
201
	case 'uninstall_replication':
202
		if (!isset($conf['REPLICATION']) || $conf['REPLICATION'] == "off") {
203
			exit("Replication not installed.");}
204
		$stdout = [];
205
		exec('sudo /usr/local/bin/alcasar-replication-uninstall.sh 2>&1', $stdout);
206
		header('Location: '.$_SERVER['PHP_SELF']);
207
		break;
208
	case 'add_replica':
209
		$role = trim($_POST['role'] ?? "");
210
		$name = trim($_POST['name'] ?? "");
211
		$ip = trim($_POST['ip'] ?? "");
212
		$port = trim($_POST['port'] ?? "");
213
		$user = trim($_POST['user'] ?? "");
214
		$pwd = trim($_POST['pwd'] ?? "");
215
		$db_user = trim($_POST['db_user'] ?? "");
216
		$db_pwd = trim($_POST['db_pwd'] ?? "");
217
		$bind_port = trim($_POST['bind_port'] ?? "");
218
		$stdout = [];
219
		$return = 0;
220
		switch ($role) {
221
			case 'primary':
222
				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);
223
				break;
224
			case 'secondary':
225
				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);
226
				break;
227
			default:
228
				// Error
229
				exit();}
230
		// If script went wrong
231
		if ($return) {
232
			$key = $choice . "_error";
233
			// Concatenate stdout lines
234
			$value = implode(PHP_EOL, $stdout);
235
			// Save error message in cookies
236
			setcookie($key, $value);
237
		}
238
		header('Location: '.$_SERVER['PHP_SELF']);
239
		break;
240
	case 'change_replicas_state':
241
		$stdout = [];
242
		$return = 0;
243
		$key_prefix = "action_primary_";
244
 
245
		// Search for action_primary_<hostname> key
246
		foreach ($_POST as $key => $value) {
247
			if (!str_starts_with($key, $key_prefix)) {
248
				continue;}
249
			// Get the remote name
250
			$name = explode($key_prefix, $key)[1];
251
			switch ($value) {
252
				case 'start':
253
					exec("sudo /usr/local/bin/alcasar-replication-start.sh --name=".escapeshellarg($name)." 2>&1", $stdout, $return);
254
					break;
255
				case 'stop':
256
					exec("sudo /usr/local/bin/alcasar-replication-stop.sh --name=".escapeshellarg($name)." 2>&1", $stdout, $return);
257
					break;
258
				case 'delete':
259
					exec("sudo /usr/local/bin/alcasar-replication-delete.sh --name=".escapeshellarg($name)." 2>&1", $stdout, $return);
260
					break;
261
				default:
262
					break;
263
			}
264
		}
265
		// If script went wrong
266
		if ($return) {
267
			$key = $choice . "_error";
268
			// Concatenate stdout lines
269
			$value = implode(PHP_EOL, $stdout);
270
			// Save error message in cookies
271
			setcookie($key, $value);
272
		}
273
		header('Location: '.$_SERVER['PHP_SELF']);
274
		break;
275
	case 'add_ssh_key':
276
		$file = $_FILES['new_ssh_key_input'] ?? "";
277
		$stdout = [];
278
		$return = 0;
279
		// Stop if file doesn't exist
280
		if (empty($file)) {
281
			break;}
282
		// Check file size
283
		if ($file['size'] > $max_ssh_file_size) {
284
			break;}
285
		// Add new key(s) to authorized keys list
286
		$tmp_file = $file['tmp_name'];
287
		exec("sudo /usr/local/bin/alcasar-replication-ssh-keys-management.sh --add --file=$tmp_file 2>&1", $stdout, $return);
288
		// If script went wrong
289
		if ($return) {
290
			$key = $choice . "_error";
291
			// Concatenate stdout lines
292
			$value = implode(PHP_EOL, $stdout);
293
			// Save error message in cookies
294
			setcookie($key, $value);
295
		}
296
		header('Location: '.$_SERVER['PHP_SELF']);
297
		break;
298
	case 'delete_ssh_key':
299
		$stdout = [];
300
		$return = 0;
301
		$key_prefix = "action_ssh_key_";
302
		foreach ($_POST as $key => $value) {
303
			if (!str_starts_with($key, $key_prefix)) {
304
				continue;}
305
			$decoded_value = htmlspecialchars_decode($value);
306
			// Delete key
307
			exec("sudo /usr/local/bin/alcasar-replication-ssh-keys-management.sh --delete --regex=$decoded_value 2>&1", $stdout, $return);
308
			// If script went wrong
309
			if ($return) {
310
				$key = $choice . "_error";
311
				// Concatenate stdout lines
312
				$value = implode(PHP_EOL, $stdout);
313
				// Save error message in cookies
314
				setcookie($key, $value);
315
			}
316
		}
317
		header('Location: '.$_SERVER['PHP_SELF']);
318
		break;
319
	default:
320
		break;
321
}
322
 
323
?>
324
<!DOCTYPE HTML>
325
<html>
326
<head>
327
	<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
328
	<title><?= $l_replication_title ?></title>
329
	<link rel="stylesheet" href="/css/acc.css" type="text/css">
330
	<script src="/js/jquery.min.js"></script>
331
	<script src="/js/jquery.connections.js"></script>
332
	<script type="text/javascript">
333
		window.onload = main;
334
		function main() {
335
			show_fields_for_new_primary();
336
			set_required_on_common_fields();
337
			enable_apply_btn_if_selected_primary_action();
338
			enable_apply_btn_if_selected_ssh_key_action();
339
		}
340
		// Set 'required' attribute on fields needed by both primary and secondary
341
		function set_required_on_common_fields() {
342
			document.querySelectorAll(".role_primary.role_secondary").forEach((input) => {
343
				input.setAttribute("required", "");
344
			});
345
		}
346
		// Only enable fields needed for new primary remote
347
		function show_fields_for_new_primary() {
348
			// Toggle 'disabled' and 'required' attributes
349
			document.querySelectorAll("input[class='role_primary']").forEach((input) => {
350
				input.removeAttribute("disabled");
351
				input.setAttribute("required", "");
352
			});
353
			document.querySelectorAll("input[class='role_secondary']").forEach((input) => {
354
				input.setAttribute("disabled", "");
355
				input.removeAttribute("required");
356
			});
357
		}
358
		function show_fields_for_new_secondary() {
359
			// Toggle 'disabled' and 'required' attributes
360
			document.querySelectorAll("input[class='role_primary']").forEach((input) => {
361
				input.removeAttribute("required");
362
				input.setAttribute("disabled", "");
363
			});
364
			document.querySelectorAll("input[class='role_secondary']").forEach((input) => {
365
				input.setAttribute("required", "");
366
				input.removeAttribute("disabled");
367
			});
368
		}
369
		// Enable the remote's list Apply button if there are any pending actions
370
		function enable_apply_btn_if_selected_primary_action() {
371
			let btn = document.querySelector("#apply_changes_primary_btn");
372
			if (!btn) {
373
				return;}
374
			let change_to_apply = false;
375
			// Check for any pending change
376
			document.querySelectorAll(".primary_action_select").forEach((element) => {
377
				if (element.value != "") {
378
					btn.removeAttribute("disabled");
379
					change_to_apply = true;
380
				}
381
			});
382
			// Disable button if there are no pending changes
383
			if (!change_to_apply) {
384
				btn.setAttribute("disabled", "");
385
			}
386
		}
387
		// Enable the SSH keys's list Apply button if there are any pending actions
388
		function enable_apply_btn_if_selected_ssh_key_action() {
389
			let btn = document.querySelector("#apply_changes_ssh_key_btn");
390
			if (!btn) {
391
				return;
392
			}
393
			let change_to_apply = false;
394
			// Check for any pending change
395
			document.querySelectorAll(".ssh_key_action_input").forEach((element) => {
396
				if (element.checked) {
397
					btn.removeAttribute("disabled");
398
					change_to_apply = true;
399
				}
400
			});
401
			// Disable button if there are no pending changes
402
			if (!change_to_apply) {
403
				btn.setAttribute("disabled", "");
404
			}
405
		}
406
	</script>
407
</head>
408
<body>
409
<div id="ldoverlay" class="overlay">
410
	<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>
411
</div>
412
<?php if ($conf['REPLICATION'] == "on") { ?>
413
<div class="panel">
414
	<div class="panel-header"><?= $l_hosts_settings ?></div>
415
</div>
416
<div>
417
<table width="100%" cellspacing="0" cellpadding="5" border="1">
418
	<tr>
419
		<td width="50%" align="center">
420
			<?php $section = "change_replicas_state" ?>
421
			<form action="<?= htmlspecialchars($_SERVER['PHP_SELF']) ?>" method="POST">
422
			<input type="hidden" name="choice" value="<?= $section ?>">
423
			<table cellspacing="2" cellpadding="3" border="1" style="table-layout: auto; min-width: 10em;">
424
				<tr>
425
					<th><?= $l_ip_address ?></th>
426
					<th><?= $l_host_name ?></th>
427
					<th><?= $l_repl_io_running ?></th>
428
					<th><?= $l_bind_port ?></th>
429
					<th><?= $l_action ?></th>
430
				</tr>
431
 
432
				<?php
433
				$stdout = [];
434
				$return = 0;
435
				exec("sudo /usr/local/bin/alcasar-replication-list.sh --all 2>&1", $stdout, $return);
436
 
437
				// If script went wrong
438
				if ($return) {
439
					// Print error message
440
					$errors_msg[$section."_error"] = implode(PHP_EOL, $stdout);
441
				// Successfully fetched remotes stats
442
				} else {
443
					$connected_prims = [];
444
					$current_prim = "";
445
					// Parse stdout in keys-array
446
					foreach ($stdout as $row) {
447
						// Skip useless delimiter
448
						if (str_starts_with($row, '*')) {
449
							continue;
450
						}
451
						// Split key: value
452
						$exploded = explode(": ", $row);
453
						$key = $exploded[0];
454
						$value = $exploded[1] ?? "";
455
						// Create subarray when starting to display a new remote
456
						if (!strcmp($key, "Connection_name")) {
457
							$current_prim = $value;
458
							$connected_prims[$current_prim] = [];
459
						}
460
						// Put value in prim's subarray
461
						($connected_prims[$current_prim])[$key] = $value;
462
					}
463
					// Skip resetted replicas,
464
					// they will stay displayed still the next database restart.
465
					foreach ($connected_prims as $prim) {
466
						if (empty($prim["Relay_Log_File"])) {
467
							unset($connected_prims[$prim["Connection_name"]]);
468
						}
469
					}
470
					// List each connection
471
					foreach ($connected_prims as $prim) {
472
						?>
473
						<tr>
474
							<td><?php
475
								$master_host = $prim["Master_Host"];
476
								if ($master_host != "127.0.0.1") {
477
									echo "$master_host";
478
								} else {
479
									echo "$l_not_connected";
480
								}
481
							?></td>
482
							<td><?= $prim["Connection_name"] ?></td>
483
							<td><?= $prim["Slave_IO_Running"] ?></td>
484
							<td><?= $prim["Master_Port"] ?></td>
485
							<td>
486
								<select name="action_primary_<?= $prim["Connection_name"] ?>" class="primary_action_select" onchange="enable_apply_btn_if_selected_primary_action()">
487
									<option value=""></option>
488
									<?php
489
										// Actions available on all remotes
490
										$options = array(
491
											"start" => "$l_start",
492
											"stop" => "$l_stop",
493
											"delete" => "$l_delete"
494
										);
495
										// Remove some options depending on the current remote state
496
										switch ($prim["Slave_IO_Running"]) {
497
										case 'Yes':
498
										case 'Connecting':
499
											unset($options["start"]);
500
											unset($options["delete"]);
501
											break;
502
										case 'No':
503
											unset($options["stop"]);
504
											break;
505
										default:
506
											break;
507
										}
508
 
509
										// Print options
510
										foreach ($options as $key => $value) { ?>
511
											<option value="<?= $key ?>"><?= $value ?></option>
512
										<?php }
513
									 ?>
514
								</select>
515
							</td>
516
						</tr>
517
					<?php }
518
					// Show submit button if there are primary servers connected
519
					echo "<tr><td colspan=5 valign='middle' align='center'>";
520
					if (sizeof($connected_prims)) { ?>
521
						<input type="submit" id="apply_changes_primary_btn" value="<?= $l_apply ?>" onClick="document.getElementById('ldoverlay').style.display='block';">
522
					<?php } else { ?>
523
						<p><?= $l_no_primary_connected ?></p>
524
					<?php }
525
					echo "</td></tr>";
526
				} ?>
527
			</table>
528
			</form>
529
			<?php if (isset($errors_msg[$section."_error"])) { ?>
530
				<details open>
531
					<summary><?= $l_error_details ?></summary>
532
					<textarea readonly cols=50 rows=10><?= $errors_msg[$section."_error"] ?></textarea>
533
				</details>
534
			<?php } ?>
535
		</td>
536
		<td width="50%" valign="middle" align="center">
537
			<?php $section = "add_replica" ?>
538
			<form action="<?= htmlspecialchars($_SERVER['PHP_SELF']) ?>" method="POST">
539
			<input type="hidden" name="choice" value="<?= $section ?>">
540
				<table cellspacing="2" cellpadding="3" border="1">
541
					<tr>
542
						<th><?= $l_field ?></th>
543
						<th><?= $l_value ?></th>
544
					</tr>
545
					<tr>
546
						<td><?= $l_remote_role ?></td>
547
						<td>
548
							<fieldset>
549
								<div>
550
									<input type="radio" id="role_primary" name="role" value="primary" checked onClick="show_fields_for_new_primary()"/>
551
									<label for="role_primary"><?= $l_role_primary ?></label>
552
 
553
									<input type="radio" id="role_secondary" name="role" value="secondary" onClick="show_fields_for_new_secondary()"/>
554
									<label for="role_secondary"><?= $l_role_secondary ?></label>
555
								</div>
556
							</fieldset>
557
						</td>
558
					</tr>
559
					<tr>
560
						<td><label for="input_name"><?= $l_host_name ?></label></td>
561
						<td><input type="text" id="input_name" name="name" class="role_primary role_secondary" pattern="<?= $reg_host ?>"></td>
562
					</tr>
563
					<tr>
564
						<td><label for="input_ip"><?= $l_ip_address ?></label></td>
565
						<td><input type="text" id="input_ip" name="ip" class="role_primary" pattern="<?= $reg_ip ?>"></td>
566
					</tr>
567
					<tr>
568
						<td><label for="input_bind_port"><?= $l_bind_port ?></label></td>
569
						<td><input type="number" id="input_bind_port" name="bind_port" min="0" max="65535" class="role_secondary" pattern="<?= $reg_ip_port ?>"></td>
570
					</tr>
571
					<tr>
572
						<td><label for="input_port"><?= $l_ssh_port ?></label></td>
573
						<td><input type="number" id="input_port" name="port" min="0" max="65535" placeholder="22" class="role_primary" pattern="<?= $reg_ip_port ?>"></td>
574
					</tr>
575
					<tr>
576
						<td><label for="input_user"><?= $l_ssh_user ?></label></td>
577
						<td><input type="text" id="input_user" name="user" value="replication" disabled class="role_primary" pattern="<?= $reg_linux_user ?>"></td>
578
					</tr>
579
					<tr>
580
						<td><label for="input_db_user"><?= $l_db_user ?></label></td>
581
						<td><input type="text" id="input_db_user" name="db_user" value="replication" disabled class="role_primary role_secondary" pattern="<?= $reg_mariadb_user ?>"></td>
582
					</tr>
583
					<tr>
584
						<td><label for="input_db_pwd"><?= $l_db_pwd ?></label></td>
585
						<td><input type="password" id="input_db_pwd" name="db_pwd" class="role_primary role_secondary"></td>
586
					</tr>
587
					<tr>
588
						<td colspan=2 valign="middle" align="center">
589
							<input type="submit" class="button" value="<?= $l_add_to_list ?>" onClick="document.getElementById('ldoverlay').style.display='block';">
590
						</td>
591
					</tr>
592
				</table>
593
			</form>
594
			<?php if (isset($errors_msg[$section."_error"])) { ?>
595
				<details open>
596
					<summary><?= $l_error_details ?></summary>
597
					<textarea readonly cols=50 rows=10><?= htmlspecialchars($errors_msg[$section."_error"]) ?></textarea>
598
				</details>
599
			<?php } ?>
600
		</td>
601
	</tr>
602
</table>
603
</div>
604
<br>
605
<div class="panel">
606
	<div class="panel-header"><?= $l_remote_access_mgmt ?></div>
607
</div>
608
<div>
609
<table width="100%" cellspacing="0" cellpadding="5" border="1">
610
	<tr>
611
		<td width="50%" align="center">
612
			<p><?= $l_ssh_keys_for_primary ?></p>
613
			<?php $section = "delete_ssh_key" ?>
614
			<form action="<?= htmlspecialchars($_SERVER['PHP_SELF']) ?>" method="POST">
615
			<input type="hidden" name="choice" value="<?= $section ?>">
616
			<table cellspacing="2" cellpadding="3" border="1" style="table-layout: auto; min-width: 10em;">
617
				<tr>
618
					<th><?= $l_host_name ?></th>
619
					<th><?= $l_algorithm ?></th>
620
					<th><?= $l_delete ?></th>
621
				</tr>
622
				<?php
623
				$stdout = [];
624
				$return = 0;
625
				exec("sudo /usr/local/bin/alcasar-replication-ssh-keys-management.sh --list 2>&1", $stdout, $return);
626
				// If script went wrong
627
				if ($return) {
628
					// Print error message
629
					$errors_msg[$section."_error"] = implode(PHP_EOL, $stdout);
630
				// Successfully fetched remotes stats
631
				} else {
632
					// List each key
633
					foreach ($stdout as $line) {
634
						// Skip empty lines
635
						if (str_starts_with($line, ' ')) {
636
							continue;
637
						}
638
						// Split args
639
						$exploded = explode(' ', $line);
640
						$algo = $exploded[0] ?? "";
641
						$hostname = $exploded[2] ?? "";
642
						?>
643
						<tr>
644
							<td><?= $hostname ?></td>
645
							<td><?= $algo ?></td>
646
							<td>
647
								<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()">
648
							</td>
649
						</tr>
650
					<?php }
651
 
652
					// Show submit button if there are primary servers connected
653
					echo "<td colspan=3 valign='middle' align='center'>";
654
					if (sizeof($stdout)) { ?>
655
						<input type="submit" id="apply_changes_ssh_key_btn" value="<?= $l_apply ?>" onClick="document.getElementById('ldoverlay').style.display='block';">
656
					<?php } else { ?>
657
						<p><?= $l_no_ssh_key ?></p>
658
					<?php }
659
					echo "</td>";
660
				} ?>
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><?= $errors_msg[$section."_error"] ?></textarea>
667
				</details>
668
			<?php } ?>
669
		</td>
670
		<td width="25%" valign="middle" align="center">
671
			<?php $section = "add_ssh_key" ?>
672
			<form action="<?= htmlspecialchars($_SERVER['PHP_SELF']) ?>" method="POST" enctype="multipart/form-data">
673
			<input type="hidden" name="choice" value="<?= $section ?>">
674
				<input type="hidden" name="MAX_FILE_SIZE" value="<?= $max_ssh_file_size ?>" />
675
				<label for="new_ssh_key_input"><b><?= $l_import_ssh_key ?></b></label>
676
				<br>
677
				<input type="file" name="new_ssh_key_input" id="new_ssh_key_input" accept=".pub">
678
				<br>
679
				<input type="submit" class="button" value="<?= $l_add_to_list ?>" onClick="document.getElementById('ldoverlay').style.display='block';">
680
			</form>
681
			<?php if (isset($errors_msg[$section."_error"])) { ?>
682
				<details open>
683
					<summary><?= $l_error_details ?></summary>
684
					<textarea readonly cols=50 rows=10><?= $errors_msg[$section."_error"] ?></textarea>
685
				</details>
686
			<?php } ?>
687
		</td>
688
		<td width="25%" valign="middle" align="center">
689
				<label for="pubkey_stdout"><?= $l_pubkey_to_deploy ?></label>
690
				<br>
691
				<?php
692
				$stdout = [];
693
				$return = 0;
694
				exec("sudo /usr/local/bin/alcasar-replication-ssh-keys-management.sh --show-pubkey 2>&1", $stdout, $return);
695
				// If script went wrong
696
				if ($return != 0) {
697
					echo "<p>$l_cant_read_pubkey</p>";
698
				} else { ?>
699
					<input type="text" id="pubkey_stdout" readonly value="<?= implode(PHP_EOL, $stdout) ?>">
700
				<?php } ?>
701
		</td>
702
	</tr>
703
</table>
704
</div>
705
<br>
706
<?php } ?>
707
<div class="panel">
708
	<div class="panel-header"><?= $l_replication_title ?></div>
709
</div>
710
<table width="100%" cellspacing="0" cellpadding="5" border="1">
711
	<tr>
712
		<td width="50%" valign="middle" align="center">
713
			<?php if ($conf['REPLICATION'] == "on") { ?>
714
				<form action="<?= htmlspecialchars($_SERVER['PHP_SELF']) ?>" method="POST" onsubmit="return confirm('<?= $l_confirm_uninstall ?>');">
715
					<input type="hidden" name="choice" value="uninstall_replication">
716
					<input type="submit" value="<?= $l_uninstall_repl ?>" onClick="document.getElementById('ldoverlay').style.display='block';">
717
				</form>
718
			<?php } else { ?>
719
				<form action="<?= htmlspecialchars($_SERVER['PHP_SELF']) ?>" method="POST">
720
					<input type="hidden" name="choice" value="install_replication">
721
					<input type="submit" value="<?= $l_install_repl ?>" onClick="document.getElementById('ldoverlay').style.display='block';">
722
				</form>
723
			<?php } ?>
724
		</td>
725
		<?php if ($conf['REPLICATION'] == "on") { ?>
726
			<td width="50%" valign="middle" align="center">
727
				<?php if ($conf['SSH_WAN'] !== '0') { ?>
728
					<input type="checkbox" id="togglessh" checked disabled>
729
					<label for="togglessh"><?= $l_ssh_wan_enabled ?></label>
730
				<?php } else { ?>
731
				<p><?= $l_want_server_as_prim ?></p>
732
					<input type="checkbox" id="togglessh" disabled>
733
					<label for="togglessh"><b><?= $l_ssh_wan_must_be_on ?></b> <a href="/acc/admin/network.php"><?= $l_go_network_conf_page ?></a></label>
734
				<?php } ?>
735
			</td>
736
		<?php } ?>
737
	</tr>
738
</table>
739
</body>
740
</html>