import { Account, errors, Notification } from "@kumori/aurora-interfaces"; import { initializeGlobalWebSocketClient, getWebSocketStatus, makeGlobalWebSocketRequest, } from "../websocket-manager"; import { eventHelper } from "../backend-handler"; type Security = string; function extractErrorInfo(error: unknown): { code: string; message: string } { if ((error as any)?.isTimeout) { return { code: "timeout", message: "The request is taking too long, but it does not mean it failed. If you need more help, please contact support.", }; } const err = (error as any)?.error; return { code: err?.code ?? "unknown_error", message: err?.content ?? err?.message ?? "Unknown error", }; } export const createAccount = async (account: Account, security: Security) => { try { await initializeGlobalWebSocketClient(security, "account", account.name); const status = getWebSocketStatus(); const providerName = account.cloudProvider?.name?.toLowerCase(); let accountBody; if (providerName === "aws") { accountBody = { tenant: account.tenant, account: account.name, provision_infrastructure: false, spec: { spec: { api: "aws", credentials: account.cloudProvider.password ? { admin_access_key: account.cloudProvider.username || "", admin_secret_key: account.cloudProvider.password || "", region: account.cloudProvider?.region || "", } : { method: "aws", aws: { region: account.cloudProvider?.region || "", aws_access_key_id: account.cloudProvider?.credentialId || "", aws_secret_access_key: account.cloudProvider?.credentialSecret || "", }, }, marks: { vcpu: { lowmark: account.usage.limit.cpu.min * 1000, highmark: account.usage.limit.cpu.max * 1000, unit: "m", }, memory: { lowmark: account.usage.limit.memory.min * 1000, highmark: account.usage.limit.memory.max * 1000, unit: "MB", }, vstorage: { lowmark: account.usage.limit.volatileStorage.min * 1000, highmark: account.usage.limit.volatileStorage.max * 1000, unit: "MB", }, nrstorage: { lowmark: account.usage.limit.nonReplicatedStorage.min * 1000, highmark: account.usage.limit.nonReplicatedStorage.max * 1000, unit: "MB", }, rstorage: { lowmark: account.usage.limit.persistentStorage.min * 1000, highmark: account.usage.limit.persistentStorage.max * 1000, unit: "MB", }, storage: { lowmark: account.usage.limit.storage.min * 1000, highmark: account.usage.limit.storage.max * 1000, unit: "MB", }, cost: { lowmark: account.usage.cost, highmark: account.usage.cost, unit: "EUR", }, nodes: { lowmark: account.nodes?.min || 0, highmark: account.nodes?.max || 0, unit: "", }, }, iaasconfig: { ...(account.flavors?.volatile?.[0] && { volatile: account.flavors.volatile[0], }), ...(account.flavors?.persistent?.[0] && { persistent: account.flavors.persistent[0], }), ...(account.flavors?.nonReplicated?.[0] && { nonreplicated: account.flavors.nonReplicated[0], }), ...(account.flavors?.small?.[0] && { smallVMFlavor: account.flavors?.small?.[0], }), ...(account.flavors?.medium?.[0] && { mediumVMFlavor: account.flavors.medium[0], }), }, }, meta: { labels: { additionalProp1: "string", additionalProp2: "string", additionalProp3: "string", }, }, }, }; } else if (providerName === "azure") { accountBody = { tenant: account.tenant, account: account.name, provision_infrastructure: false, spec: { spec: { api: "azure", credentials: account.cloudProvider.password ? { tenant_id: account.cloudProvider.tenantId || "", admin_client_id: account.cloudProvider.username || "", admin_client_secret: account.cloudProvider.password || "", subscription_id: account.cloudProvider.subscriptionId || "", region: account.cloudProvider?.region || "", } : { method: "azure", azure: { region: account.cloudProvider?.region || "", subscription_id: account.cloudProvider?.subscriptionId || "", tenant_id: account.cloudProvider?.tenantId || "", client_id: account.cloudProvider?.clientId || "", client_secret: account.cloudProvider?.clientSecret || "", }, }, marks: { vcpu: { lowmark: account.usage.limit.cpu.min * 1000, highmark: account.usage.limit.cpu.max * 1000, unit: "m", }, memory: { lowmark: account.usage.limit.memory.min * 1000, highmark: account.usage.limit.memory.max * 1000, unit: "MB", }, vstorage: { lowmark: account.usage.limit.volatileStorage.min * 1000, highmark: account.usage.limit.volatileStorage.max * 1000, unit: "MB", }, nrstorage: { lowmark: account.usage.limit.nonReplicatedStorage.min * 1000, highmark: account.usage.limit.nonReplicatedStorage.max * 1000, unit: "MB", }, rstorage: { lowmark: account.usage.limit.persistentStorage.min * 1000, highmark: account.usage.limit.persistentStorage.max * 1000, unit: "MB", }, storage: { lowmark: account.usage.limit.storage.min * 1000, highmark: account.usage.limit.storage.max * 1000, unit: "MB", }, cost: { lowmark: account.usage.cost, highmark: account.usage.cost, unit: "EUR", }, nodes: { lowmark: account.nodes?.min || 0, highmark: account.nodes?.max || 0, unit: "", }, }, iaasconfig: { ...(account.flavors?.volatile?.[0] && { volatile: account.flavors.volatile[0], }), ...(account.flavors?.persistent?.[0] && { persistent: account.flavors.persistent[0], }), ...(account.flavors?.nonReplicated?.[0] && { nonreplicated: account.flavors.nonReplicated[0], }), ...(account.flavors?.small?.[0] && { smallVMFlavor: account.flavors?.small?.[0], }), ...(account.flavors?.medium?.[0] && { mediumVMFlavor: account.flavors.medium[0], }), }, }, meta: { labels: { additionalProp1: "string", additionalProp2: "string", additionalProp3: "string", }, }, }, }; } else if (providerName === "ovh") { accountBody = { tenant: account.tenant, account: account.name, provision_infrastructure: false, spec: { spec: { api: providerName, credentials: account.cloudProvider.password ? { username: account.cloudProvider.username || "", password: account.cloudProvider.password || "", region: account.cloudProvider?.region || "", } : { method: providerName, openstack: { region_name: account.cloudProvider?.region || "", interface: account.cloudProvider?.interface || "", identity_api_version: Number( account.cloudProvider?.apiVersion || 3, ), auth_type: account.cloudProvider?.authType || "", auth: { auth_url: account.cloudProvider?.authUrl || "", application_credential_id: account.cloudProvider?.credentialId || "", application_credential_secret: account.cloudProvider?.credentialSecret || "", }, }, }, highlyAvailable: true, marks: { vcpu: { lowmark: account.usage.limit.cpu.min * 1000, highmark: account.usage.limit.cpu.max * 1000, unit: "m", }, memory: { lowmark: account.usage.limit.memory.min * 1000, highmark: account.usage.limit.memory.max * 1000, unit: "MB", }, vstorage: { lowmark: account.usage.limit.volatileStorage.min * 1000, highmark: account.usage.limit.volatileStorage.max * 1000, unit: "MB", }, nrstorage: { lowmark: account.usage.limit.nonReplicatedStorage.min * 1000, highmark: account.usage.limit.nonReplicatedStorage.max * 1000, unit: "MB", }, rstorage: { lowmark: account.usage.limit.persistentStorage.min * 1000, highmark: account.usage.limit.persistentStorage.max * 1000, unit: "MB", }, storage: { lowmark: account.usage.limit.storage.min * 1000, highmark: account.usage.limit.storage.max * 1000, unit: "MB", }, cost: { lowmark: account.usage.cost, highmark: account.usage.cost, unit: "EUR", }, nodes: { lowmark: account.nodes?.max || 0, highmark: account.nodes?.max || 0, unit: "", }, }, iaasconfig: { ...(account.flavors?.volatile?.[0] && { volatile: account.flavors.volatile[0], }), ...(account.flavors?.persistent?.[0] && { persistent: account.flavors.persistent[0], }), ...(account.flavors?.nonReplicated?.[0] && { nonreplicated: account.flavors.nonReplicated[0], }), ...(account.flavors?.small?.[0] && { smallVMFlavor: account.flavors?.small?.[0], }), ...(account.flavors?.medium?.[0] && { mediumVMFlavor: account.flavors.medium[0], }), }, }, meta: { labels: { additionalProp1: "string", additionalProp2: "string", additionalProp3: "string", }, }, }, }; } else if (providerName === "oasix") { accountBody = { tenant: account.tenant, account: account.name, provision_infrastructure: false, spec: { spec: { api: providerName, credentials: account.cloudProvider.password ? { username: account.cloudProvider.username || "", password: account.cloudProvider.password || "", region: account.cloudProvider?.region || "", domain: account.cloudProvider?.domain || "", project_name: account.cloudProvider?.project_name || "", } : { method: providerName, openstack: { region_name: account.cloudProvider?.region || "", interface: account.cloudProvider?.interface || "", identity_api_version: Number( account.cloudProvider?.apiVersion || 3, ), auth_type: account.cloudProvider?.authType || "", auth: { auth_url: account.cloudProvider?.authUrl || "", application_credential_id: account.cloudProvider?.credentialId || "", application_credential_secret: account.cloudProvider?.credentialSecret || "", }, }, }, highlyAvailable: true, marks: { vcpu: { lowmark: account.usage.limit.cpu.min * 1000, highmark: account.usage.limit.cpu.max * 1000, unit: "m", }, memory: { lowmark: account.usage.limit.memory.min * 1000, highmark: account.usage.limit.memory.max * 1000, unit: "MB", }, vstorage: { lowmark: account.usage.limit.volatileStorage.min * 1000, highmark: account.usage.limit.volatileStorage.max * 1000, unit: "MB", }, nrstorage: { lowmark: account.usage.limit.nonReplicatedStorage.min * 1000, highmark: account.usage.limit.nonReplicatedStorage.max * 1000, unit: "MB", }, rstorage: { lowmark: account.usage.limit.persistentStorage.min * 1000, highmark: account.usage.limit.persistentStorage.max * 1000, unit: "MB", }, storage: { lowmark: account.usage.limit.storage.min * 1000, highmark: account.usage.limit.storage.max * 1000, unit: "MB", }, cost: { lowmark: account.usage.cost, highmark: account.usage.cost, unit: "EUR", }, nodes: { lowmark: account.nodes?.max || 0, highmark: account.nodes?.max || 0, unit: "", }, }, iaasconfig: { ...(account.flavors?.volatile?.[0] && { volatile: account.flavors.volatile[0], }), ...(account.flavors?.persistent?.[0] && { persistent: account.flavors.persistent[0], }), ...(account.flavors?.nonReplicated?.[0] && { nonreplicated: account.flavors.nonReplicated[0], }), ...(account.flavors?.small?.[0] && { smallVMFlavor: account.flavors?.small?.[0], }), ...(account.flavors?.medium?.[0] && { mediumVMFlavor: account.flavors.medium[0], }), }, }, meta: { labels: { additionalProp1: "string", additionalProp2: "string", additionalProp3: "string", }, }, }, }; } else if (providerName === "cloudos") { accountBody = { tenant: account.tenant, account: account.name, provision_infrastructure: false, spec: { spec: { api: providerName, credentials: { method: providerName, openstack: { region_name: account.cloudProvider?.region || "", interface: account.cloudProvider?.interface || "", identity_api_version: Number( account.cloudProvider?.apiVersion || 3, ), auth_type: account.cloudProvider?.authType || "", auth: { auth_url: account.cloudProvider?.authUrl || "", application_credential_id: account.cloudProvider?.credentialId || "", application_credential_secret: account.cloudProvider?.credentialSecret || "", }, }, }, highlyAvailable: true, marks: { vcpu: { lowmark: account.usage.limit.cpu.min * 1000, highmark: account.usage.limit.cpu.max * 1000, unit: "m", }, memory: { lowmark: account.usage.limit.memory.min * 1000, highmark: account.usage.limit.memory.max * 1000, unit: "MB", }, vstorage: { lowmark: account.usage.limit.volatileStorage.min * 1000, highmark: account.usage.limit.volatileStorage.max * 1000, unit: "MB", }, nrstorage: { lowmark: account.usage.limit.nonReplicatedStorage.min * 1000, highmark: account.usage.limit.nonReplicatedStorage.max * 1000, unit: "MB", }, rstorage: { lowmark: account.usage.limit.persistentStorage.min * 1000, highmark: account.usage.limit.persistentStorage.max * 1000, unit: "MB", }, storage: { lowmark: account.usage.limit.storage.min * 1000, highmark: account.usage.limit.storage.max * 1000, unit: "MB", }, cost: { lowmark: account.usage.cost, highmark: account.usage.cost, unit: "EUR", }, nodes: { lowmark: account.nodes?.max || 0, highmark: account.nodes?.max || 0, unit: "", }, }, iaasconfig: { ...(account.flavors?.volatile?.[0] && { volatile: account.flavors.volatile[0], }), ...(account.flavors?.persistent?.[0] && { persistent: account.flavors.persistent[0], }), ...(account.flavors?.nonReplicated?.[0] && { nonreplicated: account.flavors.nonReplicated[0], }), ...(account.flavors?.small?.[0] && { smallVMFlavor: account.flavors?.small?.[0], }), ...(account.flavors?.medium?.[0] && { mediumVMFlavor: account.flavors.medium[0], }), }, }, meta: { labels: { additionalProp1: "string", additionalProp2: "string", additionalProp3: "string", }, }, }, }; } else if (providerName === "opennebula") { accountBody = { tenant: account.tenant, account: account.name, provision_infrastructure: false, spec: { spec: { api: providerName, credentials: { method: providerName, opennebula: { user: account.cloudProvider.username, password: account.cloudProvider.password, xmlrpc: account.cloudProvider.endpoint, }, }, highlyAvailable: true, marks: { vcpu: { lowmark: account.usage.limit.cpu.min * 1000, highmark: account.usage.limit.cpu.max * 1000, unit: "m", }, memory: { lowmark: account.usage.limit.memory.min * 1000, highmark: account.usage.limit.memory.max * 1000, unit: "MB", }, vstorage: { lowmark: account.usage.limit.volatileStorage.min * 1000, highmark: account.usage.limit.volatileStorage.max * 1000, unit: "MB", }, nrstorage: { lowmark: account.usage.limit.nonReplicatedStorage.min * 1000, highmark: account.usage.limit.nonReplicatedStorage.max * 1000, unit: "MB", }, rstorage: { lowmark: account.usage.limit.persistentStorage.min * 1000, highmark: account.usage.limit.persistentStorage.max * 1000, unit: "MB", }, storage: { lowmark: account.usage.limit.storage.min * 1000, highmark: account.usage.limit.storage.max * 1000, unit: "MB", }, cost: { lowmark: account.usage.cost, highmark: account.usage.cost, unit: "EUR", }, nodes: { lowmark: account.nodes?.max || 0, highmark: account.nodes?.max || 0, unit: "", }, }, iaasconfig: { ...(account.flavors?.volatile?.[0] && { volatile: account.flavors.volatile[0], }), ...(account.flavors?.persistent?.[0] && { persistent: account.flavors.persistent[0], }), ...(account.flavors?.nonReplicated?.[0] && { nonreplicated: account.flavors.nonReplicated[0], }), ...(account.flavors?.small?.[0] && { smallVMFlavor: account.flavors?.small?.[0], }), ...(account.flavors?.medium?.[0] && { mediumVMFlavor: account.flavors.medium[0], }), }, }, meta: { labels: { additionalProp1: "string", additionalProp2: "string", additionalProp3: "string", }, }, }, }; } else { throw new Error( `Unsupported cloud provider: ${providerName}. Supported providers are: ovh, aws, azure`, ); } const response = await makeGlobalWebSocketRequest( "account:create_account", accountBody, 30000, "CREATE", account.name, "account", account, ); const updatedAccount: Account = { ...account, status: "pending" }; eventHelper.account.publish.created(updatedAccount); return response; } catch (error) { console.error("Error creating account:", { error, errorMessage: error instanceof Error ? error.message : "Unknown error", account: account.name, tenant: account.tenant, provider: account.cloudProvider?.name, webSocketStatus: getWebSocketStatus(), }); const { code, message } = extractErrorInfo(error); const accountErrorNotification: Notification = { type: "error", subtype: errors.account.creationError.subtype, info_content: { code, message, }, date: Date.now().toString(), status: "unread", callToAction: false, data: { account: account.name, tenant: account.tenant, }, userError: true, }; eventHelper.notification.publish.creation(accountErrorNotification); throw error; } }; export const deleteAccount = async (account: Account, security: Security) => { try { await initializeGlobalWebSocketClient(security, "account", account.name); const providerName = account.cloudProvider?.name?.toLowerCase(); let payload = {}; if (!account.credentials) { payload = { tenant: account.tenant, account: account.name, delete: true, force: true, }; } else if (providerName === "ovh") { payload = { tenant: account.tenant, account: account.name, delete: true, force: true, spec: { credentials: { username: account.cloudProvider.username, password: account.cloudProvider.password, }, }, }; } else if (providerName === "oasix") { payload = { tenant: account.tenant, account: account.name, delete: true, force: true, spec: { credentials: { username: account.cloudProvider.username, password: account.cloudProvider.password, domain: account.cloudProvider.domain, project_name: account.cloudProvider.project_name || "", }, }, }; } else if (providerName === "aws") { payload = { tenant: account.tenant, account: account.name, delete: true, force: true, spec: { credentials: { admin_access_key: account.cloudProvider.username, admin_secret_key: account.cloudProvider.password, }, }, }; } else if (providerName === "azure") { payload = { tenant: account.tenant, account: account.name, delete: true, force: true, spec: { credentials: { admin_client_id: account.cloudProvider.username, admin_client_secret: account.cloudProvider.password, }, }, }; } const response = await makeGlobalWebSocketRequest( "account:cleanup_account", payload, 30000, "DELETE", account.name, "account", account, ); const accountNotification: Notification = { type: "success", subtype: errors.account.deleting.subtype, date: Date.now().toString(), status: "unread", callToAction: false, data: { account: account.name, tenant: account.tenant, }, }; eventHelper.notification.publish.creation(accountNotification); return response; } catch (error) { eventHelper.account.publish.deletionError(account); const { code, message } = extractErrorInfo(error); const accountErrorNotification: Notification = { type: "error", subtype: errors.account.deletionError.subtype, date: Date.now().toString(), info_content: { code, message, }, status: "unread", callToAction: false, data: { account: account.name, tenant: account.tenant, }, userError: true, }; eventHelper.notification.publish.creation(accountErrorNotification); throw error; } }; export const clearAccount = async (account: Account, security: Security) => { try { await initializeGlobalWebSocketClient(security, "account", account.name); const payload = { tenant: account.tenant, account: account.name, delete: false, force: false, }; const response = await makeGlobalWebSocketRequest( "account:cleanup_account", payload, 30000, "CLEANUP", account.name, "account", account, ); const updatedAccount: Account = { ...account, status: "pending" }; eventHelper.account.publish.cleaned(updatedAccount); const accountNotification: Notification = { type: "success", subtype: errors.account.cleaned.subtype, date: Date.now().toString(), status: "unread", callToAction: false, data: { account: account.name, tenant: account.tenant, }, }; eventHelper.notification.publish.creation(accountNotification); return response; } catch (error) { eventHelper.account.publish.cleanError(account); const { code, message } = extractErrorInfo(error); const accountErrorNotification: Notification = { type: "error", subtype: errors.account.cleanError.subtype, date: Date.now().toString(), info_content: { code, message, }, status: "unread", callToAction: false, data: { account: account.name, tenant: account.tenant, }, userError: true, }; eventHelper.notification.publish.creation(accountErrorNotification); throw error; } }; export const updateAccount = async (account: Account, security: Security) => { try { await initializeGlobalWebSocketClient(security, "account", account.name); const providerName = account.cloudProvider?.name?.toLowerCase(); let accountBody; if (providerName === "aws") { accountBody = { tenant: account.tenant, account: account.name, provision_infrastructure: false, spec: { api: "aws", credentials: account.cloudProvider.password ? { admin_access_key: account.cloudProvider.username || "", admin_secret_key: account.cloudProvider.password || "", region: account.cloudProvider?.region || "", } : { method: "aws", aws: { region: account.cloudProvider?.region || "", aws_access_key_id: account.cloudProvider?.credentialId || "", aws_secret_access_key: account.cloudProvider?.credentialSecret || "", }, }, marks: { vcpu: { lowmark: account.usage.limit.cpu.min * 1000, highmark: account.usage.limit.cpu.max * 1000, unit: "m", }, memory: { lowmark: account.usage.limit.memory.min * 1000, highmark: account.usage.limit.memory.max * 1000, unit: "MB", }, vstorage: { lowmark: account.usage.limit.volatileStorage.min * 1000, highmark: account.usage.limit.volatileStorage.max * 1000, unit: "MB", }, nrstorage: { lowmark: account.usage.limit.nonReplicatedStorage.min * 1000, highmark: account.usage.limit.nonReplicatedStorage.max * 1000, unit: "MB", }, rstorage: { lowmark: account.usage.limit.persistentStorage.min * 1000, highmark: account.usage.limit.persistentStorage.max * 1000, unit: "MB", }, storage: { lowmark: account.usage.limit.storage.min * 1000, highmark: account.usage.limit.storage.max * 1000, unit: "MB", }, cost: { lowmark: account.usage.cost, highmark: account.usage.cost, unit: "EUR", }, nodes: { lowmark: account.nodes?.max || 0, highmark: account.nodes?.max || 0, unit: "", }, }, iaasconfig: { ...(account.flavors?.volatile?.[0] && { volatile: account.flavors.volatile[0], }), ...(account.flavors?.persistent?.[0] && { persistent: account.flavors.persistent[0], }), ...(account.flavors?.nonReplicated?.[0] && { nonreplicated: account.flavors.nonReplicated[0], }), ...(account.flavors?.small?.[0] && { smallVMFlavor: account.flavors?.small?.[0], }), ...(account.flavors?.medium?.[0] && { mediumVMFlavor: account.flavors.medium[0], }), }, }, meta: { labels: { additionalProp1: "string", additionalProp2: "string", additionalProp3: "string", }, }, }; } else if (providerName === "azure") { accountBody = { tenant: account.tenant, account: account.name, provision_infrastructure: false, spec: { api: "azure", credentials: account.cloudProvider.password ? { tenant_id: account.cloudProvider.tenantId || "", admin_client_id: account.cloudProvider.username || "", admin_client_secret: account.cloudProvider.password || "", subscription_id: account.cloudProvider.subscriptionId || "", region: account.cloudProvider?.region || "", } : { method: "azure", azure: { region: account.cloudProvider?.region || "", subscription_id: account.cloudProvider?.subscriptionId || "", tenant_id: account.cloudProvider?.tenantId || "", client_id: account.cloudProvider?.clientId || "", client_secret: account.cloudProvider?.clientSecret || "", }, }, marks: { vcpu: { lowmark: account.usage.limit.cpu.min * 1000, highmark: account.usage.limit.cpu.max * 1000, unit: "m", }, memory: { lowmark: account.usage.limit.memory.min * 1000, highmark: account.usage.limit.memory.max * 1000, unit: "MB", }, vstorage: { lowmark: account.usage.limit.volatileStorage.min * 1000, highmark: account.usage.limit.volatileStorage.max * 1000, unit: "MB", }, nrstorage: { lowmark: account.usage.limit.nonReplicatedStorage.min * 1000, highmark: account.usage.limit.nonReplicatedStorage.max * 1000, unit: "MB", }, rstorage: { lowmark: account.usage.limit.persistentStorage.min * 1000, highmark: account.usage.limit.persistentStorage.max * 1000, unit: "MB", }, storage: { lowmark: account.usage.limit.storage.min * 1000, highmark: account.usage.limit.storage.max * 1000, unit: "MB", }, cost: { lowmark: account.usage.cost, highmark: account.usage.cost, unit: "EUR", }, nodes: { lowmark: account.nodes?.min || 0, highmark: account.nodes?.max || 0, unit: "", }, }, iaasconfig: { ...(account.flavors?.volatile?.[0] && { volatile: account.flavors.volatile[0], }), ...(account.flavors?.persistent?.[0] && { persistent: account.flavors.persistent[0], }), ...(account.flavors?.nonReplicated?.[0] && { nonreplicated: account.flavors.nonReplicated[0], }), ...(account.flavors?.small?.[0] && { smallVMFlavor: account.flavors?.small?.[0], }), ...(account.flavors?.medium?.[0] && { mediumVMFlavor: account.flavors.medium[0], }), }, }, meta: { labels: { additionalProp1: "string", additionalProp2: "string", additionalProp3: "string", }, }, }; } else if (providerName === "ovh") { accountBody = { tenant: account.tenant, account: account.name, provision_infrastructure: false, spec: { api: providerName, credentials: account.cloudProvider.password ? { username: account.cloudProvider.username || "", password: account.cloudProvider.password || "", region: account.cloudProvider?.region || "", } : { method: providerName, openstack: { region_name: account.cloudProvider?.region || "", interface: account.cloudProvider?.interface || "", identity_api_version: Number( account.cloudProvider?.apiVersion || 3, ), auth_type: account.cloudProvider?.authType || "", auth: { auth_url: account.cloudProvider?.authUrl || "", application_credential_id: account.cloudProvider?.credentialId || "", application_credential_secret: account.cloudProvider?.credentialSecret || "", }, }, }, highlyAvailable: true, marks: { vcpu: { lowmark: account.usage.limit.cpu.min * 1000, highmark: account.usage.limit.cpu.max * 1000, unit: "m", }, memory: { lowmark: account.usage.limit.memory.min * 1000, highmark: account.usage.limit.memory.max * 1000, unit: "MB", }, vstorage: { lowmark: account.usage.limit.volatileStorage.min * 1000, highmark: account.usage.limit.volatileStorage.max * 1000, unit: "MB", }, nrstorage: { lowmark: account.usage.limit.nonReplicatedStorage.min * 1000, highmark: account.usage.limit.nonReplicatedStorage.max * 1000, unit: "MB", }, rstorage: { lowmark: account.usage.limit.persistentStorage.min * 1000, highmark: account.usage.limit.persistentStorage.max * 1000, unit: "MB", }, storage: { lowmark: account.usage.limit.storage.min * 1000, highmark: account.usage.limit.storage.max * 1000, unit: "MB", }, cost: { lowmark: account.usage.cost, highmark: account.usage.cost, unit: "EUR", }, nodes: { lowmark: account.nodes?.min || 0, highmark: account.nodes?.max || 0, unit: "", }, }, iaasconfig: { ...(account.flavors?.volatile?.[0] && { volatile: account.flavors.volatile[0], }), ...(account.flavors?.persistent?.[0] && { persistent: account.flavors.persistent[0], }), ...(account.flavors?.nonReplicated?.[0] && { nonreplicated: account.flavors.nonReplicated[0], }), ...(account.flavors?.small?.[0] && { smallVMFlavor: account.flavors?.small?.[0], }), ...(account.flavors?.medium?.[0] && { mediumVMFlavor: account.flavors.medium[0], }), }, }, meta: { labels: { additionalProp1: "string", additionalProp2: "string", additionalProp3: "string", }, }, }; } else if (providerName === "oasix") { accountBody = { tenant: account.tenant, account: account.name, provision_infrastructure: false, spec: { api: providerName, credentials: account.cloudProvider.password ? { username: account.cloudProvider.username || "", password: account.cloudProvider.password || "", region: account.cloudProvider?.region || "", domain: account.cloudProvider?.domain || "", project_name: account.cloudProvider?.project_name || "", } : { method: providerName, openstack: { region_name: account.cloudProvider?.region || "", interface: account.cloudProvider?.interface || "", identity_api_version: Number( account.cloudProvider?.apiVersion || 3, ), auth_type: account.cloudProvider?.authType || "", auth: { auth_url: account.cloudProvider?.authUrl || "", application_credential_id: account.cloudProvider?.credentialId || "", application_credential_secret: account.cloudProvider?.credentialSecret || "", }, }, }, highlyAvailable: true, marks: { vcpu: { lowmark: account.usage.limit.cpu.min * 1000, highmark: account.usage.limit.cpu.max * 1000, unit: "m", }, memory: { lowmark: account.usage.limit.memory.min * 1000, highmark: account.usage.limit.memory.max * 1000, unit: "MB", }, vstorage: { lowmark: account.usage.limit.volatileStorage.min * 1000, highmark: account.usage.limit.volatileStorage.max * 1000, unit: "MB", }, nrstorage: { lowmark: account.usage.limit.nonReplicatedStorage.min * 1000, highmark: account.usage.limit.nonReplicatedStorage.max * 1000, unit: "MB", }, rstorage: { lowmark: account.usage.limit.persistentStorage.min * 1000, highmark: account.usage.limit.persistentStorage.max * 1000, unit: "MB", }, storage: { lowmark: account.usage.limit.storage.min * 1000, highmark: account.usage.limit.storage.max * 1000, unit: "MB", }, cost: { lowmark: account.usage.cost, highmark: account.usage.cost, unit: "EUR", }, nodes: { lowmark: account.nodes?.min || 0, highmark: account.nodes?.max || 0, unit: "", }, }, iaasconfig: { ...(account.flavors?.volatile?.[0] && { volatile: account.flavors.volatile[0], }), ...(account.flavors?.persistent?.[0] && { persistent: account.flavors.persistent[0], }), ...(account.flavors?.nonReplicated?.[0] && { nonreplicated: account.flavors.nonReplicated[0], }), ...(account.flavors?.small?.[0] && { smallVMFlavor: account.flavors?.small?.[0], }), ...(account.flavors?.medium?.[0] && { mediumVMFlavor: account.flavors.medium[0], }), }, }, meta: { labels: { additionalProp1: "string", additionalProp2: "string", additionalProp3: "string", }, }, }; } else if (providerName === "cloudos") { accountBody = { tenant: account.tenant, account: account.name, provision_infrastructure: false, spec: { api: providerName, credentials: { method: providerName, openstack: { region_name: account.cloudProvider?.region || "", interface: account.cloudProvider?.interface || "", identity_api_version: Number( account.cloudProvider?.apiVersion || 3, ), auth_type: account.cloudProvider?.authType || "", auth: { auth_url: account.cloudProvider?.authUrl || "", application_credential_id: account.cloudProvider?.credentialId || "", application_credential_secret: account.cloudProvider?.credentialSecret || "", }, }, }, highlyAvailable: true, marks: { vcpu: { lowmark: account.usage.limit.cpu.min * 1000, highmark: account.usage.limit.cpu.max * 1000, unit: "m", }, memory: { lowmark: account.usage.limit.memory.min * 1000, highmark: account.usage.limit.memory.max * 1000, unit: "MB", }, vstorage: { lowmark: account.usage.limit.volatileStorage.min * 1000, highmark: account.usage.limit.volatileStorage.max * 1000, unit: "MB", }, nrstorage: { lowmark: account.usage.limit.nonReplicatedStorage.min * 1000, highmark: account.usage.limit.nonReplicatedStorage.max * 1000, unit: "MB", }, rstorage: { lowmark: account.usage.limit.persistentStorage.min * 1000, highmark: account.usage.limit.persistentStorage.max * 1000, unit: "MB", }, storage: { lowmark: account.usage.limit.storage.min * 1000, highmark: account.usage.limit.storage.max * 1000, unit: "MB", }, cost: { lowmark: account.usage.cost, highmark: account.usage.cost, unit: "EUR", }, nodes: { lowmark: account.nodes?.min || 0, highmark: account.nodes?.max || 0, unit: "", }, }, iaasconfig: { ...(account.flavors?.volatile?.[0] && { volatile: account.flavors.volatile[0], }), ...(account.flavors?.persistent?.[0] && { persistent: account.flavors.persistent[0], }), ...(account.flavors?.nonReplicated?.[0] && { nonreplicated: account.flavors.nonReplicated[0], }), ...(account.flavors?.small?.[0] && { smallVMFlavor: account.flavors?.small?.[0], }), ...(account.flavors?.medium?.[0] && { mediumVMFlavor: account.flavors.medium[0], }), }, }, meta: { labels: { additionalProp1: "string", additionalProp2: "string", additionalProp3: "string", }, }, }; } else if (providerName === "opennebula") { accountBody = { tenant: account.tenant, account: account.name, provision_infrastructure: false, spec: { api: providerName, credentials: { method: providerName, opennebula: { user: account.cloudProvider.username, password: account.cloudProvider.password, xmlrpc: account.cloudProvider.endpoint, }, }, highlyAvailable: true, marks: { vcpu: { lowmark: account.usage.limit.cpu.min * 1000, highmark: account.usage.limit.cpu.max * 1000, unit: "m", }, memory: { lowmark: account.usage.limit.memory.min * 1000, highmark: account.usage.limit.memory.max * 1000, unit: "MB", }, vstorage: { lowmark: account.usage.limit.volatileStorage.min * 1000, highmark: account.usage.limit.volatileStorage.max * 1000, unit: "MB", }, nrstorage: { lowmark: account.usage.limit.nonReplicatedStorage.min * 1000, highmark: account.usage.limit.nonReplicatedStorage.max * 1000, unit: "MB", }, rstorage: { lowmark: account.usage.limit.persistentStorage.min * 1000, highmark: account.usage.limit.persistentStorage.max * 1000, unit: "MB", }, storage: { lowmark: account.usage.limit.storage.min * 1000, highmark: account.usage.limit.storage.max * 1000, unit: "MB", }, cost: { lowmark: account.usage.cost, highmark: account.usage.cost, unit: "EUR", }, nodes: { lowmark: account.nodes?.max || 0, highmark: account.nodes?.max || 0, unit: "", }, }, iaasconfig: { ...(account.flavors?.volatile?.[0] && { volatile: account.flavors.volatile[0], }), ...(account.flavors?.persistent?.[0] && { persistent: account.flavors.persistent[0], }), ...(account.flavors?.nonReplicated?.[0] && { nonreplicated: account.flavors.nonReplicated[0], }), ...(account.flavors?.small?.[0] && { smallVMFlavor: account.flavors?.small?.[0], }), ...(account.flavors?.medium?.[0] && { mediumVMFlavor: account.flavors.medium[0], }), }, }, meta: { labels: { additionalProp1: "string", additionalProp2: "string", additionalProp3: "string", }, }, }; } else { throw new Error( `Unsupported cloud provider: ${providerName}. Supported providers are: ovh, aws, azure`, ); } const response = await makeGlobalWebSocketRequest( "account:update_account", accountBody, 30000, "UPDATE", account.name, "account", account, ); return response; } catch (error) { console.error("Error updating account:", { error, errorMessage: error instanceof Error ? error.message : "Unknown error", account: account.name, tenant: account.tenant, provider: account.cloudProvider?.name, }); eventHelper.account.publish.updateError(account); const { code, message } = extractErrorInfo(error); const accountErrorNotification: Notification = { type: "error", subtype: errors.account.updateError.subtype, date: Date.now().toString(), info_content: { code, message, }, status: "unread", callToAction: false, data: { account: account.name, tenant: account.tenant, }, userError: true, }; eventHelper.notification.publish.creation(accountErrorNotification); throw error; } };