app.js 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242
  1. const API_BASE = window.location.origin;
  2. function getStateClass(state) {
  3. switch (state) {
  4. case 'running': return 'bg-success';
  5. case 'shut off': return 'bg-secondary';
  6. case 'paused': return 'bg-warning text-dark';
  7. case 'crashed': return 'bg-danger';
  8. default: return 'bg-light text-dark';
  9. }
  10. }
  11. async function loadISOs() {
  12. try {
  13. const response = await fetch(`${API_BASE}/isos`);
  14. const data = await response.json();
  15. const tbody = document.getElementById('isoTableBody');
  16. tbody.innerHTML = '';
  17. data.isos.forEach(iso => {
  18. const row = document.createElement('tr');
  19. row.innerHTML = `
  20. <td>${iso.name}</td>
  21. <td>
  22. <button class="btn btn-sm btn-danger" onclick="deleteISO('${iso.name}')">Delete</button>
  23. </td>
  24. `;
  25. tbody.appendChild(row);
  26. });
  27. } catch (error) {
  28. console.error('Error loading ISOs:', error);
  29. alert('Error loading ISOs');
  30. }
  31. }
  32. async function deleteISO(name) {
  33. if (confirm(`Delete ISO ${name}?`)) {
  34. try {
  35. const response = await fetch(`${API_BASE}/isos/${name}`, { method: 'DELETE' });
  36. const result = await response.json();
  37. if (response.ok) {
  38. alert(result.message);
  39. loadISOs();
  40. loadISOsForSelect(); // Refresh the select
  41. } else {
  42. alert(result.error);
  43. }
  44. } catch (error) {
  45. console.error('Error deleting ISO:', error);
  46. alert('Error deleting ISO');
  47. }
  48. }
  49. }
  50. async function loadISOsForSelect() {
  51. try {
  52. const response = await fetch(`${API_BASE}/isos`);
  53. const data = await response.json();
  54. const select = document.getElementById('iso');
  55. select.innerHTML = '<option value="">Select ISO</option>';
  56. data.isos.forEach(iso => {
  57. select.innerHTML += `<option value="${iso.path}">${iso.name}</option>`;
  58. });
  59. } catch (error) {
  60. console.error('Error loading ISOs:', error);
  61. }
  62. }
  63. /* Load VMs and populate the table */
  64. async function loadVMs() {
  65. try {
  66. const response = await fetch(`${API_BASE}/vms`);
  67. const data = await response.json();
  68. const tbody = document.getElementById('vmTableBody');
  69. tbody.innerHTML = '';
  70. const select = document.getElementById('bootVM');
  71. select.innerHTML = '<option value="">Select VM</option>';
  72. data.vms.forEach(vm => {
  73. const row = document.createElement('tr');
  74. row.innerHTML = `
  75. <td>${vm.id}</td>
  76. <td>${vm.name}</td>
  77. <td><span class="badge ${getStateClass(vm.state)}">${vm.state}</span></td>
  78. <td>
  79. <button class="btn btn-sm btn-success" onclick="startVM('${vm.name}')">Lanzar</button>
  80. <button class="btn btn-sm btn-warning" onclick="stopVM('${vm.name}')">Stop</button>
  81. <button class="btn btn-sm btn-danger" onclick="deleteVM('${vm.name}')">Delete</button>
  82. ${vm.vnc_port ? `<button class="btn btn-sm btn-info" onclick="openVNC('${vm.name}')">Console</button>` : ''}
  83. </td>
  84. `;
  85. tbody.appendChild(row);
  86. select.innerHTML += `<option value="${vm.name}">${vm.name}</option>`;
  87. });
  88. loadISOsForSelect(); // Load ISOs after loading VMs
  89. } catch (error) {
  90. console.error('Error loading VMs:', error);
  91. alert('Error loading VMs');
  92. }
  93. }
  94. async function startVM(name) {
  95. try {
  96. await fetch(`${API_BASE}/vms/${name}/start`);
  97. loadVMs();
  98. } catch (error) {
  99. console.error('Error starting VM:', error);
  100. alert('Error starting VM');
  101. }
  102. }
  103. async function stopVM(name) {
  104. try {
  105. await fetch(`${API_BASE}/vms/${name}/stop`);
  106. loadVMs();
  107. } catch (error) {
  108. console.error('Error stopping VM:', error);
  109. alert('Error stopping VM');
  110. }
  111. }
  112. async function deleteVM(name) {
  113. if (confirm(`Delete VM ${name}?`)) {
  114. try {
  115. await fetch(`${API_BASE}/vms/${name}`, { method: 'DELETE' });
  116. loadVMs();
  117. } catch (error) {
  118. console.error('Error deleting VM:', error);
  119. alert('Error deleting VM');
  120. }
  121. }
  122. }
  123. function openVNC(vm_name) {
  124. fetch(`${API_BASE}/console/${vm_name}`)
  125. .then(response => response.json())
  126. .then(data => {
  127. if (data.url) {
  128. window.open(data.url);
  129. } else {
  130. alert(data.error || 'Error opening console');
  131. }
  132. })
  133. .catch(error => {
  134. console.error('Error:', error);
  135. alert('Error opening console');
  136. });
  137. }
  138. document.getElementById('createVMForm').addEventListener('submit', async (e) => {
  139. e.preventDefault();
  140. const name = document.getElementById('name').value;
  141. const memory = document.getElementById('memory').value;
  142. const disk_size = document.getElementById('disk_size').value;
  143. const iso = document.getElementById('iso').value;
  144. try {
  145. const response = await fetch(`${API_BASE}/vms?name=${name}&memory=${memory}&disk_size=${disk_size}&iso=${iso}`, {
  146. method: 'POST'
  147. });
  148. let result;
  149. try {
  150. result = await response.json();
  151. } catch {
  152. result = { error: 'Unknown error' };
  153. }
  154. if (response.ok) {
  155. alert(result.message);
  156. loadVMs();
  157. document.getElementById('createVMForm').reset();
  158. } else {
  159. alert(result.error || 'Error creating VM');
  160. }
  161. } catch (error) {
  162. console.error('Error creating VM:', error);
  163. alert('Error creating VM');
  164. }
  165. });
  166. document.getElementById('setBootOrderForm').addEventListener('submit', async (e) => {
  167. e.preventDefault();
  168. const vm_name = document.getElementById('bootVM').value;
  169. const boot_order_str = document.getElementById('bootOrder').value;
  170. const order = boot_order_str.split(',').map(s => s.trim());
  171. try {
  172. const response = await fetch(`${API_BASE}/vms/${vm_name}/boot-order`, {
  173. method: 'PUT',
  174. headers: {
  175. 'Content-Type': 'application/json'
  176. },
  177. body: JSON.stringify({ order: order })
  178. });
  179. const result = await response.json();
  180. if (response.ok) {
  181. alert(result.message);
  182. loadVMs();
  183. document.getElementById('setBootOrderForm').reset();
  184. } else {
  185. alert(result.error);
  186. }
  187. } catch (error) {
  188. console.error('Error setting boot order:', error);
  189. alert('Error setting boot order');
  190. }
  191. });
  192. document.getElementById('uploadIsoForm').addEventListener('submit', async (e) => {
  193. e.preventDefault();
  194. const fileInput = document.getElementById('isoFile');
  195. const file = fileInput.files[0];
  196. if (!file) {
  197. alert('Please select a file');
  198. return;
  199. }
  200. const formData = new FormData();
  201. formData.append('file', file);
  202. try {
  203. const response = await fetch(`${API_BASE}/upload-iso`, {
  204. method: 'POST',
  205. body: formData
  206. });
  207. const result = await response.json();
  208. if (response.ok) {
  209. alert(result.message);
  210. loadISOsForSelect(); // Refresh ISO list
  211. document.getElementById('uploadIsoForm').reset();
  212. } else {
  213. alert(result.error || 'Error uploading ISO');
  214. }
  215. } catch (error) {
  216. console.error('Error uploading ISO:', error);
  217. alert('Error uploading ISO');
  218. }
  219. });
  220. // Load VMs on page load
  221. loadVMs();
  222. loadISOs();