All checks were successful
HAProxy Manager Build and Push / Build-and-Push (push) Successful in 48s
378 lines
14 KiB
HTML
378 lines
14 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>HAProxy Manager</title>
|
|
<style>
|
|
body {
|
|
font-family: Arial, sans-serif;
|
|
max-width: 1200px;
|
|
margin: 0 auto;
|
|
padding: 20px;
|
|
background-color: #f5f5f5;
|
|
}
|
|
.container {
|
|
background-color: white;
|
|
padding: 20px;
|
|
border-radius: 8px;
|
|
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
|
}
|
|
.form-group {
|
|
margin-bottom: 15px;
|
|
}
|
|
label {
|
|
display: block;
|
|
margin-bottom: 5px;
|
|
font-weight: bold;
|
|
}
|
|
input[type="text"], input[type="number"] {
|
|
width: 100%;
|
|
padding: 8px;
|
|
border: 1px solid #ddd;
|
|
border-radius: 4px;
|
|
box-sizing: border-box;
|
|
}
|
|
button {
|
|
background-color: #4CAF50;
|
|
color: white;
|
|
padding: 10px 15px;
|
|
border: none;
|
|
border-radius: 4px;
|
|
cursor: pointer;
|
|
}
|
|
button:hover {
|
|
background-color: #45a049;
|
|
}
|
|
.server-list {
|
|
margin-top: 10px;
|
|
}
|
|
.server-item, .domain-list-item {
|
|
border: 1px solid #ddd;
|
|
padding: 15px;
|
|
margin-bottom: 10px;
|
|
border-radius: 5px;
|
|
}
|
|
.domain-list-item {
|
|
background-color: #f9f9f9;
|
|
}
|
|
.server-item {
|
|
background-color: #fff;
|
|
}
|
|
.delete-btn {
|
|
background-color: #f44336;
|
|
}
|
|
.delete-btn:hover {
|
|
background-color: #da190b;
|
|
}
|
|
.domain-list {
|
|
margin-top: 20px;
|
|
}
|
|
.ssl-btn {
|
|
background-color: #2196F3;
|
|
}
|
|
.ssl-btn:hover {
|
|
background-color: #0b7dda;
|
|
}
|
|
.status {
|
|
padding: 10px;
|
|
margin: 10px 0;
|
|
border-radius: 4px;
|
|
}
|
|
.status.success {
|
|
background-color: #dff0d8;
|
|
color: #3c763d;
|
|
}
|
|
.status.error {
|
|
background-color: #f2dede;
|
|
color: #a94442;
|
|
}
|
|
.regenerate-btn {
|
|
background-color: #ff9800;
|
|
color: white;
|
|
padding: 10px 15px;
|
|
border: none;
|
|
border-radius: 4px;
|
|
cursor: pointer;
|
|
margin-bottom: 20px;
|
|
}
|
|
.regenerate-btn:hover {
|
|
background-color: #f57c00;
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div class="container">
|
|
<h1>HAProxy Domain Manager</h1>
|
|
<button onclick="regenerateConfig()" class="regenerate-btn">Regenerate HAProxy Config</button>
|
|
<button onclick="reloadHAProxy()" class="regenerate-btn" style="background-color: #2196F3;">Reload HAProxy</button>
|
|
<form id="domainForm">
|
|
<div class="form-group">
|
|
<label for="domain">Domain:</label>
|
|
<input type="text" id="domain" required placeholder="example.com">
|
|
</div>
|
|
<div class="form-group">
|
|
<label for="backendName">Backend Name:</label>
|
|
<input type="text" id="backendName" required placeholder="example_backend">
|
|
</div>
|
|
<div class="form-group">
|
|
<label for="templateOverride">Template Override (optional):</label>
|
|
<input type="text" id="templateOverride" placeholder="custom_template">
|
|
</div>
|
|
<h3>Backend Servers</h3>
|
|
<div id="serverList" class="server-list"></div>
|
|
<button type="button" onclick="addServerField()">Add Server</button>
|
|
<button type="submit">Add Domain</button>
|
|
</form>
|
|
<h2>Existing Domains</h2>
|
|
<div id="domainList" class="domain-list"></div>
|
|
</div>
|
|
|
|
<script>
|
|
window.onerror = function(msg, url, lineNo, columnNo, error) {
|
|
console.log('Error: ' + msg + '\nURL: ' + url + '\nLine: ' + lineNo + '\nColumn: ' + columnNo + '\nError object: ' + JSON.stringify(error));
|
|
return false;
|
|
};
|
|
|
|
function addServerField() {
|
|
const serverList = document.getElementById('serverList');
|
|
const serverDiv = document.createElement('div');
|
|
serverDiv.className = 'server-item';
|
|
const serverHTML = `
|
|
<div class="form-group">
|
|
<label>Server Name:</label>
|
|
<input type="text" class="server-name" required placeholder="server1">
|
|
</div>
|
|
<div class="form-group">
|
|
<label>Server Address:</label>
|
|
<input type="text" class="server-address" required placeholder="192.168.1.100">
|
|
</div>
|
|
<div class="form-group">
|
|
<label>Server Port:</label>
|
|
<input type="number" class="server-port" required placeholder="8080">
|
|
</div>
|
|
<div class="form-group">
|
|
<label>Server Options:</label>
|
|
<input type="text" class="server-options" placeholder="check">
|
|
</div>
|
|
<button type="button" class="delete-btn" onclick="this.parentElement.remove()">Remove Server</button>
|
|
`;
|
|
|
|
serverDiv.innerHTML = serverHTML;
|
|
serverList.appendChild(serverDiv);
|
|
}
|
|
|
|
document.getElementById('domainForm').addEventListener('submit', async (e) => {
|
|
e.preventDefault();
|
|
const serverItems = document.getElementById('serverList').getElementsByClassName('server-item');
|
|
|
|
const domainInput = document.getElementById('domain');
|
|
const backendNameInput = document.getElementById('backendName');
|
|
const templateOverrideInput = document.getElementById('templateOverride');
|
|
|
|
if (!domainInput || !backendNameInput) {
|
|
showStatus('Required form fields are missing', 'error');
|
|
return;
|
|
}
|
|
|
|
if (serverItems.length === 0) {
|
|
showStatus('At least one server is required', 'error');
|
|
return;
|
|
}
|
|
|
|
const servers = [];
|
|
for (const item of serverItems) {
|
|
const nameInput = item.querySelector('.server-name');
|
|
const addressInput = item.querySelector('.server-address');
|
|
const portInput = item.querySelector('.server-port');
|
|
const optionsInput = item.querySelector('.server-options');
|
|
|
|
if (!nameInput || !addressInput || !portInput) {
|
|
showStatus('Server configuration is incomplete', 'error');
|
|
return;
|
|
}
|
|
|
|
if (!nameInput.value || !addressInput.value || !portInput.value) {
|
|
showStatus('Please fill in all required server fields', 'error');
|
|
return;
|
|
}
|
|
|
|
servers.push({
|
|
name: nameInput.value,
|
|
address: addressInput.value,
|
|
port: parseInt(portInput.value),
|
|
options: optionsInput.value || "check"
|
|
});
|
|
}
|
|
|
|
const data = {
|
|
domain: domainInput.value,
|
|
backend_name: backendNameInput.value,
|
|
template_override: templateOverrideInput.value || null,
|
|
servers: servers
|
|
};
|
|
|
|
try {
|
|
const response = await fetch('/api/domain', {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
},
|
|
body: JSON.stringify(data)
|
|
});
|
|
|
|
const responseData = await response.json();
|
|
|
|
if (response.ok) {
|
|
showStatus(`Domain added successfully! Domain ID: ${responseData.domain_id}`, 'success');
|
|
document.getElementById('domainForm').reset();
|
|
document.getElementById('serverList').innerHTML = '';
|
|
addServerField();
|
|
loadDomains();
|
|
} else {
|
|
showStatus('Failed to add domain: ' + (responseData.message || 'Unknown error'), 'error');
|
|
}
|
|
} catch (error) {
|
|
showStatus('Error: ' + error.message, 'error');
|
|
console.error('Error details:', error);
|
|
}
|
|
});
|
|
|
|
async function reloadHAProxy() {
|
|
try {
|
|
const response = await fetch('/api/reload', {
|
|
method: 'GET',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
}
|
|
});
|
|
|
|
if (response.ok) {
|
|
showStatus('HAProxy reloaded successfully', 'success');
|
|
} else {
|
|
const data = await response.json();
|
|
showStatus('Failed to reload HAProxy: ' + (data.message || 'Unknown error'), 'error');
|
|
}
|
|
} catch (error) {
|
|
showStatus('Error: ' + error.message, 'error');
|
|
console.error('Error reloading HAProxy:', error);
|
|
}
|
|
}
|
|
|
|
async function requestSSL(domain) {
|
|
try {
|
|
const response = await fetch('/api/ssl', {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
},
|
|
body: JSON.stringify({ domain })
|
|
});
|
|
|
|
if (response.ok) {
|
|
showStatus(`SSL certificate requested for ${domain}`, 'success');
|
|
loadDomains();
|
|
} else {
|
|
showStatus('Failed to request SSL certificate', 'error');
|
|
}
|
|
} catch (error) {
|
|
showStatus('Error: ' + error.message, 'error');
|
|
}
|
|
}
|
|
|
|
async function deleteDomain(domain) {
|
|
if (!confirm(`Are you sure you want to delete ${domain}?`)) {
|
|
return;
|
|
}
|
|
|
|
try {
|
|
const response = await fetch('/api/domain', {
|
|
method: 'DELETE',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
},
|
|
body: JSON.stringify({ domain })
|
|
});
|
|
|
|
if (response.ok) {
|
|
showStatus(`Domain ${domain} deleted successfully`, 'success');
|
|
loadDomains();
|
|
} else {
|
|
showStatus('Failed to delete domain', 'error');
|
|
}
|
|
} catch (error) {
|
|
showStatus('Error: ' + error.message, 'error');
|
|
}
|
|
}
|
|
|
|
async function regenerateConfig() {
|
|
try {
|
|
const response = await fetch('/api/regenerate', {
|
|
method: 'GET',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
}
|
|
});
|
|
|
|
if (response.ok) {
|
|
showStatus('HAProxy configuration regenerated successfully', 'success');
|
|
} else {
|
|
const data = await response.json();
|
|
showStatus('Failed to regenerate configuration: ' + (data.message || 'Unknown error'), 'error');
|
|
}
|
|
} catch (error) {
|
|
showStatus('Error: ' + error.message, 'error');
|
|
console.error('Error regenerating config:', error);
|
|
}
|
|
}
|
|
|
|
function showStatus(message, type) {
|
|
const statusDiv = document.createElement('div');
|
|
statusDiv.className = `status ${type}`;
|
|
statusDiv.textContent = message;
|
|
const container = document.querySelector('.container');
|
|
const domainList = document.querySelector('.domain-list');
|
|
if (container && domainList) {
|
|
container.insertBefore(statusDiv, domainList);
|
|
} else {
|
|
document.body.appendChild(statusDiv);
|
|
}
|
|
setTimeout(() => {
|
|
if (statusDiv.parentNode) {
|
|
statusDiv.remove();
|
|
}
|
|
}, 5000);
|
|
}
|
|
|
|
function loadDomains() {
|
|
fetch('/api/domains')
|
|
.then(response => response.json())
|
|
.then(domains => {
|
|
const domainList = document.getElementById('domainList');
|
|
domainList.innerHTML = '';
|
|
domains.forEach(domain => {
|
|
const domainDiv = document.createElement('div');
|
|
domainDiv.className = 'domain-list-item';
|
|
domainDiv.innerHTML = `
|
|
<h3>${domain.domain}</h3>
|
|
<p>Backend: ${domain.backend_name}</p>
|
|
<p>SSL: ${domain.ssl_enabled ? 'Enabled' : 'Disabled'}</p>
|
|
<button onclick="requestSSL('${domain.domain}')" class="ssl-btn">
|
|
${domain.ssl_enabled ? 'Renew SSL' : 'Enable SSL'}
|
|
</button>
|
|
<button onclick="deleteDomain('${domain.domain}')" class="delete-btn">Delete Domain</button>
|
|
`;
|
|
domainList.appendChild(domainDiv);
|
|
});
|
|
})
|
|
.catch(error => {
|
|
console.error('Error loading domains:', error);
|
|
showStatus('Error loading domains: ' + error.message, 'error');
|
|
});
|
|
}
|
|
|
|
addServerField();
|
|
loadDomains();
|
|
</script>
|
|
</body>
|
|
</html> |