import { Environment, errors, Notification } from "@kumori/aurora-interfaces"; import { eventHelper } from "../backend-handler"; import { initializeGlobalWebSocketClient, getWebSocketStatus, makeGlobalWebSocketRequest, markEnvironmentAsPurging, } from "../websocket-manager"; type Security = string; export const createEnvironment = async ( env: Environment, security: Security ) => { try { await initializeGlobalWebSocketClient(security, "environment", env.name); const status = getWebSocketStatus(); const isPrimary = true; const baseMarks = { vcpu: { lowmark: env.usage.limit.cpu.min * 1000, highmark: env.usage.limit.cpu.max * 1000, unit: "m", }, memory: { lowmark: env.usage.limit.memory.min * 1000, highmark: env.usage.limit.memory.max * 1000, unit: "MB", }, vstorage: { lowmark: env.usage.limit.volatileStorage.min * 1000, highmark: env.usage.limit.volatileStorage.max * 1000, unit: "MB", }, nrstorage: { lowmark: env.usage.limit.nonReplicatedStorage.min * 1000, highmark: env.usage.limit.nonReplicatedStorage.max * 1000, unit: "MB", }, rstorage: { lowmark: env.usage.limit.persistentStorage.min * 1000, highmark: env.usage.limit.persistentStorage.max * 1000, unit: "MB", }, storage: { lowmark: env.usage.limit.storage.min * 1000, highmark: env.usage.limit.storage.max * 1000, unit: "MB", }, cost: { lowmark: env.usage.cost, highmark: env.usage.cost, unit: "EUR", }, nodes: { lowmark: env.nodes?.max, highmark: env.nodes?.max, unit: "", } }; const environmentSpec: any = isPrimary ? { type: "primary", marks: baseMarks, highlyAvailable: env.highAvaliable || false, } : { type: "secondary", primary: { name: env.organization, kind: "environment" }, parent: { kind: "account", name: env.account }, marks: baseMarks, isolated: true, }; const labels: { [key: string]: string } = {}; if (env.labels && env.labels.length > 0) { env.labels.forEach((label, idx) => { labels[`label${idx + 1}`] = label; }); } const environmentBody = { tenant: env.tenant, account: env.account, environment: env.name, provision_infrastructure: false, spec: { spec: environmentSpec, labels, }, }; const response = await makeGlobalWebSocketRequest( "environment:create_environment", environmentBody, 30000, "CREATE", env.name, "environment", env ); //const updatedEnv: Environment = { ...env, status: "pending" }; //eventHelper.environment.publish.created(updatedEnv); return response; } catch (error) { console.error("Error creating environment:", { error, errorMessage: error instanceof Error ? error.message : "Unknown error", environment: env.name, tenant: env.tenant, account: env.account, webSocketStatus: getWebSocketStatus(), }); let contentMessage = "Unknown error"; let errorContent = "Unknown error"; if ( typeof error === "object" && error !== null && "error" in error && typeof (error as any).error === "object" && (error as any).error !== null ) { if ("code" in (error as any).error) { contentMessage = (error as any).error.code; } if ("content" in (error as any).error) { errorContent = (error as any).error.content; } } const envErrorNotification: Notification = { type: "error", subtype: errors.environment.creationError.subtype, info_content: { code: contentMessage, message: errorContent, }, date: Date.now().toString(), status: "unread", callToAction: false, data: { environment: env.name, account: env.account, tenant: env.tenant }, userError: true, }; eventHelper.notification.publish.creation(envErrorNotification); throw error; } }; export const deleteEnvironment = async ( env: Environment, security: Security ) => { try { await initializeGlobalWebSocketClient(security, "environment", env.name); const status = getWebSocketStatus(); const deletePayload = { tenant: env.tenant, account: env.account, environment: env.name, delete: true, force: true, }; const response = await makeGlobalWebSocketRequest( "environment:delete_environment", deletePayload, 30000, "DELETE", env.name, "environment", env ); // const updatedEnv: Environment = { ...env, status: "pending" }; // eventHelper.environment.publish.deleted(updatedEnv); const envNotification: Notification = { type: "success", subtype: errors.environment.deleting.subtype, date: Date.now().toString(), status: "unread", callToAction: false, data: { environment: env.name, account: env.account, tenant: env.tenant } }; eventHelper.notification.publish.creation(envNotification); return response; } catch (error) { console.error("Error deleting environment:", { error, environment: env.name, tenant: env.tenant, account: env.account, webSocketStatus: getWebSocketStatus(), }); eventHelper.environment.publish.deletionError(env); let contentMessage = "Unknown error"; let errorContent = "Unknown error"; if ( typeof error === "object" && error !== null && "error" in error && typeof (error as any).error === "object" && (error as any).error !== null ) { if ("code" in (error as any).error) { contentMessage = (error as any).error.code; } if ("content" in (error as any).error) { errorContent = (error as any).error.content; } } const envErrorNotification: Notification = { type: "error", subtype: errors.environment.deletionError.subtype, info_content: { code: contentMessage, message: errorContent, }, date: Date.now().toString(), status: "unread", callToAction: false, data: { environment: env.name, account: env.account, tenant: env.tenant }, userError: true, }; eventHelper.notification.publish.creation(envErrorNotification); throw error; } }; export const clearEnvironment = async ( env: Environment, security: Security ) => { try { const envNotification: Notification = { type: "info", subtype: errors.environment.purging.subtype, date: Date.now().toString(), status: "unread", callToAction: false, data: { environment: env.name, account: env.account, tenant: env.tenant } }; eventHelper.notification.publish.creation(envNotification); const purgeKey = env.tenant && env.account ? `${env.tenant}/${env.account}/${env.name}` : env.name; markEnvironmentAsPurging(purgeKey); await initializeGlobalWebSocketClient(security, "environment", env.name); const status = getWebSocketStatus(); const deletePayload = { tenant: env.tenant, account: env.account, environment: env.name, delete: false, force: false, }; const response = await makeGlobalWebSocketRequest( "environment:delete_environment", deletePayload, 30000, "CLEAN", env.name, "environment", env ); return response; } catch (error) { console.error("Error deleting environment:", { error, environment: env.name, tenant: env.tenant, account: env.account, webSocketStatus: getWebSocketStatus(), }); eventHelper.environment.publish.deletionError(env); let contentMessage = "Unknown error"; let errorContent = "Unknown error"; if ( typeof error === "object" && error !== null && "error" in error && typeof (error as any).error === "object" && (error as any).error !== null ) { if ("code" in (error as any).error) { contentMessage = (error as any).error.code; } if ("content" in (error as any).error) { errorContent = (error as any).error.content; } } const envErrorNotification: Notification = { type: "error", subtype: errors.environment.purgeError.subtype, info_content: { code: contentMessage, message: errorContent, }, date: Date.now().toString(), status: "unread", callToAction: false, data: { environment: env.name, account: env.account, tenant: env.tenant }, userError: true, }; eventHelper.notification.publish.creation(envErrorNotification); throw error; } }; export const updateEnvironment = async ( env: Environment, security: Security ) => { try { await initializeGlobalWebSocketClient(security, "environment", env.name); const status = getWebSocketStatus(); const updatePayload = { tenant: env.tenant, account: env.account, environment: env.name, spec: { marks: { vcpu: { lowmark: env.usage.limit.cpu.min * 1000, highmark: env.usage.limit.cpu.max * 1000, unit: "m", }, memory: { lowmark: env.usage.limit.memory.min * 1000, highmark: env.usage.limit.memory.max * 1000, unit: "MB", }, vstorage: { lowmark: env.usage.limit.volatileStorage.min * 1000, highmark: env.usage.limit.volatileStorage.max * 1000, unit: "MB", }, nrstorage: { lowmark: env.usage.limit.nonReplicatedStorage.min * 1000, highmark: env.usage.limit.nonReplicatedStorage.max * 1000, unit: "MB", }, rstorage: { lowmark: env.usage.limit.persistentStorage.min * 1000, highmark: env.usage.limit.persistentStorage.max * 1000, unit: "MB", }, storage: { lowmark: env.usage.limit.storage.min * 1000, highmark: env.usage.limit.storage.max * 1000, unit: "MB", }, cost: { lowmark: env.usage.cost, highmark: env.usage.cost, unit: "EUR", }, nodes: { lowmark: env.nodes?.max, highmark: env.nodes?.max, unit: "", } }, isolated: true, highlyAvailable: env.highAvaliable || false, }, }; const response = await makeGlobalWebSocketRequest( "environment:update_environment", updatePayload, 30000, "UPDATE", env.name, "environment", env ); const updatedEnv: Environment = { ...env, status: { code: "pending", message: "", timestamp: "" } }; eventHelper.environment.publish.updated(updatedEnv); const envNotification: Notification = { type: "success", subtype: errors.environment.updated.subtype, date: Date.now().toString(), status: "unread", callToAction: false, data: { environment: env.name, account: env.account, tenant: env.tenant } }; eventHelper.notification.publish.creation(envNotification); return response; } catch (error) { console.error("Error updating environment:", { error, environment: env.name, tenant: env.tenant, account: env.account, webSocketStatus: getWebSocketStatus(), }); eventHelper.environment.publish.updateError(env); let contentMessage = "Unknown error"; let errorContent = "Unknown error"; if ( typeof error === "object" && error !== null && "error" in error && typeof (error as any).error === "object" && (error as any).error !== null ) { if ("code" in (error as any).error) { contentMessage = (error as any).error.code; } if ("content" in (error as any).error) { errorContent = (error as any).error.content; } } const envErrorNotification: Notification = { type: "error", subtype: errors.environment.updateError.subtype, info_content: { code: contentMessage, message: errorContent, }, date: Date.now().toString(), status: "unread", callToAction: false, data: { environment: env.name, account: env.account, tenant: env.tenant }, userError: true }; eventHelper.notification.publish.creation(envErrorNotification); throw error; } }; export const scaleEnvironment = async ( env: Environment, security: Security ) => { try{ const updatePayload = { tenant: env.tenant, account: env.account, environment: env.name, // controlPlane: env.targetVMS?.controlPlane, // worker: env.targetVMS?.worker, ingress: env.targetVMS?.ingress.toString(), }; const response = await makeGlobalWebSocketRequest( "environment:scale_environment", updatePayload, 30000, "SCALE", env.name, "environment", env ); if(!response.ok) return; eventHelper.environment.publish.scaled(env); const envNotification: Notification = { type: "success", subtype: errors.environment.scaled.subtype, date: Date.now().toString(), status: "unread", callToAction: false, data: { environment: env.name, account: env.account, tenant: env.tenant } }; eventHelper.notification.publish.creation(envNotification); return response; } catch(error){ eventHelper.environment.publish.scaleError(env); let contentMessage = "Unknown error"; let errorContent = "Unknown error"; if ( typeof error === "object" && error !== null && "error" in error && typeof (error as any).error === "object" && (error as any).error !== null ) { if ("code" in (error as any).error) { contentMessage = (error as any).error.code; } if ("content" in (error as any).error) { errorContent = (error as any).error.content; } } const envErrorNotification: Notification = { type: "error", subtype: errors.environment.scaleError.subtype, info_content: { code: contentMessage, message: errorContent, }, date: Date.now().toString(), status: "unread", callToAction: false, data: { environment: env.name, account: env.account, tenant: env.tenant }, userError: true }; eventHelper.notification.publish.creation(envErrorNotification); throw error; } }