| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431 |
- const API_BASE = window.location.origin;
- function getStateClass(state) {
- switch (state) {
- case 'running': return 'bg-success';
- case 'shut off': return 'bg-secondary';
- case 'paused': return 'bg-warning text-dark';
- case 'crashed': return 'bg-danger';
- default: return 'bg-light text-dark';
- }
- }
- async function loadISOs() {
- try {
- const response = await fetch(`${API_BASE}/isos`);
- const data = await response.json();
- const tbody = document.getElementById('isoTableBody');
- tbody.innerHTML = '';
-
- data.isos.forEach(iso => {
- const row = document.createElement('tr');
- row.innerHTML = `
- <td>${iso.name}</td>
- <td>
- <button class="btn btn-sm btn-danger" onclick="deleteISO('${iso.name}')">Delete</button>
- </td>
- `;
- tbody.appendChild(row);
- });
- } catch (error) {
- console.error('Error loading ISOs:', error);
- alert('Error loading ISOs');
- }
- }
- async function deleteISO(name) {
- if (confirm(`Delete ISO ${name}?`)) {
- try {
- const response = await fetch(`${API_BASE}/isos/${name}`, { method: 'DELETE' });
- const result = await response.json();
- if (response.ok) {
- alert(result.message);
- loadISOs();
- loadISOsForSelect(); // Refresh the select
- } else {
- alert(result.error);
- }
- } catch (error) {
- console.error('Error deleting ISO:', error);
- alert('Error deleting ISO');
- }
- }
- }
- async function loadISOsForSelect() {
- try {
- const response = await fetch(`${API_BASE}/isos`);
- const data = await response.json();
- const select = document.getElementById('iso');
- select.innerHTML = '<option value="">Select ISO</option>';
- data.isos.forEach(iso => {
- select.innerHTML += `<option value="${iso.path}">${iso.name}</option>`;
- });
- } catch (error) {
- console.error('Error loading ISOs:', error);
- }
- }
- /* Load VMs and populate the table */
- async function loadVMs() {
- try {
- const response = await fetch(`${API_BASE}/vms`);
- const data = await response.json();
- const tbody = document.getElementById('vmTableBody');
- tbody.innerHTML = '';
- const select = document.getElementById('bootVM');
- select.innerHTML = '<option value="">Select VM</option>';
- const diskSelect = document.getElementById('diskVM');
- diskSelect.innerHTML = '<option value="">Select VM</option>';
-
- data.vms.forEach(vm => {
- const row = document.createElement('tr');
- row.innerHTML = `
- <td>${vm.id}</td>
- <td>${vm.name}</td>
- <td><span class="badge ${getStateClass(vm.state)}">${vm.state}</span></td>
- <td>
- <button class="btn btn-sm btn-info" onclick="showVMInfo('${vm.name}')">Info</button>
- <button class="btn btn-sm btn-success" onclick="startVM('${vm.name}')">Lanzar</button>
- <button class="btn btn-sm btn-warning" onclick="stopVM('${vm.name}')">Stop</button>
- <button class="btn btn-sm btn-danger" onclick="deleteVM('${vm.name}')">Delete</button>
- ${vm.vnc_port ? `<button class="btn btn-sm btn-primary" onclick="openVNC('${vm.name}')">Console</button>` : ''}
- </td>
- `;
- tbody.appendChild(row);
- select.innerHTML += `<option value="${vm.name}">${vm.name}</option>`;
- diskSelect.innerHTML += `<option value="${vm.name}">${vm.name}</option>`;
- });
- loadISOsForSelect(); // Load ISOs after loading VMs
- } catch (error) {
- console.error('Error loading VMs:', error);
- alert('Error loading VMs');
- }
- }
- async function showVMInfo(name) {
- try {
- const response = await fetch(`${API_BASE}/vms/${name}/info`);
- const data = await response.json();
-
- if (!response.ok) {
- alert(data.error || 'Error loading VM information');
- return;
- }
-
- const modalBody = document.getElementById('infoModalBody');
- modalBody.innerHTML = `
- <div class="row mb-3">
- <div class="col-md-6">
- <h6><strong>Nombre:</strong></h6>
- <p>${data.name}</p>
- </div>
- <div class="col-md-6">
- <h6><strong>ID:</strong></h6>
- <p>${data.id}</p>
- </div>
- </div>
- <div class="row mb-3">
- <div class="col-md-6">
- <h6><strong>Estado:</strong></h6>
- <p><span class="badge ${getStateClass(data.state)}">${data.state}</span></p>
- </div>
- <div class="col-md-6">
- <h6><strong>Memoria:</strong></h6>
- <p>${data.memory} MiB</p>
- </div>
- </div>
- <div class="row mb-3">
- <div class="col-md-6">
- <h6><strong>CPUs:</strong></h6>
- <p>${data.cpus}</p>
- </div>
- <div class="col-md-6">
- <h6><strong>Puerto VNC:</strong></h6>
- <p>${data.vnc_port || 'No asignado'}</p>
- </div>
- </div>
- <div class="mb-3">
- <h6><strong>Discos:</strong></h6>
- <table class="table table-sm">
- <thead>
- <tr>
- <th>Dispositivo</th>
- <th>Tipo</th>
- <th>Ruta</th>
- </tr>
- </thead>
- <tbody>
- ${data.disks.map(disk => `
- <tr>
- <td>${disk.target}</td>
- <td>${disk.type}</td>
- <td>${disk.source}</td>
- </tr>
- `).join('')}
- </tbody>
- </table>
- </div>
- <div class="mb-3">
- <h6><strong>Interfaces de Red:</strong></h6>
- <table class="table table-sm">
- <thead>
- <tr>
- <th>MAC</th>
- <th>Red</th>
- <th>Modelo</th>
- </tr>
- </thead>
- <tbody>
- ${data.interfaces.map(iface => `
- <tr>
- <td>${iface.mac}</td>
- <td>${iface.network}</td>
- <td>${iface.model}</td>
- </tr>
- `).join('')}
- </tbody>
- </table>
- </div>
- `;
-
- const modal = new bootstrap.Modal(document.getElementById('infoModal'));
- modal.show();
- } catch (error) {
- console.error('Error loading VM information:', error);
- alert('Error loading VM information');
- }
- }
- async function startVM(name) {
- try {
- await fetch(`${API_BASE}/vms/${name}/start`);
- loadVMs();
- } catch (error) {
- console.error('Error starting VM:', error);
- alert('Error starting VM');
- }
- }
- async function stopVM(name) {
- try {
- await fetch(`${API_BASE}/vms/${name}/stop`);
- loadVMs();
- } catch (error) {
- console.error('Error stopping VM:', error);
- alert('Error stopping VM');
- }
- }
- async function deleteVM(name) {
- if (confirm(`Delete VM ${name}?`)) {
- try {
- await fetch(`${API_BASE}/vms/${name}`, { method: 'DELETE' });
- loadVMs();
- } catch (error) {
- console.error('Error deleting VM:', error);
- alert('Error deleting VM');
- }
- }
- }
- function openVNC(vm_name) {
- fetch(`${API_BASE}/console/${vm_name}`)
- .then(response => response.json())
- .then(data => {
- if (data.url) {
- window.open(data.url);
- } else {
- alert(data.error || 'Error opening console');
- }
- })
- .catch(error => {
- console.error('Error:', error);
- alert('Error opening console');
- });
- }
- document.getElementById('createVMForm').addEventListener('submit', async (e) => {
- e.preventDefault();
- const name = document.getElementById('name').value;
- const memory = document.getElementById('memory').value;
- const disk_size = document.getElementById('disk_size').value;
- const cpus = document.getElementById('cpus').value;
- const iso = document.getElementById('iso').value;
-
- if (!iso) {
- alert('Por favor seleccione una imagen ISO');
- return;
- }
-
- try {
- const response = await fetch(`${API_BASE}/vms?name=${name}&memory=${memory}&disk_size=${disk_size}&cpus=${cpus}&iso=${iso}`, {
- method: 'POST'
- });
- let result;
- try {
- result = await response.json();
- } catch {
- result = { error: `Server error: ${response.status} ${response.statusText}` };
- }
- if (response.ok) {
- alert(result.message || 'VM creada correctamente');
- loadVMs();
- document.getElementById('createVMForm').reset();
- } else {
- console.error('Error response:', result);
- alert(`Error: ${result.error || 'Error desconocido al crear VM'}`);
- }
- } catch (error) {
- console.error('Error creating VM:', error);
- alert(`Error de conexión: ${error.message}`);
- }
- });
- if (document.getElementById('setBootOrderForm')) {
- document.getElementById('setBootOrderForm').addEventListener('submit', async (e) => {
- e.preventDefault();
- const vm_name = document.getElementById('bootVM').value;
- const boot_order_str = document.getElementById('bootOrder').value;
- const order = boot_order_str.split(',').map(s => s.trim());
-
- try {
- const response = await fetch(`${API_BASE}/vms/${vm_name}/boot-order`, {
- method: 'PUT',
- headers: {
- 'Content-Type': 'application/json'
- },
- body: JSON.stringify({ order: order })
- });
- const result = await response.json();
- if (response.ok) {
- alert(result.message);
- loadVMs();
- document.getElementById('setBootOrderForm').reset();
- } else {
- alert(result.error);
- }
- } catch (error) {
- console.error('Error setting boot order:', error);
- alert('Error setting boot order');
- }
- });
- }
- if (document.getElementById('addDiskForm')) {
- document.getElementById('addDiskForm').addEventListener('submit', async (e) => {
- e.preventDefault();
- const vm_name = document.getElementById('diskVM').value;
- const disk_name = document.getElementById('diskName').value;
- const disk_size = document.getElementById('diskSize').value;
-
- if (!vm_name) {
- alert('Por favor selecciona una máquina virtual');
- return;
- }
-
- if (!disk_name) {
- alert('Por favor ingresa un nombre para el disco');
- return;
- }
-
- if (!disk_size || disk_size <= 0) {
- alert('Por favor ingresa un tamaño de disco válido (> 0 GB)');
- return;
- }
-
- try {
- const response = await fetch(`${API_BASE}/vms/${vm_name}/add-disk?disk_name=${disk_name}&disk_size=${disk_size}`, {
- method: 'POST'
- });
- let result;
- try {
- result = await response.json();
- } catch {
- result = { error: `Server error: ${response.status} ${response.statusText}` };
- }
- if (response.ok) {
- alert(result.message || 'Disco agregado correctamente');
- loadVMs();
- document.getElementById('addDiskForm').reset();
- } else {
- console.error('Add disk error:', result);
- alert(result.error || 'Error al agregar disco');
- }
- } catch (error) {
- console.error('Error adding disk:', error);
- alert(`Error de conexión: ${error.message}`);
- }
- });
- }
- if (document.getElementById('uploadIsoForm')) {
- document.getElementById('uploadIsoForm').addEventListener('submit', (e) => {
- e.preventDefault();
- const fileInput = document.getElementById('isoFile');
- const file = fileInput.files[0];
- if (!file) {
- alert('Please select a file');
- return;
- }
- const formData = new FormData();
- formData.append('file', file);
-
- const progressContainer = document.getElementById('progressContainer');
- const progressBar = document.getElementById('uploadProgress');
- const uploadBtn = document.getElementById('uploadBtn');
-
- // Show progress bar
- progressContainer.style.display = 'block';
- uploadBtn.disabled = true;
- progressBar.style.width = '0%';
- progressBar.textContent = '0%';
-
- const xhr = new XMLHttpRequest();
-
- xhr.upload.addEventListener('progress', (e) => {
- if (e.lengthComputable) {
- const percentComplete = Math.round((e.loaded / e.total) * 100);
- progressBar.style.width = percentComplete + '%';
- progressBar.textContent = percentComplete + '%';
- }
- });
-
- xhr.addEventListener('load', () => {
- if (xhr.status === 200) {
- const result = JSON.parse(xhr.responseText);
- alert(result.message);
- loadISOsForSelect();
- document.getElementById('uploadIsoForm').reset();
- progressContainer.style.display = 'none';
- uploadBtn.disabled = false;
- } else {
- try {
- const result = JSON.parse(xhr.responseText);
- alert(result.error || 'Error uploading ISO');
- } catch {
- alert('Error uploading ISO');
- }
- progressContainer.style.display = 'none';
- uploadBtn.disabled = false;
- }
- });
-
- xhr.addEventListener('error', () => {
- alert('Error uploading ISO');
- progressContainer.style.display = 'none';
- uploadBtn.disabled = false;
- });
-
- xhr.open('POST', `${API_BASE}/upload-iso`);
- xhr.send(formData);
- });
- }
- // Initialize event listeners and load data when DOM is ready
- document.addEventListener('DOMContentLoaded', function() {
- loadVMs();
- loadISOs();
- });
|