diff --git a/api/src/core/modules/vms/get-domains.ts b/api/src/core/modules/vms/get-domains.ts index 425431f40..5a831d86b 100644 --- a/api/src/core/modules/vms/get-domains.ts +++ b/api/src/core/modules/vms/get-domains.ts @@ -1,8 +1,8 @@ -import { ConnectListAllDomainsFlags } from '@vmngr/libvirt'; -import { getHypervisor } from '@app/core/utils/vms/get-hypervisor'; -import { VmState, type VmDomain } from '@app/graphql/generated/api/types'; import { GraphQLError } from 'graphql'; +import type { VmDomain } from '@app/graphql/generated/api/types'; +import { VmState } from '@app/graphql/generated/api/types'; + const states = { 0: 'NOSTATE', 1: 'RUNNING', @@ -17,10 +17,11 @@ const states = { /** * Get vm domains. */ -export const getDomains =async () => { - +export const getDomains = async () => { + const { ConnectListAllDomainsFlags } = await import('@vmngr/libvirt'); + const { UnraidHypervisor } = await import('@app/core/utils/vms/get-hypervisor'); try { - const hypervisor = await getHypervisor(); + const hypervisor = await UnraidHypervisor.getInstance().getHypervisor(); if (!hypervisor) { throw new GraphQLError('VMs Disabled'); } @@ -30,9 +31,7 @@ export const getDomains =async () => { ); const autoStartDomainNames = await Promise.all( - autoStartDomains.map(async (domain) => - hypervisor.domainGetName(domain) - ) + autoStartDomains.map(async (domain) => hypervisor.domainGetName(domain)) ); // Get all domains @@ -53,9 +52,11 @@ export const getDomains =async () => { }) ); - return resolvedDomains; + return resolvedDomains; } catch (error: unknown) { // If we hit an error expect libvirt to be offline - throw new GraphQLError(`Failed to fetch domains with error: ${error instanceof Error ? error.message : 'Unknown Error'}`); + throw new GraphQLError( + `Failed to fetch domains with error: ${error instanceof Error ? error.message : 'Unknown Error'}` + ); } }; diff --git a/api/src/core/utils/vms/get-hypervisor.ts b/api/src/core/utils/vms/get-hypervisor.ts index bff5c020a..6b338445b 100644 --- a/api/src/core/utils/vms/get-hypervisor.ts +++ b/api/src/core/utils/vms/get-hypervisor.ts @@ -1,13 +1,12 @@ -import { access } from 'fs/promises'; import { constants } from 'fs'; +import { access } from 'fs/promises'; + +import type { Hypervisor as HypervisorType } from '@vmngr/libvirt'; -import { Hypervisor } from '@vmngr/libvirt'; import { libvirtLogger } from '@app/core/log'; const uri = process.env.LIBVIRT_URI ?? 'qemu:///system'; -let hypervisor: Hypervisor | null; - const libvirtPid = '/var/run/libvirt/libvirtd.pid'; const isLibvirtRunning = async (): Promise => { @@ -19,29 +18,40 @@ const isLibvirtRunning = async (): Promise => { } }; -export const getHypervisor = async (): Promise => { - // Return hypervisor if it's already connected - const running = await isLibvirtRunning(); +export class UnraidHypervisor { + private static instance: UnraidHypervisor | null = null; + private hypervisor: HypervisorType | null = null; + private constructor() {} - if (hypervisor && running) { - return hypervisor; + public static getInstance(): UnraidHypervisor { + if (this.instance === null) { + this.instance = new UnraidHypervisor(); + } + return this.instance; } - if (!running) { - hypervisor = null; - throw new Error('Libvirt is not running'); - } + public async getHypervisor(): Promise { + // Return hypervisor if it's already connected + const running = await isLibvirtRunning(); - hypervisor = new Hypervisor({ uri }); - await hypervisor.connectOpen().catch((error: unknown) => { - libvirtLogger.error( - `Failed starting VM hypervisor connection with "${ - (error as Error).message - }"` - ); + if (this.hypervisor && running) { + return this.hypervisor; + } - throw error; - }); + if (!running) { + this.hypervisor = null; + throw new Error('Libvirt is not running'); + } + const { Hypervisor } = await import('@vmngr/libvirt'); + this.hypervisor = new Hypervisor({ uri }); + await this.hypervisor.connectOpen().catch((error: unknown) => { + libvirtLogger.error( + `Failed starting VM hypervisor connection with "${(error as Error).message}"` + ); - return hypervisor; -}; + throw error; + }); + + return this.hypervisor; + } +} diff --git a/api/src/core/utils/vms/parse-domain.ts b/api/src/core/utils/vms/parse-domain.ts index c63f88b78..ce0c8a0b0 100644 --- a/api/src/core/utils/vms/parse-domain.ts +++ b/api/src/core/utils/vms/parse-domain.ts @@ -1,5 +1,4 @@ import { type Domain } from '@app/core/types'; -import { getHypervisor } from '@app/core/utils/vms/get-hypervisor'; export type DomainLookupType = 'id' | 'uuid' | 'name'; @@ -21,7 +20,8 @@ export const parseDomain = async (type: DomainLookupType, id: string): Promise