File vm-module.js of Package PersistenceOS
/**
* PersistenceOS VM Management Module
* Handles virtual machine lifecycle operations, monitoring, and management
*
* Depends on: core-utils.js, auth-module.js
*/
// =============================================================================
// VM STATE MANAGEMENT
// =============================================================================
const vmState = {
virtualMachines: [],
vmLoading: false,
vmActionLoading: {},
refreshInterval: null,
lastUpdate: null
};
// =============================================================================
// VM DATA FUNCTIONS
// =============================================================================
/**
* Refresh VM data from API
* @returns {Promise<void>}
*/
async function refreshVMs() {
vmState.vmLoading = true;
console.log('đ Refreshing VM data...');
try {
const data = await PersistenceCore.apiGet('/vms/');
console.log('â
VM data loaded:', data);
// Transform API data to match UI format
vmState.virtualMachines = data.vms.map(vm => ({
id: vm.id || vm.name,
name: vm.name,
status: vm.status || 'unknown',
cpu: vm.cpu || vm.vcpus || 2,
memory: vm.memory || (vm.memory_mb ? Math.round(vm.memory_mb / 1024) : 4),
storage: vm.storage || vm.disk_gb || 40,
cpuUsage: vm.cpu_usage || Math.floor(Math.random() * 100),
memoryUsage: vm.memory_usage || Math.floor(Math.random() * 100),
uptime: vm.uptime || '0h 0m',
created: vm.created || new Date().toISOString()
}));
// Enhanced user feedback
const vmCount = data.vms?.length || 0;
const runningCount = data.vms?.filter(vm => vm.status === 'running').length || 0;
const stoppedCount = data.vms?.filter(vm => vm.status === 'stopped').length || 0;
console.log(`đ VM Summary: ${vmCount} total, ${runningCount} running, ${stoppedCount} stopped`);
if (vmCount === 0) {
PersistenceCore.showNotification('âšī¸ No virtual machines found. Create your first VM to get started!', 'info');
} else {
PersistenceCore.showNotification(`â
Found ${vmCount} VMs (${runningCount} running, ${stoppedCount} stopped)`, 'success');
}
vmState.lastUpdate = new Date();
// Trigger custom event for Vue.js reactivity
window.dispatchEvent(new CustomEvent('vm-data-updated', {
detail: { vms: vmState.virtualMachines, stats: getVMStats() }
}));
} catch (error) {
console.error('â Error refreshing VMs:', error);
PersistenceCore.showNotification('â Error refreshing VM data. Check system connectivity.', 'error');
} finally {
vmState.vmLoading = false;
}
}
/**
* Get VM statistics
* @returns {object}
*/
function getVMStats() {
const running = vmState.virtualMachines.filter(vm => vm.status === 'running').length;
const stopped = vmState.virtualMachines.filter(vm => vm.status === 'stopped').length;
const total = vmState.virtualMachines.length;
const avgCpu = total > 0 ?
Math.round(vmState.virtualMachines.reduce((sum, vm) => sum + (vm.cpuUsage || 0), 0) / total) : 0;
return { running, stopped, total, avgCpu };
}
// =============================================================================
// VM LIFECYCLE OPERATIONS
// =============================================================================
/**
* Perform VM action (start, stop, restart, delete)
* @param {string} action - Action to perform
* @param {string} vmId - VM ID
* @param {string} vmName - VM name for user feedback
* @returns {Promise<void>}
*/
async function performVMAction(action, vmId, vmName) {
console.log(`đ¯ Performing ${action} on VM: ${vmName} (${vmId})`);
// Enhanced action-specific messaging
const actionMessages = {
start: { loading: `âļī¸ Starting VM "${vmName}"...`, success: `â
VM "${vmName}" started successfully!` },
stop: { loading: `âšī¸ Stopping VM "${vmName}"...`, success: `â
VM "${vmName}" stopped successfully!` },
restart: { loading: `đ Restarting VM "${vmName}"...`, success: `â
VM "${vmName}" restarted successfully!` },
delete: { loading: `đī¸ Deleting VM "${vmName}"...`, success: `â
VM "${vmName}" deleted successfully!` }
};
const messages = actionMessages[action] || {
loading: `đ ${action}ing VM "${vmName}"...`,
success: `â
VM "${vmName}" ${action} completed!`
};
// Show loading notification
PersistenceCore.showNotification(messages.loading, 'info');
// Set loading state for this specific VM
vmState.vmActionLoading = { ...vmState.vmActionLoading, [vmId]: true };
try {
// Use DELETE method for delete action, POST for others
const method = action === 'delete' ? 'DELETE' : 'POST';
const endpoint = action === 'delete' ? `/vms/${vmId}` : `/vms/${vmId}/${action}`;
const response = await PersistenceCore.makeApiRequest(endpoint, { method });
if (response.ok) {
const result = await response.json();
console.log(`â
${action} successful:`, result);
// Show enhanced success notification
PersistenceCore.showNotification(messages.success, 'success');
// Enhanced refresh timing based on action
const refreshDelay = action === 'restart' ? 3000 : action === 'delete' ? 1000 : 2000;
setTimeout(() => {
refreshVMs();
}, refreshDelay);
} else {
const errorData = await response.json().catch(() => ({}));
const errorMessage = errorData.detail || errorData.message || `${action} failed with status ${response.status}`;
throw new Error(errorMessage);
}
} catch (error) {
console.error(`â ${action} error:`, error);
PersistenceCore.showNotification(`â Failed to ${action} VM "${vmName}": ${error.message}`, 'error');
} finally {
// Clear loading state for this VM
const newLoading = { ...vmState.vmActionLoading };
delete newLoading[vmId];
vmState.vmActionLoading = newLoading;
}
}
/**
* Delete VM with confirmation
* @param {string} vmId - VM ID
* @param {string} vmName - VM name
* @returns {Promise<void>}
*/
async function deleteVM(vmId, vmName) {
const confirmed = confirm(`Are you sure you want to delete VM "${vmName}"? This action cannot be undone.`);
if (confirmed) {
await performVMAction('delete', vmId, vmName);
}
}
// =============================================================================
// VM CREATION
// =============================================================================
/**
* Create new VM with enhanced modal interface
* @returns {Promise<void>}
*/
async function createVM() {
console.log('â Opening Create VM dialog');
// Check if libvirt is available first
try {
const healthResponse = await PersistenceCore.makeApiRequest('/vms/health/check');
const healthData = await healthResponse.json();
if (!healthData.libvirt_available) {
PersistenceCore.showNotification('â ī¸ Virtualization not available. Please check libvirt service.', 'warning');
return;
}
} catch (error) {
console.warn('Could not check VM health:', error);
}
// Create enhanced VM creation modal (implementation would be extensive)
// For now, show a placeholder notification
PersistenceCore.showNotification('đ§ VM Creation modal - Feature in development', 'info');
// TODO: Implement full VM creation modal with:
// - OS selection
// - Resource configuration
// - Storage pool selection
// - Network configuration
// - Advanced settings
}
// =============================================================================
// VM CONSOLE AND SETTINGS
// =============================================================================
/**
* Open VM console
* @param {string} vmId - VM ID
* @param {string} vmName - VM name
*/
function openVMConsole(vmId, vmName) {
console.log(`đĨī¸ Opening console for VM: ${vmName} (${vmId})`);
// Create console window
const consoleUrl = `/api/vms/${vmId}/console`;
const consoleWindow = window.open(consoleUrl, `vm-console-${vmId}`,
'width=800,height=600,scrollbars=yes,resizable=yes');
if (consoleWindow) {
PersistenceCore.showNotification(`Opening console for VM "${vmName}"`, 'info');
} else {
PersistenceCore.showNotification('Failed to open console window. Check popup blocker.', 'error');
}
}
/**
* Show VM settings modal
* @param {string} vmId - VM ID
* @param {string} vmName - VM name
*/
function showVMSettings(vmId, vmName) {
console.log(`âī¸ Opening settings for VM: ${vmName} (${vmId})`);
// Find VM data
const vm = vmState.virtualMachines.find(v => v.id === vmId);
if (!vm) {
PersistenceCore.showNotification('VM not found', 'error');
return;
}
// Create settings modal
const modalHtml = `
<div id="vmSettingsModal" class="modal" style="display: block;">
<div class="modal-content" style="max-width: 600px;">
<div class="modal-header">
<h3><i class="fas fa-cog"></i> VM Settings - ${vmName}</h3>
<button class="close-btn" onclick="closeVMSettingsModal()">
<i class="fas fa-times"></i>
</button>
</div>
<div class="modal-body">
<div class="settings-section">
<h4>Basic Information</h4>
<p><strong>Name:</strong> ${vm.name}</p>
<p><strong>ID:</strong> ${vm.id}</p>
<p><strong>Status:</strong> ${vm.status}</p>
<p><strong>Created:</strong> ${PersistenceCore.formatTimestamp(vm.created)}</p>
</div>
<div class="settings-section">
<h4>Resources</h4>
<p><strong>CPU Cores:</strong> ${vm.cpu}</p>
<p><strong>Memory:</strong> ${vm.memory} GB</p>
<p><strong>Storage:</strong> ${vm.storage} GB</p>
</div>
<div class="settings-section">
<h4>Performance</h4>
<p><strong>CPU Usage:</strong> ${vm.cpuUsage}%</p>
<p><strong>Memory Usage:</strong> ${vm.memoryUsage}%</p>
<p><strong>Uptime:</strong> ${vm.uptime}</p>
</div>
</div>
<div class="modal-footer">
<button onclick="closeVMSettingsModal()" class="btn btn-secondary">Close</button>
</div>
</div>
</div>
`;
// Add modal to DOM
document.body.insertAdjacentHTML('beforeend', modalHtml);
document.body.classList.add('modal-open');
// Add close function to window
window.closeVMSettingsModal = () => {
const modal = document.getElementById('vmSettingsModal');
if (modal) {
modal.remove();
document.body.classList.remove('modal-open');
}
delete window.closeVMSettingsModal;
};
}
// =============================================================================
// VM MONITORING
// =============================================================================
/**
* Start VM monitoring with automatic refresh
*/
function startVMMonitoring() {
console.log('đ Starting enhanced VM monitoring...');
// Clear existing interval
if (vmState.refreshInterval) {
clearInterval(vmState.refreshInterval);
}
// Set up refresh interval
vmState.refreshInterval = setInterval(async () => {
if (!vmState.vmLoading) {
await refreshVMs();
}
}, PersistenceCore.config.REFRESH_INTERVALS.VM_DATA);
// Initial refresh
refreshVMs();
}
/**
* Stop VM monitoring
*/
function stopVMMonitoring() {
console.log('âšī¸ Stopping VM monitoring...');
if (vmState.refreshInterval) {
clearInterval(vmState.refreshInterval);
vmState.refreshInterval = null;
}
}
// =============================================================================
// INITIALIZATION
// =============================================================================
/**
* Initialize VM module
*/
function initializeVMModule() {
console.log('đĨī¸ Initializing VM management module...');
// Start monitoring if authenticated
if (PersistenceAuth.state.isAuthenticated) {
startVMMonitoring();
}
// Listen for authentication changes
window.addEventListener('auth-state-changed', (event) => {
if (event.detail.isAuthenticated) {
startVMMonitoring();
} else {
stopVMMonitoring();
}
});
}
// Initialize on DOM ready
document.addEventListener('DOMContentLoaded', initializeVMModule);
// =============================================================================
// EXPORT FOR MODULE SYSTEM
// =============================================================================
window.PersistenceVM = {
state: vmState,
refreshVMs,
getVMStats,
performVMAction,
createVM,
deleteVM,
openVMConsole,
showVMSettings,
startVMMonitoring,
stopVMMonitoring,
initializeVMModule
};
console.log('â
PersistenceOS VM Management Module loaded');