app.js 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279
  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. */
  95. async function loadVMsCard() {
  96. try {
  97. const response = await fetch(`${API_BASE}/vms`);
  98. const data = await response.json();
  99. const columna = document.getElementById('vmCard');
  100. columna.innerHTML = '';
  101. // const select = document.getElementById('bootVM');
  102. //select.innerHTML = '<option value="">Select VM</option>';
  103. data.vms.forEach(vm => {
  104. const card = document.createElement('div');
  105. card.className = 'card';
  106. card.style.width = '18rem';
  107. const cardbody = document.createElement('div');
  108. cardbody.className = 'card-body';
  109. card.appendChild(cardbody);
  110. columna.appendChild(card);
  111. cardbody.innerHTML = `
  112. <h6>${vm.id} - ${vm.name} <span class="badge ${getStateClass(vm.state)}">${vm.state}</span></h6>
  113. <button class="btn btn-sm btn-success" onclick="startVM('${vm.name}')">Lanzar</button>
  114. <button class="btn btn-sm btn-warning" onclick="stopVM('${vm.name}')">Stop</button>
  115. <button class="btn btn-sm btn-danger" onclick="deleteVM('${vm.name}')">Delete</button>
  116. ${vm.vnc_port ? `<button class="btn btn-sm btn-info" onclick="openVNC('${vm.name}')">Console</button>` : ''}
  117. `;
  118. card.appendChild(cardbody);
  119. //select.innerHTML += `<option value="${vm.name}">${vm.name}</option>`;
  120. });
  121. //loadISOsForSelect(); // Load ISOs after loading VMs
  122. } catch (error) {
  123. console.error('Error loading VMs:', error);
  124. alert('Error loading VMs');
  125. }
  126. }
  127. async function startVM(name) {
  128. try {
  129. await fetch(`${API_BASE}/vms/${name}/start`);
  130. loadVMs();
  131. } catch (error) {
  132. console.error('Error starting VM:', error);
  133. alert('Error starting VM');
  134. }
  135. }
  136. async function stopVM(name) {
  137. try {
  138. await fetch(`${API_BASE}/vms/${name}/stop`);
  139. loadVMs();
  140. } catch (error) {
  141. console.error('Error stopping VM:', error);
  142. alert('Error stopping VM');
  143. }
  144. }
  145. async function deleteVM(name) {
  146. if (confirm(`Delete VM ${name}?`)) {
  147. try {
  148. await fetch(`${API_BASE}/vms/${name}`, { method: 'DELETE' });
  149. loadVMs();
  150. } catch (error) {
  151. console.error('Error deleting VM:', error);
  152. alert('Error deleting VM');
  153. }
  154. }
  155. }
  156. function openVNC(vm_name) {
  157. fetch(`${API_BASE}/console/${vm_name}`)
  158. .then(response => response.json())
  159. .then(data => {
  160. if (data.url) {
  161. window.open(data.url);
  162. } else {
  163. alert(data.error || 'Error opening console');
  164. }
  165. })
  166. .catch(error => {
  167. console.error('Error:', error);
  168. alert('Error opening console');
  169. });
  170. }
  171. document.getElementById('createVMForm').addEventListener('submit', async (e) => {
  172. e.preventDefault();
  173. const name = document.getElementById('name').value;
  174. const memory = document.getElementById('memory').value;
  175. const disk_size = document.getElementById('disk_size').value;
  176. const iso = document.getElementById('iso').value;
  177. try {
  178. const response = await fetch(`${API_BASE}/vms?name=${name}&memory=${memory}&disk_size=${disk_size}&iso=${iso}`, {
  179. method: 'POST'
  180. });
  181. let result;
  182. try {
  183. result = await response.json();
  184. } catch {
  185. result = { error: 'Unknown error' };
  186. }
  187. if (response.ok) {
  188. alert(result.message);
  189. loadVMs();
  190. document.getElementById('createVMForm').reset();
  191. } else {
  192. alert(result.error || 'Error creating VM');
  193. }
  194. } catch (error) {
  195. console.error('Error creating VM:', error);
  196. alert('Error creating VM');
  197. }
  198. });
  199. document.getElementById('setBootOrderForm').addEventListener('submit', async (e) => {
  200. e.preventDefault();
  201. const vm_name = document.getElementById('bootVM').value;
  202. const boot_order_str = document.getElementById('bootOrder').value;
  203. const order = boot_order_str.split(',').map(s => s.trim());
  204. try {
  205. const response = await fetch(`${API_BASE}/vms/${vm_name}/boot-order`, {
  206. method: 'PUT',
  207. headers: {
  208. 'Content-Type': 'application/json'
  209. },
  210. body: JSON.stringify({ order: order })
  211. });
  212. const result = await response.json();
  213. if (response.ok) {
  214. alert(result.message);
  215. loadVMs();
  216. document.getElementById('setBootOrderForm').reset();
  217. } else {
  218. alert(result.error);
  219. }
  220. } catch (error) {
  221. console.error('Error setting boot order:', error);
  222. alert('Error setting boot order');
  223. }
  224. });
  225. document.getElementById('uploadIsoForm').addEventListener('submit', async (e) => {
  226. e.preventDefault();
  227. const fileInput = document.getElementById('isoFile');
  228. const file = fileInput.files[0];
  229. if (!file) {
  230. alert('Please select a file');
  231. return;
  232. }
  233. const formData = new FormData();
  234. formData.append('file', file);
  235. try {
  236. const response = await fetch(`${API_BASE}/upload-iso`, {
  237. method: 'POST',
  238. body: formData
  239. });
  240. const result = await response.json();
  241. if (response.ok) {
  242. alert(result.message);
  243. loadISOsForSelect(); // Refresh ISO list
  244. document.getElementById('uploadIsoForm').reset();
  245. } else {
  246. alert(result.error || 'Error uploading ISO');
  247. }
  248. } catch (error) {
  249. console.error('Error uploading ISO:', error);
  250. alert('Error uploading ISO');
  251. }
  252. });
  253. // Load VMs on page load
  254. //loadVMs();
  255. loadVMsCard();
  256. loadISOs();