/** * Service Verify Command * Re-verify a container service connection */ import { extractTemplateFilename } from '../../api-clients/proxmox'; import { askConfirm, withInterviewSession } from '../../services/bus-interview'; import { type ProxmoxCredentials, getContainerServiceByServiceId, getServiceCredentials, verifyContainerService, } from '../../services/container-service'; import { celiloIntro, celiloOutro } from '../prompts'; import type { CommandResult } from '../types'; import { runApplianceDownload } from './proxmox-template-selection'; /** * Handle service verify command * * @param args - Command arguments: [serviceId] * @param flags - Command flags */ export async function handleServiceVerify( args: string[], _flags: Record = {}, ): Promise { try { celiloIntro('Verify Container Service'); const serviceId = args[0]; if (!serviceId) { return { success: false, error: 'Service ID is required\n\nUsage: celilo service verify ', }; } // Look up service by ID const service = await getContainerServiceByServiceId(serviceId); if (!service) { return { success: false, error: `Service not found: ${serviceId}\n\nRun 'celilo service list' to see available services.`, }; } console.log(`\nVerifying service: ${service.name} (${service.providerName})`); console.log('Testing connection...\n'); // Verify the service const { service: updatedService, testResult } = await verifyContainerService(service.id); if (testResult.success) { console.log(`✓ ${testResult.message}`); console.log(`\nService verified at: ${updatedService.verifiedAt?.toISOString()}`); celiloOutro( `Service '${service.serviceId}' (${service.name}) verified successfully!\n\nThe service is now ready to use.`, ); return { success: true, message: `Verified service: ${service.serviceId}`, }; } console.log('✗ Connection test failed\n'); console.log(testResult.message); // Check if error is about missing permissions (Proxmox) if ( service.providerName === 'proxmox' && testResult.message && testResult.message.includes('missing required permissions') ) { celiloOutro( `Service '${service.serviceId}' verification failed due to insufficient API token permissions.\n\nSee instructions above to fix permissions, then try again:\n celilo service verify ${service.serviceId}`, ); return { success: false, error: 'API token has insufficient permissions (see details above)', }; } // Check if error is about missing template if ( service.providerName === 'proxmox' && testResult.message && testResult.message.includes('Template') && testResult.message.includes('not found') ) { const shouldDownload = await withInterviewSession(() => askConfirm({ scope: `service:${service.serviceId}`, key: 'download_template', message: 'Download missing template now?', defaultValue: true, }), ); if (shouldDownload) { try { const credentials = (await getServiceCredentials(service.id)) as ProxmoxCredentials; const providerConfig = service.providerConfig as { default_target_node: string; lxc_template: string; storage: string; }; const templateFilename = extractTemplateFilename(providerConfig.lxc_template); const templateStorage = providerConfig.lxc_template.split(':')[0] || 'local'; // The saved volid was the canonical filename when the service was // created; if Proxmox refreshed the revision since then, this download // will fail with `started-failed` and the user can `service reconfigure` // to pick a fresh filename from the catalog. const outcome = await runApplianceDownload({ credentials, targetNode: providerConfig.default_target_node, templateStorage, templateFilename, }); if (!outcome.ready) { const detail = outcome.reason === 'task-failed' ? `pveam download exited with status: ${outcome.exitStatus ?? 'unknown'}\n\nThis usually means the saved template revision is no longer available on Proxmox's mirror.` : outcome.reason === 'started-failed' ? `Proxmox rejected the download request: ${outcome.startError ?? 'unknown error'}\n\nThis usually means the saved template name does not match Proxmox's current catalog.` : 'Template download did not complete in time. The Proxmox host may have slow internet or connectivity issues.'; return { success: false, error: `${detail}\n\nTroubleshooting:\n 1. Pick a fresh template version: celilo service reconfigure ${service.serviceId}\n 2. SSH into your Proxmox host and run: pveam update && pveam download ${templateStorage} ${templateFilename}\n 3. Check DNS and firewall settings on the Proxmox host`, }; } console.log('\nRetrying verification...'); const retryResult = await verifyContainerService(service.id); if (retryResult.testResult.success) { console.log(`✓ ${retryResult.testResult.message}`); celiloOutro( `Service '${service.serviceId}' (${service.name}) verified successfully!\n\nThe service is now ready to use.`, ); return { success: true, message: `Verified service: ${service.serviceId}`, }; } return { success: false, error: `Verification still failed: ${retryResult.testResult.message}`, }; } catch (error) { return { success: false, error: `Template download failed: ${error instanceof Error ? error.message : String(error)}`, }; } } } celiloOutro( `Service '${service.serviceId}' verification failed.\n\nPlease check:\n - Network connectivity\n - API credentials\n - Service configuration\n\nThen try again: celilo service verify ${service.serviceId}`, ); return { success: false, error: 'Service verification failed (see details above)', }; } catch (error) { return { success: false, error: `Failed to verify service: ${error instanceof Error ? error.message : String(error)}`, }; } }